Sed Editor single check - sed

I have a sed command which will append a string on the end of a line. When I re-run the same command again the same content is getting append at the end of the line again and again.
I am looking for a command which will check if the content is already there or not then proceed.
Here is my sed command:
shell: sed -i '/only_from/s/$/ xx.xx.xx.xx\/24/' file.txt

this line works for your needs:
sed -i '/only_from/{/ xx\.xx\.xx\.xx\/24$/!s#$# xx.xx.xx.xx/24#}' file
E.g:
kent$ cat f
only_from foo bar
kent$ sed -i '/only_from/{/xx\.xx\.xx\.xx\/24$/!s#$# xx.xx.xx.xx/24#}' f
kent$ cat f
only_from foo bar xx.xx.xx.xx/24
kent$ sed -i '/only_from/{/xx\.xx\.xx\.xx\/24$/!s#$# xx.xx.xx.xx/24#}' f
kent$ cat f
only_from foo bar xx.xx.xx.xx/24

You can try this sed:
sed '/only_from/{ / xx\.xx\.xx\.xx\/24/ !s/$/ xx\.xx\.xx\.xx\/24/}' file

This might be a bit naive, but why don't you write something as simple as
sed -i '/only_from$/s/$/ xx.xx.xx.xx\/24/' file.txt

Related

Why does sed 'w' editing command truncate the file instead of appending to it?

I wrote this shell script.
echo a: foo > a.txt
echo a: bar >> a.txt
echo a: baz >> a.txt
sed -i -e '/bar/{ w b.txt' -e 'd }' a.txt
sed -i -e '/baz/{ w b.txt' -e 'd }' a.txt
cat b.txt
Here is the output I got.
a: baz
But I expected this output.
a: bar
a: baz
I expected this output because http://pubs.opengroup.org/onlinepubs/9699919799/utilities/sed.html says:
[2addr]w wfile
Append (write) the pattern space to wfile.
Since it says "append", I was assuming that the first sed command would append a: bar to a non-existent file, thus creating that file. Then the second sed command would append a: baz to the same file.
But the output above shows that this was not the case.
What is wrong in my understanding?
You run sed twice, and the first (and only) call to w each time truncates the file. To get your expected output, you need to run sed only once:
$ sed -i -e '/bar/{ w b.txt' -e 'd }' -e '/baz/{ w b.txt' -e 'd }' a.txt
$ cat b.txt
a: bar
a: baz
Or with less -e:
sed -i '/bar\|baz/{
w b.txt
d
}' a.txt
Alternation with \| is a GNU extension to basic regular expressions, just like -i is not part of POSIX sed either.
All write commands of a single sed invocation append to the same file. However, every new invocation truncates the file first.

Merging 2 sed commands into 1

Is there a way to do the following in a single sed command to improve performance?
cat some_file | sed -n '/^MODIFIED/p' | sed 's/^MODIFIED\s*//g'
You could try the below sed command. -n and p helps to print those lines where the replacement takesplace. [[:space:]]* POSIX notation which matches zero or more spaces.
sed -n 's/^MODIFIED[[:space:]]*//p' some_file
OR
sed -n 's/^MODIFIED\s*//p' some_file
Example:
$ cat ri
MODIFIED foo bar
apple
mango
$ cat ri | sed -n '/^MODIFIED/p' | sed 's/^MODIFIED\s*//g'
foo bar
$ sed -n 's/^MODIFIED[[:space:]]*//p' ri
foo bar
Here is an awk version:
awk 'gsub(/^MODIFIED\s*/,"")' file
Example:
cat file
test
MODIFIED data
more MODIFIED home
awk 'gsub(/^MODIFIED\s*/,"")' file
data
You can remove both cat and sed, just use last sed like:
sed -nr 's/^MODIFIED\s*//p' some_file

Search replace regular expression variable using sed

