Getting bad flag in substitute command '/' for sed replacement - bash

I am facing one issue while using replace in my sed command. I've a file named a.txt, I want to replace a single line with some other line but I am getting above mentioned error.
Code I want to replace:
DOMAIN_LOCAL = "http://127.0.0.1:3000";
I want it to replace with any other ip lets say something like below:-
DOMAIN_LOCAL = "http://127.1.1.2:3000";
What I've tried:-
ip=http://127.1.1.2:3000
sed "s/DOMAIN_LOCAL = .*$/DOMAIN_LOCAL = "$ip";/g" a.txt
But it is giving me following error. Can somebody help here.
sed: 1: "s/DOMAIN_LOCAL = .*$/DO ...": bad flag in substitute command: '/'

You will need to use another delimiter. And escape the $ or use single quotes:
% ip="http://127.1.1.2:3000"
% sed 's~DOMAIN_LOCAL = .*$~DOMAIN_LOCAL = "'"$ip"'";~' a.txt
DOMAIN_LOCAL = http://127.1.1.2:3000;
When you use / as a delimiter in the substitute command it will be terminated at the first slash in http://:
sed 's/DOMAIN_LOCAL = .*$/DOMAIN_LOCAL = http://127.1.1.2:3000;/'
# ^ here
Breakdown:
sed 's~DOMAIN_LOCAL = .*$~DOMAIN_LOCAL = "'"$ip"'";~' a.txt
# │ ││└ Use double quotes to avoid word splitting and
# │ ││ globbing on $ip
# │ │└ Exit single quotes
# │ └ Literal double quotes
# └ Using single quotes to avoid having to escape special characters

You may need another delimiter instead of "/", for example "%".It worked for me.

use # replace / to avoid this issue
$ sed 's#find#replace#' file

Related

Dynamically replace string value in configuration file

I'm building a shell script to install apache-airflow and update some configurations for local development.
I would like to replace the value of property dags_folder. How can I replace it using shell script?
Here is what I've tried:
if [[ "$OSTYPE" == "darwin"* ]]; then
SED_EXTRA=" "
else
SED_EXTRA=""
fi
sed -i${SED_EXTRA}'' "s,dags_folder = ,dags_folder = banana,g" ~/airflow/airflow.cfg
It's almost working but I want to replace entire value. Is possible?
Don't use sed at all. Use ed, which won't require OS-specific changes to the invocation.
You want to match the entire line, not just the name = prefix, so add .* to the regular expression.
ed ~/airflow/airflow.cfg <<EOF
s,dags_folder = .*,dags_folder = banana,g
wq
EOF
Match up until the end of the line with .* regex
sed -i${SED_EXTRA}'' 's,dags_folder = .*,dags_folder = banana,g' ~/airflow/airflow.cfg
try this one if I understand your issue correctly :)
var1="dags_folder ="
var2="dags_folder = banana"
sed -i 's/'"$var1"'/'"$var2"'/g' path to your cfg file

Sed an entire line with only the begin of the line

I have a config file with this line:
foo.bar = http://localhost/foo
I want to replace this line with a new url. For example:
foo.bar = http://new_url/bar
But I don't know the original url, I only know the name of the parameter.
I tried this:
sed "s!^foo.bar.*!foo.bar = http://new_url/bar!" test.ini
But it return an error
Use single quotes to prevent shell expansion:
sed -e 's!^foo.bar.*!foo.bar = http://new_url/bar!'
In bash double-quotes and ! don't go well when placed inside ( see HISTORY EXPANSION in man bash), change the separator to # (or) use single-quotes
sed 's#foo.bar.*#foo.bar = http://new_url/bar#' file
foo.bar = http://new_url/bar

Sed fails to update long text

