Why does this code return an error?
#!/bin/bash
ARG=$1
MYVAR="TEST"
FILE="/path/to/file/$ARG"
AAA="/path/test/$MYVAR"
BBB="foo bar $AAA bar foo $AAA"
sed -i -e "s/TEXT/$BBB/g" $FILE
sed: -e expression #1, char 58: unknown option to `s'
Your replacement ($BBB) has slashes in it, the same delimiter you are using for sed. Use another:
sed -i -e "s|TEXT|$BBB|g" $FILE
Using the debug mode (use #!/bin/bash -x as a shebang):
+ ARG=foo
+ MYVAR=TEST
+ FILE=/path/to/file/foo
+ AAA=/path/test/TEST
+ BBB='foo bar /path/test/TEST bar foo /path/test/TEST'
+ sed -i -e 's/TEXT/foo bar /path/test/TEST bar foo /path/test/TEST/g' /path/to/file/foo
sed: -e expression #1, char 18: unknown option to `s'
Other people gave an explanation.
Related
This function is part of a shell script:
function json_ccp {
local PP=$(one_line_pem $4)
local CP=$(one_line_pem $5)
sed -e "s/\${ORG}/$1/" \
-e "s/\${P0PORT}/$2/" \
-e "s/\${P1PORT}/$6/" \
-e "s/\${CAPORT}/$3/" \
-e "s#\${PEERPEM}#$PP#" \
-e "s#\${CAPEM}#$CP#" \
organizations/ccp-template.json
}
I get the following error when I execute the script:
sed: -e expression #5, char 841: unterminated `s' command
Everything looks correct to me, in the last two sed expressions I have used # instead of / as a delimiter.
$ sed --version
sed (GNU sed) 4.8
I am using the sed command on Ubuntu to replace content.
This initial command comes from here.
sed -i '$ s/$/ /replacement/' "$DIR./result/doc.md"
However, as you can see, I have a slash in the replacement. The slash causes the command to throw:
sed: -e expression #1, char 9: unknown option to `s'
Moreover, my replacement is stored in a variable.
So the following will not work because of the slash:
sed -i "$ s/$/ $1/" "$DIR./result/doc.md"
As stated here and in duplicate, I should use another delimiter. If I try with #:
sed -i "$ s#$# $1#" "$DIR./result/doc.md"
It gives the error:
sed: -e expression #1, char 42: unterminated `s' command
My question is:
How can I use a variable in this command as well as other delimiter than / ?
Don't use sed here; perl and awk allow more robust approaches.
sed doesn't allow variables to be passed out-of-band from code, so they always need to be escaped. Use a language without that limitation, and you have code that always works, no matter what characters your data contains.
The Short Answer: Using perl
The below is taken from BashFAQ #21:
inplace_replace() {
local search=$1; shift; local replace=$1; shift
in="$search" out="$replace" perl -pi -e 's/\Q$ENV{"in"}/$ENV{"out"}/g' "$#"
}
inplace_replace '#' "replacement" "$DIR/result/doc.md"
The Longer Answer: Using awk
...or, using awk to do a streaming replacement, and a shell function to make that file replacement instead:
# usage as in: echo "in should instead be out" | gsub_literal "in" "out"
gsub_literal() {
local search=$1 replace=$2
awk -v s="${search//\\/\\\\}" -v r="${rep//\\/\\\\}" 'BEGIN {l=length(s)} {o="";while (i=index($0, s)) {o=o substr($0,1,i-1) r; $0=substr($0,i+l)} print o $0}'
}
# usage as in: inplace_replace "in" "out" /path/to/file1 /path/to/file2 ...
inplace_replace() {
local search=$1 replace=$2 retval=0; shift; shift
for file; do
tempfile=$(mktemp "$file.XXXXXX") || { retval |= $?; continue; }
if gsub_literal "$search" "$replace" <"$file" >"$tempfile"; then
mv -- "$tempfile" "$file" || (( retval |= $? ))
else
rm -f -- "$tempfile" || (( retval |= $? ))
fi
done
}
TL;DR:
Try:
sed -i '$ s#$# '"$1"'#' "$DIR./result/doc.md"
Long version:
Let's start with your original code:
sed -i '$ s/$/ /replacement/' "$DIR./result/doc.md"
And let's compare it to the code you referenced:
sed -i '$ s/$/abc/' file.txt
We can see that they don't exactly match up. I see that you've correctly made this substitution:
file.txt --> "$DIR./result/doc.md"
That looks fine (although I do have my doubts about the . after $DIR ). However, the other substitution doesn't look great:
abc --> /replacement
You actually introduced another delimeter /. However, if we replace the delimiters with '#' we get this:
sed -i '$ s#$# /replacement#' "$DIR./result/doc.md"
I think that the above is perfectly valid in sed/bash. The $# will not be replaced by the shell because it is single quoted. The $DIR variable will be interpolated by the shell because it is double quoted.
Looking at one of your attempts:
sed -i "$ s#$# $1#" "$DIR./result/doc.md"
You will have problems due to the shell interpolation of $# in the double quotes. Let's correct that by replacing with single quotes (but leaving $1 unquoted):
sed -i '$ s#$# '"$1"'#' "$DIR./result/doc.md"
Notice the '"$1"'. I had to surround $1 with '' to basically unescape the surrounding single quotes. But then I surrounded the $1 with double quotes so we could protect the string from white spaces.
Use shell parameter expansion to add escapes to the slashes in the variable:
$ cat file
foo
bar
baz
$ set -- ' /repl'
$ sed "s/$/$1/" file
sed: 1: "s/$/ /repl/": bad flag in substitute command: 'r'
$ sed "s/$/${1//\//\\\/}/" file
foo /repl
bar /repl
baz /repl
That is a monstrosity of leaning toothpicks, but it serves to transform this:
sed "s/$/ /repl/"
into
sed "s/$/ \/repl/"
The same technique can be used for whatever you choose as the sed s/// delimiter.
I wrote this code:
cat /etc/passwd | cut -d : -f1 | sed -n "${FT_LINE1}, ${FT_LINE2} p"
Output:
sed: -e expression #1, char 1: unknown command: `,'
But I have a problem with variables $FT_LINE1, $FT_LINE2.
When I use constants instead of a variables, this code works correctly
cat /etc/passwd | cut -d : -f1 | sed -n "3, 5 p"
I tried to use these constructions:
sed -n -e "${FT_LINE1}, ${FT_LINE2} p"
sed -n "{$FT_LINE1}, {$FT_LINE2} p"
sed -n "${FT_LINE1},${FT_LINE2} p"
sed -n "${FT_LINE1}, ${FT_LINE2}" p
sed -n "$FT_LINE1, $FT_LINE2" p
but the error remained.
As noted in melpomene and PesaThe's comments, sed address ranges can't be blank, both shell variables ${FT_LINE1}, and ${FT_LINE2}, must be set to some appropriate value.
This simplest way to reproduce the error is:
sed ,
Which outputs:
sed: -e expression #1, char 1: unknown command: `,'
Because , is not a sed command, it's just a delimiter that separates range addresses.
It might help to look at some other related errors. Let's add a starting address of 1:
sed 1,
Output:
sed: -e expression #1, char 2: unexpected `,'
Which seems unhelpful, since it should be expecting an address after the ,. Now let's add a second address of 1:
sed 1,1
Output:
sed: -e expression #1, char 3: missing command
A little better, but really it's char 4 that's missing a command, or rather there's a missing command after char 3.
Now let's add a command, and a bit of input and it works:
echo foo | sed 1,1p
Output:
foo
I would like to find and replace a string in multiple files using bash command. I am using sed which I am not really familiar with.
My variables:
$FILE = (/home/user/file1.txt, /home/user/file2.txt)
$REL = 5.0
My code:
for f in ${FILES[#]}; do sed -i "$f" "s/__ver__ =*/__ver__=$REL/g";
output:
sed: -e expression #1, char 2: unknown command: `/'
sed: -e expression #1, char 2: unknown command: `/'
What is wrong with my expression?
1) The filename should be specified as the last argument for sed expression:
2) bash's for loop should ended with done keyword
for f in ${FILES[#]}; do sed -i "s/__ver__ =*/__ver__=$REL/" "$f"; done
If your files have similar naming format you can avoid for loop:
sed -i 's/__ver__ =*/__ver__=$REL/' /home/user/file[2].txt
I used the below command to replace the "mppu" word with "hihi" and it was working right.
sed 's/mppu/'`echo "hihi"`'/' memo.cir
but when I was trying the below command
sed 's/mppu/'`echo "hi hi"`'/' memo.cir
then it gives error as
sed: -e expression #1, char 9: unterminated `s' command.
I really don't why it is giving such error as i just added a space in hihi
the correct syntax will be as follows.
Solution 1st: For simple replacement of a string.
sed 's/old_text/new_text/' Input_file
You need not to mention echo and all there.
Solution 2nd: In case you want to search for a string and then do a substitution of any string then following may help you in same.
sed '/look_for_string/s/old_text/new_test/' Input_file
Solution 3rd: If you want to change multiple/all occurrences of any string into a single line then following may help you too by adding g at last of command.
sed '/look_for_string/s/old_text/new_text/g' Input_file
Solution 4th: In case you want to do the changes into Input_file itself then following may help you in same.
sed -i '/look_for_string/s/old_text/new_text/g' Input_file
EDIT1: As per OP, code should replace a variable's value to line then following may help you in same then.
VAL="SINGH"
sed 's/tools/'"$VAL"'/' Input_file
EDIT2: Adding an example for OP for substituting the nth number of a string if it matched a string.
Let's say following is my Input_file.
cat Input_file
31116441
AAA,hi,hi,hi,hji
AAA
AA
BBB
BB
Now to substitute the 3rd occurrence of string(hi) for a line which stars from AAA we could do following then.
sed '/AAA/s/hi/cha_cha_ch_ch_cha/3' Input_file
31116441
AAA,hi,hi,cha_cha_ch_ch_cha,hji
AAA
AA
BBB
BB
You need to quote the output from external command. set -x helps to debug what is going wrong.
$ set -x
# can also use: echo 'asd mppu foo' | sed 's/mppu/'"`echo "hi hi"`"'/'
$ echo 'asd mppu foo' | sed 's/mppu/'"$(echo "hi hi")"'/'
+ echo 'asd mppu foo'
++ echo 'hi hi'
+ sed 's/mppu/hi hi/'
asd hi hi foo
You can see that hi hi is within outer single quotes. Without double quotes, you'd get
$ echo 'asd mppu foo' | sed 's/mppu/'`echo "hi hi"`'/'
+ echo 'asd mppu foo'
++ echo 'hi hi'
+ sed s/mppu/hi hi/
sed: -e expression #1, char 9: unterminated `s' command
Similarly, newlines would cause issue
$ echo 'asd mppu foo' | sed 's/mppu/'"$(printf "hi hi\nabc")"'/'
+ echo 'asd mppu foo'
++ printf 'hi hi\nabc'
+ sed 's/mppu/hi hi
abc/'
sed: -e expression #1, char 12: unterminated `s' command
With variables instead of external command:
$ r='hi hi'
$ echo 'asd mppu foo' | sed 's/mppu/'"$r"'/'
+ echo 'asd mppu foo'
+ sed 's/mppu/hi hi/'
asd hi hi foo
$ echo 'asd mppu foo' | sed 's/mppu/'$r'/'
+ sed s/mppu/hi hi/
sed: -e expression #1, char 9: unterminated `s' command
+ echo 'asd mppu foo'
See Why does my shell script choke on whitespace or other special characters? for more details on this topic
you can use
sed 's/old/new/g' file
if you want to replace variable,you can use the follow tow methods
sed -i 's/XXXXX/${WEEK_DAY}/g' ==> sed -i "s/XXXXX/${WEEK_DAY}/g"
sed -i 's/XXXXX/${WEEK_DAY}/g' ==> sed -i 's/XXXXX/'${WEEK_DAY}'/g'