I'm using the Git Bash shell on Windows, and trying to replace a string like this in an XML file using sed:
<customTag>C:\path\to\2016a.0</customTag>
To a string like this:
<customTag>C:\path\to\2017b.0</customTag>
I can do the replacement directly like this:
$ cat test.txt
<customTag>C:\path\to\2016a.0</customTag>
$ sed -i 's^<customTag>C:\\path\\to\\2016a.0</customTag>^<customTag>C:\\path\\to\\2017b.0</customTag>^g' test.txt
$ cat test.txt
<customTag>C:\path\to\2017b.0</customTag>
But if I need to pass in variables for those strings, the replacement doesn't work.
$ cat test.txt
<customTag>C:\path\to\2016a.0</customTag>
$ export OLD_VER=2016a.0
$ export NEW_VER=2017b.0
$ sed -i 's^<customTag>C:\\path\\to\\${OLD_VER}</customTag>^<customTag>C:\\path\\to\\${NEW_VER}</customTag>^g' test.txt
$ cat test.txt
<customTag>C:\path\to\2016a.0</customTag>
Or if I use double quotes around the sed expression, I get "Invalid back reference", presumably because it thinks the 2 in the year is a reference.
$ sed -i "s^<customTag>C:\\path\\to\\${OLD_VER}</customTag>^<customTag>C:\\path\\to\\${NEW_VER}</customTag>^g" test.txt
sed: -e expression #1, char 87: Invalid back reference
What's the correct way to escape or quote this, or would I be better off using something like awk?
Keep the single quotes on the ends, and add single quotes around each variable. The single quotes prevent the shell from collapsing your double backslashes. The extra single quotes leave the variable refs outside of quotes.
Or (don't laugh) consider using forward slashes. Windows recognizes both kinds of slash as path separators; it's only the DOS command shell that does not.
Related
I have into a text file the following line :
\[Omega]BD=100;
I would like to replace with gsed the value 100 by a shell variable (zsh shell), here 600 :
I tried :
$ i=600
$ gsed 's/\[Omega]BD=.*/\[Omega]BD=\'\\"$i"\\';/' text_to_modify.txt | grep 600
but it returns me :
\[Omega]BD=\600; and not \[Omega]BD=600;
The is an additional backslash that I don't want, I wonder how could I remove this backslash. I would like to keep the two single quotes of gsed 's/.../.../'
Using sed;
i=600
$ sed "/\[Omega]/s/[[:digit:]]\+/$i/" input_file
\[Omega]BD=600;
You may use this sed command:
i=600
sed -E "s/(\\\\\[Omega]BD=).*/\1$i;/" file
\[Omega]BD=600;
We require additional escaping i.e. \\\\ to match a single \ because we are using double quotes around full sed command.
Or we can avoid you can use this combination of single and double quotes to avoid extra escaping:
sed -E 's/(\\\[Omega]BD=).*/\1'"$i;/" file
I want to use grep to count the number of W occurrences in the file.txt, save it as the variable WATER_NUMBER. Then append that number to the end of file.txt.
Following here,
I tried
#!/bin/bash -l
WATER_NUMBER="$(grep -c W file.txt)"
sed -i -e '$a\"${WATER_NUMBER}"' file.txt
but I got "${WATER_NUMBER}" printed out, instead of the number. Can I ask how to modify it?
The command
sed -i '$a\"${WATER_NUMBER}"' file.txt
will simply add the line "${WATER_NUMBER}" at the end of the file. You could try
sed -i "$ a\$WATER_NUMBER" file.txt
but this will still add the line $WATER_NUMBER. The problem is that the variable WATER_NUMBER is not expanded in the sed script. In order to pass its value to sed, place it outside the quoting, like this
sed -i '$ a\'$WATER_NUMBER file.txt
Edit: I actually wrote my answer yesterday without really thinking about the reason as to why the variable is not expanded. This morning I wondered why this is the case even though the variable is in double quotes as opposed to single quotes. The reason is actually just the coincidence that the \ from the append command is in front of the $ from the variable, thus escaping it. To prevent this, you need to escape the \. On the other hand, a backslash is actually not needed to separate the a from the line you want to add, hence
sed -i "$ a $WATER_NUMBER" file.txt
will do the job.
How to save a number to a variable?
WATER_NUMBER=42
How to append the variable content to a file?
echo $WATER_NUMBER >> file.txt
I want to replace with sed in some bash script something like:
s:44:\"STRING\"
To:
s:NEWSTRING:\"NEWSTRING2\"
I tried many ways with escaping special characters, but I got always error
sed: -e expression #1, char 32: unterminateds' command`
or someting like that.
Can you please tell me the correct sed -i (sed -i "s/xxx/xxx/g" file) command for that?
You have to escape the backslashes properly:
sed 's/s:44:\\"STRING\\"/s:NEWSTRING:\\"NEWSTRING2\\"/'
Example:
$ echo 's:44:\"STRING\"' | sed 's/s:44:\\"STRING\\"/s:NEWSTRING:\\"NEWSTRING2\\"/g'
s:NEWSTRING:\"NEWSTRING2\"
You are missing the final delimiter. In your case it seems to be : therefore, you need to add a final : after your substitution content. It does not matter if you are using modification instruction like g
File.txt
/aaa/bbb/ccc/ddd
/aaa/bbb/ccc/mmm
/aaa/eee/ccc/ddd
if my $(pwd) is /aaa/bbb/ccc
the it should delete only first two
I have tried like sed /^$(pwd)/d but not worked
The problem here is that you are using $(pwd), which tries to execute a command pwd. This result contains slashes, so that the final command is something like:
sed /^/aaa/bbb/ccc/d
Which sed cannot handle and returns an error:
sed: -e expression #1, char 4: extra characters after command
You should instead use another delimiter. For example, _:
sed "\_${PWD}_d"
As 123 comments below, you need to escape the first delimiter if it is not a substitution. I also enclose the var within ${ } to prevent the variable to be considered PWD_ instead of PWD.
You can use awk for a nicer approach:
$ awk -v patt="$PWD" '!($0 ~ patt)' file
/aaa/eee/ccc/ddd
Note $PWD is the same as executing pwd.
grep can also do the job:
grep -v "$(pwd)" file
Just to precise the answer of fedorqui...
In your question there is another problem because you variable $pwd contain special sed symbols (/).
So the sed will not be glad...
Some solution for example could be find here : Replace a string in shell script using a variable
So you could use additional variable to correct this problem.
This work perfectly for your example (I just replace echo $(pwd) by 'echo /aaa/bbb/ccc').
pwd_bis=$( echo $(pwd) | sed 's/[\/]/\\\0/g' )
sed "/^${pwd_bis}/d" File.txt
Basically I want to copy several lines of code from a template file to a script file.
Is it even possible to use sed to copy a string full of symbols that interact with the script?
I used these lines:
$SWAP='sudo cat /home/kaarel/template'
sed -i -e "s/#pointer/${SWAP}/" "script.sh"
The output is:
./line-adder.sh: line 11: =sudo cat /home/kaarel/template: No such file or directory
No, it is not possible to do this robustly with sed. Just use awk:
awk -v swap="$SWAP" '{sub(/#pointer/,swap)}1' script.sh > tmp && mv tmp script.sh
With recent versions of GNU awk there's a -i inplace flag for inplace editing if that's something you care about.
Good point about "&&". Here's the REALLY robust version that will work for absolutely any character in the search or replacement strings:
awk -v old="#pointer" -v new="$SWAP" 's=index($0,old){$0 = substr($0,1,s-1) new substr($0,s+length(old))} 1'
e.g.:
$ echo "abc" | awk -v old="b" -v new="m&&n" 's=index($0,old){$0 = substr($0,1,s-1) new substr($0,s+length(old))} 1'
am&&nc
There are two issues with the line:
$SWAP='sudo cat /home/kaarel/template'
The first is that, before executing the line, bash performs variable expansion and replaces $SWAP with the current value of SWAP. That is not what you wanted. You wanted bash to assign a value to SWAP.
The second issue is that the right-hand side is enclosed in single-quotes which protect the string from expansion. You didn't want to protect the string from expansion: you wanted to execute it. To execute it, you can use back-quotes which may look similar but act very differently.
Back-quotes, however, are an ancient form of asking for command execution. The more modern form is $(...) which eliminates some problems that back-quotes had.
Putting it all together, use:
SWAP=$(sudo cat /home/kaarel/template)
sed -i -e "s/#pointer/${SWAP}/" "script.sh"
Be aware, though, that the sed command may have problems if there are any sed-active characters in the template file.