Consider test file csf.conf:
CC_DENY = ""
Running the command:
sed -i -E 's/(CC_DENY *= *")[^"]+/\1AR,BE,CL,CN,CO,CS,ES,FR,GR,HK,IT,KO,PA,PE,PH,PL,RS,RU,SG,SK,TH,UA,VN,AE,AF,AL,AS,AZ,BA,BD,BF,BH,BJ,BN,CI,DJ,EG,EH,ER,ET,GM,GN,GW,IQ,IR,IS,JO,KG,KM,KW,KZ,LB,LY,MC,MK,ML,MR,MV,MY,NE,NG,OM,PK,PS,QA,SA,SD,SL,SN,SO,SY,TD,TJ,TM,TN,TR,UZ,XK,YE,YT/g' csf.conf
Does not replace the match inside the file. Output should look like this:
CC_DENY="AR,BE,CL,CN,CO,CS,ES,FR,GR,HK,IT,KO,PA,PE,PH,PL,RS,RU,SG,SK,TH,UA,VN,AE,AF,AL..."
Sed v4.2.2, same result on Debian 8, and Centos 7
This has nothing to do with long text, your regexp just doesn't match the content of your file. Change [^"]+ to [^"]* so it'll match even when there's nothing between the double quotes "". Look:
$ cat csf.conf
CC_DENY = ""
$ sed -E 's/(CC_DENY *= *")[^"]+/\1foo/' csf.conf
CC_DENY = ""
$ sed -E 's/(CC_DENY *= *")[^"]*/\1foo/' csf.conf
CC_DENY = "foo"
wrt the comment below from the OP that this sed command works:
$ cat file
LF_SPI = ""
$ sed -E 's/(LF_SPI *= *\")[^\"]+/\1blah/g' file
LF_SPI = ""
Clearly and predictably, no it does not. It simply can't because the regexp metacharacter + means 1 or more so [^\"]+ states there must be at least one non-" after the " and that just does not exist in the input file. There is no reason to escape the double quotes btw.
Suppose the current variable value in the file is empty. Then your regular expression doesn't match because [^"]+ means "any character, except double quote repeated one or more times".
You might fix it by replacing + quantifier with * (zero or more times). But suppose the value contains a double quote:
CC_DENY = "\""
Then the [^"]* will match everything until it gets to the double quote within the value.
Thus, I suggest the following command:
# Put the variable value here
value='AR,BE\\" ... YE,YT';
sed -i -r 's/^( *CC_DENY *= *").*"/\1'"$value"'"/' csf.conf
Also note, that the expression above uses an anchor for the beginning of the line. Otherwise, it will fail to match as expected, if such a CC_DENY = "... exists in the variable value in the configuration file: CC_DENY = "SOMETHING_CC_DENY = \"value\"".
Sed is certainly the wrong tool for this:
#!/usr/bin/awk -f
BEGIN {
FS = OFS = "\42"
}
$2 = "AR,BE,CL,CN,CO,CS,ES,FR,GR,HK,IT,KO,PA,PE,PH,PL,RS,RU,SG,SK,TH,UA,VN," \
"AE,AF,AL,AS,AZ,BA,BD,BF,BH,BJ,BN,CI,DJ,EG,EH,ER,ET,GM,GN,GW,IQ,IR,IS,JO,KG," \
"KM,KW,KZ,LB,LY,MC,MK,ML,MR,MV,MY,NE,NG,OM,PK,PS,QA,SA,SD,SL,SN,SO,SY,TD,TJ," \
"TM,TN,TR,UZ,XK,YE,YT"

ssh sed not changing variables correctly

I'm trying to use sed to change a variable in the site.js file on my server.
Here is the line: var url = "page.php"; I'm looking to just substitute page.php for whatever.php.
I thought this would be pretty simple and I figured this would work with no issues:
sed -i "s/\url = \".*\"/\url = \"page2.php\"/" /home/site.js
It works okay except instead of getting: var url = "page2.php"; I get: var R1 = "page2.php";
Why is the url value being changed to R1 when I use sed here?
You don't need \ before url.
sed -i -r 's#url\s*=\s*"[^"]+"#url = "page2.php"#' /home/site.js
Extra escaping of " can be eliminated by enclosing sed expression with ' instead of "
It's better to use different separator than / (here #) when the strings themselves may contain /
Try doing this :
sed -i -r 's#(var\s+url\s*=\s*")[^"]+"#\1whatever.php"#' file.js
/ is not mandatory as delimiter, I've picked up # there.
Here's another example: Took me while to figure that you change the / for delimiter and not the / in the directory path.
Use # instead of / for sed delimiter if you have dir path names.
First I tried this:
[root#ip-172-35-24-37 ec2-user]# egrep -q "^(\s*\S+\s+)/dev/shm(\s+\S+\s+\S+)(\s+\S+\s+\S+)(\s*#.*)?\s*$" /etc/fstab && sed -ri "s/^(\s*\S+\s+)/dev/shm(\s+\S+\s+\S+)(\s+\S+\s+\S+)(\s*#.*)?\s*$/\1/dev/shm\2nodev\3\4/" /etc/fstab
And got this error:
sed: -e expression #1, char 20: unknown option to `s'
So then I used # for the sed delimiter instead of /:
[root#ip-172-35-24-37 ec2-user]# egrep -q "^(\s*\S+\s+)/dev/shm(\s+\S+\s+\S+)(\s+\S+\s+\S+)(\s*#.*)?\s*$" /etc/fstab && sed -ri "s#^(\s*\S+\s+)/dev/shm(\s+\S+\s+\S+)(\s+\S+\s+\S+)(\s*#.*)?\s*$#\1/dev/shm\2nodev\3\4##" /etc/fstab
[root#ip-172-35-24-37 ec2-user]#
And it worked.
You can use something else besides # for a delimiter like ! or ? or %. Just don't use / if you have dir paths.

How do I insert a newline/linebreak after a line using sed

It took me a while to figure out how to do this, so posting in case anyone else is looking for the same.
For adding a newline after a pattern, you can also say:
sed '/pattern/{G;}' filename
Quoting GNU sed manual:
G
Append a newline to the contents of the pattern space, and then append the contents of the hold space to that of the pattern space.
EDIT:
Incidentally, this happens to be covered in sed one liners:
# insert a blank line below every line which matches "regex"
sed '/regex/G'
This sed command:
sed -i '' '/pid = run/ a\
\
' file.txt
Finds the line with: pid = run
file.txt before
; Note: the default prefix is /usr/local/var
; Default Value: none
;pid = run/php-fpm.pid
; Error log file
and adds a linebreak after that line inside file.txt
file.txt after
; Note: the default prefix is /usr/local/var
; Default Value: none
;pid = run/php-fpm.pid
; Error log file
Or if you want to add text and a linebreak:
sed -i '/pid = run/ a\
new line of text\
' file.txt
file.txt after
; Note: the default prefix is /usr/local/var
; Default Value: none
;pid = run/php-fpm.pid
new line of text
; Error log file
A simple substitution works well:
sed 's/pattern.*$/&\n/'
Example :
$ printf "Hi\nBye\n" | sed 's/H.*$/&\nJohn/'
Hi
John
Bye
To be standard compliant, replace \n by backslash newline :
$ printf "Hi\nBye\n" | sed 's/H.*$/&\
> John/'
Hi
John
Bye
sed '/pattern/a\\r' file name
It will add a return after the pattern while g will replace the pattern with a blank line.
If a new line (blank) has to be added at end of the file use this:
sed '$a\\r' file name
Another possibility, e.g. if You don't have an empty hold register, could be:
sed '/pattern/{p;s/.*//}' file
Explanation:
/pattern/{...} = apply sequence of commands, if line with pattern found,
p = print the current line,
; = separator between commands,
s/.*// = replace anything with nothing in the pattern register,
then automatically print the empty pattern register as additional line)
The easiest option -->
sed 'i\
' filename

Resources