sed to replace all line on the first match not working - sed

Here's the file that i want to be edited
server {
listen 99;
listen 200;
listen 300;
server_name xxxx;
root xxxx;
...
I want to change the first line containing 'listen' to new words like ' listen_xyz 40;', here's my code:
sed -i -e '0,/listen/s/.*/listen_xyz 40;/' file
why it also replace first line (not matching with the pattern), so my file now look like this:
listen_xyz 40;
listen_xyz 40;
listen 200;
listen 300;
server_name xxxx;
root xxxx;
...
whats wrong with my sed code, why it replace the first line even tho its not matchg my pattern?

Try:
$ sed -e '0,/listen/ s/listen.*/listen_xyz 40;/' file
server {
listen_xyz 40;
listen 200;
listen 300;
server_name xxxx;
root xxxx;
...
Explanation
0,/listen/ is a range. It matches all lines from the beginning of the file to the first line that matches the regex listen. Thus, this matches the first two lines of your sample file.
s/.*/listen_xyz 40;/ is a substitute command. It is executed for any line in the range. It replaces any line (.*) with listen_xyz 40;. This means that it replace server { as well as listen 99;.
By changing the substitute command to s/listen.*/listen_xyz 40;/, we make sure that it only replaces lines that contain listen.

Related

Appending using sed pattern after certain line number

I am using following command to append string after AMP, but now I want to add after to AMP which is after SET2 or line number 9, can we modify this command to append the string only after SET2 or line number 9? And if I want to add to only to SET1 AMPs or before line number 9 , could someone help me with the command, thanks.
$ sed -i '/AMP/a Target4' test.txt
$ cat test.txt
#SET1
AMP
Target 1
Target 2
AMP
Target 3
Target 4
Target 5
#Set2
AMP
Target 11
Target 12
Note there is no line between above text.
Would you please try the following:
sed -i '
/^#Set2/,${ ;# if the line starts with "#Set2", execute the {block} until the last line $
/AMP/a Target4 ;# append the string after "AMP"
} ;# end of the block
' test.txt
If you want to append the string before the #Set2 line, please try:
sed -i '
1,/^#Set2/ { ;# excecute the {block} while the line number >= 1 until the line matches the pattern /^#Set2/
/AMP/a Target4
}
' test.txt
The expression address1,address2 is a flip-flop operator. Once the
address1 (line number, regular expression, or other condition) meets,
the operator keeps on returning true until the address2 meets.
Then the following command or block is executed from address1 until
address2.
If you want to add to after AMP which is after #Set2 or line number 9,
I think it is better to process up to the 8th line and after the 9th line separately.
For example, the command is below:
sed '
1,8{
/^#Set2/,${
/AMP/a Target4
}
}
9,${
/AMP/a Target4
}' test.txt

How to find a line in .css file and then changing the correlated config between the following brackets

