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'
Related
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
#!/bin/sh
arr=(
a
b
c
)
sed "s/abc/${arr[#]}/" file
sh -x this_script.sh show the result with error:
+ arr=(a b c)
+ sed s/abc/a b c/ file
sed: -e expression #1, char 5: unterminated `s' command
it should be:
+ sed 's/abc/a b c/' file
there's already double quotation in this script, why need declare a variable to make it work:
x=${arr[#]}
sed "s/abc/$x/" file
You can use ${arr[*]} instead of ${arr[#]} to be treated it like a single string:
sed "s/abc/${arr[*]}/" <<< "abc"
a b c
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.
I'm getting totally crazy with the following script.
The following command works as expected :
echo a | sed 's/a/b/'
Output :
b
But this script doesn't :
test="'s/a/b/'"
echo a | sed $test
Output :
sed: -e expression #1, char 1: unknown command : `''
I should really be stupid, but I don't see what I am missing.
Thanks,
test="'s/a/b/'"
echo a | sed $test
is equivalent to:
test="'s/a/b/'"
echo a | sed "'s/a/b/'"
Obviously sed doesn't understand the command with both " and ', It interprets ' as a command. You can use either one of them:
test='s/a/b/'
Or
test='s/a/b/'
This is because your double wrapping your string. test="'s/a/b'". Sed then gets 's/a/b/' as literal string. You only want sed to receive s/a/b/.
You only need to wrap the string in one set of quotes, otherwise the inner set of quotes will be interpreted as part of the argument.
you may want this:
kent$ test="s/a/b/"
kent$ echo a | sed ${test}
b
or
kent$ echo a | sed $test
b
or
test=s/a/b/