This is probably a trivial one:
I have a file (my.file) with these lines:
>h1_c1
>h1_c2
>h1_c3
>h2_c1
>h2_c2
>h2_c3
and I want to change it in place to be:
>c1_h1
>c2_h1
>c3_h1
>c1_h2
>c2_h2
>c3_h3
I thought this ought to do it:
sed -i 's/\(\>\)\(h1\)\(\_\)\(.*\)/\1 \4 \3 \2/g' my.file
sed -i 's/\(\>\)\(h2\)\(\_\)\(.*\)/\1 \4 \3 \2/g' my.file
but it doesn't seem to work. How do I do it?
The obvious sed for your example is:
$ sed -i~ -e 's/^>\(h[0-9]\)_\(c[0-9]\)/>\2_\1/' *.foo
I tested this and it works for your example file.
Try this awk
awk -F">|_" '{print ">"$3"_"$2}' my.file > tmp && mv tmp my.file
awk -F">|_" '{print ">"$3"_"$2}' my.file
>c1_h1
>c2_h1
>c3_h1
>c1_h2
>c2_h2
>c3_h2
You can try this sed,
sed 's/>\(h[1-2]\)_\(.*\)/>\2_\1/' yourfile
(OR)
sed -r 's/>(h[1-2])_(.*)/>\2_\1/' yourfile
kent$ sed -r 's/>([^_]*)_(.*)/>\2_\1/' f
>c1_h1
>c2_h1
>c3_h1
>c1_h2
>c2_h2
>c3_h2
you add -i if you want it to happen "in-place"

bash script using sed to substitute twice

file1 contains:
first=stan
last=smith
I want to create file2 which contains
first=homer
last=simpson
script.sh contains
#!/bin/bash
sed s/stan/$1/ file1 >tempfile
sed s/smith/$2/ tempfile >file2
rm tempfile
script.sh homer simpson does what I want.
Is there a better way to do this in a bash script without creating and deleting tempfile?
Yes you can:
$ s1="homer"
$ s2="simpson"
$ sed -e "s/stan/$s1/g" -e "s/smith/$s2/g" file1 > file2
$ cat file2
first=homer
last=simpson
As you can see the -e option is used to perform two different sed commands in the same line.
In a bash script:
#!/bin/bash
sed -e "s/stan/$1/g" -e "s/smith/$2/g" file1 > file2
Sed supports multiple expressions. So you can do something like:
sed -e "s/stan/$1/" -e "s/smith/$2/" file1 > file2
I also recommend to use double quotes to prevent wordsplitting.

How to replace a string using Sed?

Suppose I have a string like this
<start><a></a><a></a><a></a></start>
I want to replace values inside <start></start> like this
<start><ab></ab><ab></ab><ab></ab><more></more><vale></value></start>
How do I do this using Sed?
Try this :
sed 's#<start>.*</start>#<start><ab></ab><ab></ab><ab></ab></start>#' file
I get this line with gnu sed :
sed -r 's#(<start>)(.*)(</start>)#echo "\1"$(echo "\2"\|sed "s:a>:ab>:g")"\3"#ge'
see example:
kent$ echo "<start><a></a><a></a><a></a><foo></foo><bar></bar></start>"|sed -r 's#(<start>)(.*)(</start>)#echo "\1"$(echo "\2"\|sed "s:a>:ab>:g")"\3"#ge'
<start><ab></ab><ab></ab><ab></ab><foo></foo><bar></bar></start>
note
this will replace the tags between <start>s which ending with a . which worked for your example. but if you have <aaa></aaa>:
you could do: (I break it into lines for better reading)
sed -r 's#(<start>)(.*)(</start>)
#echo "\1"$(echo "\2"\|sed "s:<a>:<ab>:g;s:</a>:</ab>:g")"\3"
#ge'
e.g.
kent$ echo "<start><a></a><a></a><a></a><aaa></aaa><aba></aba></start>" \
|sed -r 's#(<start>)(.*)(</start>)#echo "\1"$(echo "\2"\|sed "s:<a>:<ab>:g;s:</a>:</ab>:g")"\3"#ge'
<start><ab></ab><ab></ab><ab></ab><aaa></aaa><aba></aba></start>
sed 's/(\<\/?)a\>/\1ab\>/g' yourfile, though that would get <a></a> that was outside <start> as well...
grep -rl 'abc' a.txt | xargs sed -i 's/abc/def/g'