sed in-place replacement inside a bash for loop - bash

I can replace text with the following command:
for f in $(ls some/dir); do sed 's/XXX/YYY/g' template.$f.txt; done
But when I try to use in-place replacement I fail:
sed: 1: "template.test00.types ...": undefined label 'emplate.test00.types.txt'
What am I doing wrong?
EDIT: Here is a complete minimal example:
for f in $(ls some/dir); do echo $f && cat -n some/dir/$f; done
a.txt
1 path: XXX/725
b.txt
1 path: XXX/615
c.txt
1 path: XXX/931
Here is how sed works correctly without actual replacement:
for f in $(ls some/dir); do sed 's/XXX/YYY/g' some/dir/$f; done
path: YYY/725
path: YYY/615
path: YYY/931
And here is the failure:
for f in $(ls some/dir); do sed -i 's/XXX/YYY/g' some/dir/$f; done
sed: 1: "some/dir/a.txt": unterminated substitute pattern
sed: 1: "some/dir/b.txt": unterminated substitute pattern
sed: 1: "some/dir/c.txt": unterminated substitute pattern

Related

Replace a string in multiple files using sed

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

unix scripting error with sed command

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'

What's wrong with this sed ? (trying to delete a line)

I'm new in bash, and I'm trying to delete a line in a file I'm creating.
So without further ado :
if [[ $(ls -1 | grep 'fichiers.toCheck' | wc -l) -eq 0 ]]; then
touch fichiers.toCheck
fi
find . -name '*.mp4' > fichiers.toCheck
while read p; do
echo $p
sed -i "$p/d" ./fichiers.toCheck
done <fichiers.toCheck
Console is giving me this:
sed: 1: "./fichiers.toCheck": invalid command code .
I'm suspecting sed interprets the "/" in the line as an argument (the line is something like "./nosound.mp4".
What's your guess?
edit 2 = the correct syntax was with -i.bak
sed -i.bak "s#$p##" fichiers.toCheck
edit = so here's my experiments :
1
while read p; do
echo $p
sed -i "/$p/d" fichiers.toCheck
done <fichiers.toCheck
And I get :
sed: 1: "fichiers.toCheck": invalid command code f
2
sed -i "#$p#d" fichiers.toCheck
and same error :
sed: 1: "fichiers.toCheck": invalid command code f
Your sed syntax is wrong, to delete a line containing a pattern from a bash variable. Also being using FreeBSD native sed in OS X use the -i.bak for in-place edits.
sed -i.bak "/$p/d" fichiers.toCheck
If you suspect your variable contains / change the sed separator to # and use the traditional pattern s/<pattern>/<replacement>/ style with the replacement part set to empty, i.e.
sed -i.bak "s#$p##" fichiers.toCheck

${arr[#]} in sed command

#!/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

Bash expand variable containing sed pattern correctly

I have a script like this:
#!/bin/bash
xx="-e \"s|a|b|g\""
sed -i $xx file
But sed breaks with message:
sed: -e expression #1, char 1: unknown command: `"'
Using set -x I can see that the command is being expanded to sed -i -e '"s|a|b|g"' file, so I guess the double quotes are why it is not working.
How to fix this?
I'm not sure exactly why you want to do what you're doing but I think that this might help:
$ cat file
a a
$ xx=( -e 's|a|b|g' -e 's|b|c|g' )
$ sed "${xx[#]}" file
c c
Use an array to store each argument to sed. Use "${xx[#]}" to safely expand the array, passing each element as a single argument.
You can build up the array like this:
$ xx=()
$ xx+=( -e 's|a| b c |g' )
$ xx+=( -e 's|c| d |g' )
$ sed "${xx[#]}" file
b d b d
You could try expanding the strings using eval, but it is not often recommended by bash aficionados.
#!/bin/bash
xx="-e 's|b|a|g'"
eval sed -i "$xx" file
You can see it getting expanded when using eval, below is the snippet from set +x
++ xx='-e '\''s|a|b|g'\'''
++ eval sed -i '-e '\''s|a|b|g'\''' file
+++ sed -i -e 's|a|b|g' file
To see it in action:-
$ cat file
line1/script
alaalaala++
line1/script
line2/script
line3/script
alaalaala--
line1/script
$ ./script.sh ; cat file
line1/script
blbblbblb++
line1/script
line2/script
line3/script
blbblbblb--
line1/script

Resources