Sed regex match with variable endings is not matchng - linux

I have file that in simple example looks like:
some_file_name{
something
otherthing2
otherthing3
}
How ever "some_file_name" can end with end of line, space or { so I need to match every variant. To further complicate things the some_file_name contains / so delimiter needs to be different... and in the end I need to replace "something" between the some_file_name{ and the next } so the result would be:
some_file_name{
something_replaced
otherthing2
otherthing3
}
I got as far:
sed -r "\%some_file_name\($\|[[:space:]]\|\{\)%,\%\}%{s/something/something_replaced/}" "file.txt"
( sed -r is mandatory )
My best gues the issue is somewhere here: \($\|[[:space:]]\|\{\) where I try to match the 3 possible endings ... but for life of me I can't figure it out what is missing.
sed --version
sed (GNU sed) 4.2.2

sed -r "\%some_file_name($|[[:space:]]|\{)%,\%\}%{s/something/something_replaced/}" "file.txt"
-r (and -E, which is more portable, so whenever you can, choose this one) enables extended regular expressions. So you should neither escape the grouping parenthesis, nor the vertical bar, otherwise they are treated literally by sed.
Still confused? Consider this:
$ echo '(' | sed 's/(/X/'
X
$ echo '(' | sed -E 's/(/X/'
sed: -e expression #1, char 6: Unmatched ( or \(
$ echo '(' | sed -E 's/\(/X/'
X

Related

sed + replace key that begin in file with long text that include key and value

in kafka.properies file
more /home/kafka.properies
log.retention.hours=12
delete.topic.enable=true
leader.imbalance.check.interval.seconds=300
leader.imbalance.per.broker.percentage=10
log.dir=/var/kafka/data1
we want to replace the
log.dir=/var/kafka/data1
or any combination as
log.dir=/var/kafka/data1,/var/kafka/data2, ......
with $line
when:
echo $line
/var/kafka/data1,/var/kafka/data2,/var/kafka/data3,/var/kafka/data4,/var/kafka/data5,/var/kafka/data6,/var/kafka/data7,/var/kafka/data8
so we did the following:
sed "s/^log.dir.*/\$line/g" /home/kafka.properies
or
sed 's/^log.dir.*/$line/g' /home/kafka.properies
but we get
log.retention.hours=12
delete.topic.enable=true
leader.imbalance.check.interval.seconds=300
leader.imbalance.per.broker.percentage=10
$line
instead to get
log.retention.hours=12
delete.topic.enable=true
leader.imbalance.check.interval.seconds=300
leader.imbalance.per.broker.percentage=10
log.dir=/var/kafka/data1,/var/kafka/data2,/var/kafka/data3,/var/kafka/data4,/var/kafka/data5,/var/kafka/data6,/var/kafka/data7,/var/kafka/data8
where I am wrong? , what is the right approach for this replacing ? ( with sed or perl one liner or other )
You need to use
sed "s~^log\.dir.*~log.dir=$line~" /home/kafka.properies
If there are any leading whitespaces, you may try
sed "s~^ *log\.dir.*~log.dir=$line~" /home/kafka.properies # only spaces
sed "s~^[[:space:]]*log\.dir.*~log.dir=$line~" /home/kafka.properies # any whitespaces
sed "s~^\s*log\.dir.*~log.dir=$line~" /home/kafka.properies # GNU sed only
See the online demo:
#!/bin/bash
s='log.retention.hours=12
delete.topic.enable=true
leader.imbalance.check.interval.seconds=300
leader.imbalance.per.broker.percentage=10
log.dir=/var/kafka/data1'
line='/var/kafka/data1,/var/kafka/data2,/var/kafka/data3,/var/kafka/data4,/var/kafka/data5,/var/kafka/data6,/var/kafka/data7,/var/kafka/data8'
sed "s~^log\.dir.*~log.dir=$line~g" <<< "$s"
Ouitput:
log.retention.hours=12
delete.topic.enable=true
leader.imbalance.check.interval.seconds=300
leader.imbalance.per.broker.percentage=10
log.dir=/var/kafka/data1,/var/kafka/data2,/var/kafka/data3,/var/kafka/data4,/var/kafka/data5,/var/kafka/data6,/var/kafka/data7,/var/kafka/data8
Note:
~ is used as a regex delimiter char here since the replacement contains / chars
. in log.dir must be escaped to match a literal . char, else, . matches any single char
You need to use double quotation marks in the sed command to be able to use variables in it.
Since you match log.dir and consume it, this text will be removed from the match, and you should put it back in the replacement pattern.
As an option, you can capture the log.dir and use the backreference/placeholder to the group value in the RHS:
sed -E "s~^(log\.dir=).*~\1$line~" /home/kafka.properies

in bash using sed replace 'oldstring' with 'newstring'

I have an extra credit assignment that's asking me to take 3 arguments to use to rid of someone's name on their assignment and replace it with mine.
1st argument is the file name
2nd argument is the "oldstring"
3rd argument is the "newstring"
this is my script:
#!/bin/bash
file=$1
oldname=$2
newname=$3
changed=`grep -R "$oldname" $file | sed -i "s/$2/$3/g" $file`
done
this is the file I'm searching through
int main(int argc, char**argv)
{
printf("Assignment #3-4, Smarty McSmartypants, smarty#mcsmartypants.smart\n");
printf("%0.4f\n",cos(sqrt(atoi(argv[1]))/10.0f));'
I'll be replacing "Smarty McSmartypants" with "my name" which works perfectly fine but when I run it again to try to replace "smarty#mcsmartypants.smart\n" with "my#email" there's no changes. Can someone explain this phenomenon?
sed matches line-by-line, so you can't use it to replace newlines. It looks like you're trying to replace a literal \ followed by an n, however, in which case you need to escape the \ so that sed doesn't treat the \n as an escape sequence.
Compare:
$ echo 'foo\nbar' | sed 's/foo\n/fib/g'
foo\nbar
$ echo 'foo\nbar' | sed 's/foo\\n/fib/g'
fibbar

Linux Command to make columns separated by multiple delimeters

Want to convert the following pattern
ab
cd
de
fg as
'ab','cd','de','fg' using unix / linux command .
----Guys -------- The patern is as following
QRTC1065173134
QRTC3988977812
QRTC0889556882
QUTR1641276912
ABCD1763495154
QRTC3991601819
and this is the required pattern 'QRTC1065173134','QRTC3988977812','QRTC0889556882','QUTR1641276912','ABCD1763495154','QRTC3991601819'
I agree with the comments that it's a bit unclear but, for fun sake:
A="ab cd ef gh "
echo $A | sed -e "s/^\s*/'/; s/ \{1,\}/','/g; s/\s*$/'/g"
Since the question wasn't precise, I only worked on spaces & string boundaries. So it will work with any number of characters, separated space(s). The result is also trimmed at both ends. HTH.
From the clarification, it seems that this is what you want.
$ echo "QRTC1065173134 QRTC3988977812 QRTC0889556882 QUTR1641276912 ABCD1763495154 QRTC3991601819" | sed -E "s/ /', '/g" | sed -E "s/$/'/" | sed -E "s/^/'/"
'QRTC1065173134', 'QRTC3988977812', 'QRTC0889556882', 'QUTR1641276912', 'ABCD1763495154', 'QRTC3991601819'
Here "E" is for extended regex so that we do not need to escape the regex metacharacters.
COMMENT 1: Removing an extra whitespace is left as an exercise for you.
If I understand correctly, that you have groups (e.g. ab bc de ...) separated by spaces, where you want to include a ' at the beginning/end of everything, and replace the spaces with ',' then sed can handle this with relative ease. Below ab cd ... can be any string of characters, such as QRTC1065173134. There are several ways to piece together a matching regular expression, but the following is fairly simple:
sed -e "s/\s/','/g" -e "s/^/'/" -e "s/$/'/"
example
$ echo "ab cd de fg hi" | sed -e "s/\s/','/g" -e "s/^/'/" -e "s/$/'/"
'ab','cd','de','fg','hi'
or
$ echo "QRTC1065173134 QRTC3988977812 QRTC0889556882" | sed -e "s/\s/','/g" -e "s/^/'/" -e "s/$/'/"
'QRTC1065173134','QRTC3988977812','QRTC0889556882'

sed returns "sed: command garbled"

I have this data in file.txt:
1234-abca-dgdsf-kds-2;abc dfsfds 2
123-abcdegfs-sdsd;dsfdsf dfd f
12523-cvjbsvndv-dvd-dvdv;dsfdsfpage
I want to replace the string after "-" and up to ";" with just ";", so that I get:
1234;abc dfsfds 2
123;dsfdsf dfd f
12523;dsfdsfpage
I tried with the command:
sed -e "s/-.*;/;" file.txt
But it gives me the following error:
sed command garbled
Why is this happening?
sed replacement commands are defined as (source):
's/REGEXP/REPLACEMENT/[FLAGS]'
(substitute) Match the regular-expression against the content of the pattern space. If found, replace matched string with REPLACEMENT.
However, you are saying:
sed "s/-.*;/;"
That is:
sed "s/REGEXP/REPLACEMENT"
And hence missing a "/" at the end of the expression. Just add it to have:
sed "s/-.*;/;/"
# ^
You are missing a slash at the end of the sed command:
Should be "s/-.*;/;/"
-.* here the * greedy, so this would fail if there are more than one ;
echo "12523-cvjbsvndv-dvd-dvdv;dsfdsfpage;test" | sed -e "s/-.*;/;/"
12523;test
Change to -[^;]*
echo "12523-cvjbsvndv-dvd-dvdv;dsfdsfpage;test" | sed -e "s/-[^;]*;/;/"
12523;dsfdsfpage;test
This should work :
sed 's/-.*;/;/g' file > newFile

linux shell title case

I am wrinting a shell script and have a variable like this: something-that-is-hyphenated.
I need to use it in various points in the script as:
something-that-is-hyphenated, somethingthatishyphenated, SomethingThatIsHyphenated
I have managed to change it to somethingthatishyphenated by stripping out - using sed "s/-//g".
I am sure there is a simpler way, and also, need to know how to get the camel cased version.
Edit: Working function derived from #Michał's answer
function hyphenToCamel {
tr '-' '\n' | awk '{printf "%s%s", toupper(substr($0,1,1)), substr($0,2)}'
}
CAMEL=$(echo something-that-is-hyphenated | hyphenToCamel)
echo $CAMEL
Edit: Finally, a sed one liner thanks to #glenn
echo a-hyphenated-string | sed -E "s/(^|-)([a-z])/\u\2/g"
a GNU sed one-liner
echo something-that-is-hyphenated |
sed -e 's/-\([a-z]\)/\u\1/g' -e 's/^[a-z]/\u&/'
\u in the replacement string is documented in the sed manual.
Pure bashism:
var0=something-that-is-hyphenated
var1=(${var0//-/ })
var2=${var1[*]^}
var3=${var2// /}
echo $var3
SomethingThatIsHyphenated
Line 1 is trivial.
Line 2 is the bashism for replaceAll or 's/-/ /g', wrapped in parens, to build an array.
Line 3 uses ${foo^}, which means uppercase (while ${foo,} would mean 'lowercase' [note, how ^ points up while , points down]) but to operate on every first letter of a word, we address the whole array with ${foo[*]} (or ${foo[#]}, if you would prefer that).
Line 4 is again a replace-all: blank with nothing.
Line 5 is trivial again.
You can define a function:
hypenToCamel() {
tr '-' '\n' | awk '{printf "%s%s", toupper(substr($0,0,1)), substr($0,2)}'
}
CAMEL=$(echo something-that-is-hyphenated | hypenToCamel)
echo $CAMEL
In the shell you are stuck with being messy:
aa="aaa-aaa-bbb-bbb"
echo " $aa" | sed -e 's/--*/ /g' -e 's/ a/A/g' -e 's/ b/B/g' ... -e 's/ *//g'
Note the carefully placed space in the echo and the double space in the last -e.
I leave it as an exercise to complete the code.
In perl it is a bit easier as a one-line shell command:
perl -e 'print map{ $a = ucfirst; $a =~ s/ +//g; $a} split( /-+/, $ARGV[0] ), "\n"' $aa
For the records, here's a pure Bash safe method (that is not subject to pathname expansion)—using Bash≥4:
var0=something-that-is-hyphenated
IFS=- read -r -d '' -a var1 < <(printf '%s\0' "${var0,,}")
printf '%s' "${var1[#]^}"
This (safely) splits the lowercase expansion of var0 at the hyphens, with each split part in array var1. Then we use the ^ parameter expansion to uppercase the first character of the fields of this array, and concatenate them.
If your variable may also contain spaces and you want to act on them too, change IFS=- into IFS='- '.

Resources