Let me start off by saying I'm just starting to dabble in sed, awk and regex.
Here's what I need help with.
On ubuntu, in /etc/alternative/gdm3.css I have this config section:
.login-dialog-banner {
color: #d6d6d1; }
I need it to be
.login-dialog-banner{
color: rgba(255,255,255,1);
font-size: 14;
text-align: center;}
I am lost on how to first find .login-dialog-banner and then change the data in the follow on { data }
Would you try the following:
sed '
/\.login-dialog-banner[[:blank:]]*{/{ ;# if the specified 1st line is found
$!{ n ;# and the current line is not the last line, then print it and read the next line
s/.*color:.*/color: rgba(255,255,255,1);\
font-size: 14;\
text-align: center;}/ ;# if the next line contains "color:"
;# then replace the line with the specified lines
}
}' /etc/alternative/gdm3.css
Can you try below sed as per your requirement stated in the question:
sed '/^\.login-dialog-banner {/{N;s/color: #d6d6d1; }/color: rgba(255,255,255,1)\;\nfont-size: 14\;\ntext-align: center\;}/}' /etc/alternative/gdm3.css
I'm searching for the line starting with string .login-dialog-banner { and then substituting the second line : color: #d6d6d1; } with your next required data.
If the above command is working for you, you can include -i option for edit the file inplace.
sed -i '/^\.login-dialog-banner {/{N;s/color: #d6d6d1; }/color: rgba(255,255,255,1)\;\nfont-size: 14\;\ntext-align: center\;}/}' /etc/alternative/gdm3.css
From man sed:
i[SUFFIX], --in-place[=SUFFIX]
edit files in place (makes backup if SUFFIX supplied)

Error in replacing pattern with `sed` command

I am trying to replace occurrences of pattern in a file. Lines in the file look like this:
****time is = 0000
****time is = 0001
I am trying to search string by case insensitive time is and want to replace time is = xxxx by ****.
I tried using sed 's/time \ is/.*' filename.txt
But I get error sed: -e expression #1, char : unterminated 's' command
Any suggestions?
Update
I corrected the command. sed 's/time \ is/.*/' filename.txt But this places .* = xxxx This is not I wanted. I wanted to replace the entire pattern by ****.
Original line: ****time is = 0000
Desired output: ********
Any sugegstions?

Sed: How to insert a pattern which includes single ticks?

I'm trying to use sed to replace a specific line within a configuration file:
The pattern for the line I want to replace is:
ALLOWED_HOSTS.*
The text I want to insert is:
'$PublicIP' (Including the single ticks)
But when I run the command:
sed 's/ALLOWED_HOSTS.*/ALLOWED_HOSTS = ['$PublicIP']/g' /root/project/django/mysite/mysite/settings.py
The line is changed to:
ALLOWED_HOSTS = [1.1.1.1]
instead of:
ALLOWED_HOSTS = ['1.1.1.1']
How shall I edit the command to include the single ticks as well?
You could try to escape the single ticks , or better you can reassign the variable including the simple ticks:
PublicIP="'$PublicIP'".
By the way even this sed without redifining var, works ok in my case:
$ a="3.3.3.3"
$ echo "ALLOWED_HOSTS = [2.2.2.2]" |sed 's/2.2.2.2/'"'$a'"'/g'
ALLOWED_HOSTS = ['3.3.3.3']
Even this works ok:
$ echo "ALLOWED_HOSTS = [2.2.2.2]" |sed "s/2.2.2.2/'$a'/g"
ALLOWED_HOSTS = ['3.3.3.3']

use sed to change a text report to csv

I have a report looks like this:
par_a
.xx
.yy
par_b
.zz
.tt
I wish to convert this format into csv format as below using sed 1 liner:
par_a,.xx
par_a,.yy
par_b,.zz
par_b,.tt
please help.
With awk:
awk '/^par_/{v=$0;next}/^ /{$0=v","$1;print}' File
Or to make it more generic:
awk '/^[^[:blank:]]/{v=$0;next} /^[[:blank:]]/{$0=v","$1;print}' File
When a line starts with par_, save the content to variable v. Now, when a line starts with space, change the line to content of v followed by , followed by the first field.
Output:
AMD$ awk '/^par_/{v=$0}/^ /{$0=v","$1;print}' File
par_a,.xx
par_a,.yy
par_b,.zz
par_b,.tt
With sed:
sed '/^par_/ { h; d; }; G; s/^[[:space:]]*//; s/\(.*\)\n\(.*\)/\2,\1/' filename
This works as follows:
/^par_/ { # if a new paragraph begins
h # remember it
d # but don't print anything yet
}
# otherwise:
G # fetch the remembered paragraph line to the pattern space
s/^[[:space:]]*// # remove leading whitespace
s/\(.*\)\n\(.*\)/\2,\1/ # rearrange to desired CSV format
Depending on your actual input data, you may want to replace the /^par_/ with, say, /^[^[:space:]]/. It just has to be a pattern that recognizes the beginning line of a paragraph.
Addendum: Shorter version that avoids regex repetition when using the space pattern to recognize paragraphs:
sed -r '/^\s+/! { h; d; }; s///; G; s/(.*)\n(.*)/\2,\1/' filename
Or, if you have to use BSD sed (as comes with Mac OS X):
sed '/^[[:space:]]\{1,\}/! { h; d; }; s///; G; s/\(.*\)\n\(.*\)/\2,\1/' filename
The latter should be portable to all seds, but as you can see, writing portable sed involves some pain.