How do I escape backslashes in a sed script embedd

2019-04-22 20:22发布

问题:

I want to edit a file via a sed script in a bash script. I want this to be easy to maintain later; easy to understand and modify. The replacement string looks like:

PS1='\[\e[1;32m\][\u@\h \W]\$\[\e[0m\]'

In a perfect world, it would like this:

sed -i "s/^PS1.*$/PS1='\[\e[1;32m\][\u@\h \W]\$\[\e[0m\]'/g" /etc/skel/.bashrc

The problem is that bash and sed are stripping out the \ giving the following result in the file:

PS1='[e[1;32m][@h W]$[e[0m]'

Obviously single quotes can't be used. A brute force solution is to use escapes, but for this to work I get a really ugly looking line:

sed -i "s/^PS1.*$/PS1='\\\\[\\\\e[1;32m\\\\][\\\\u@\\\\h \\\\W]\\\\$\\\\[\\\\e[0m\\\\]'/g" /etc/skel/.bashrc

I want the script to be readable and self contained (not using external files). Any alternatives to the above?

回答1:

Bash's printf can add the necessary escapes, leaving the string to be inserted in an readable, editable form.

sed -i "s/^PS1.*$/$(printf "%q" "PS1='\[\e[1;32m\][\u@\h \W]$\[\e[0m\]'")/g" /etc/skel/.bashrc

Not trying to stick it all on one line makes the whole thing clearer.

REPL=$(printf "%q" "PS1='\[\e[1;32m\][\u@\h \W]$\[\e[0m\]'")
sed -i "s/^PS1.*$/$REPL/g" /etc/skel/.bashrc


回答2:

This might work for you:

echo "PS1=abc" |
sed 's/^PS1.*$/PS1='\''\\[\\e[1;32m\\][\\u@\\h \\W]\\$\\[\\e[0m\\]'\''/'
PS1='\[\e[1;32m\][\u@\h \W]\$\[\e[0m\]'


回答3:

Use a sed script file with sed -f. This alternative is not pretty, too, because it means having an additional file lying around, but at least you avoid shell escapes.



回答4:

How about this:

sed -i 's/^PS1.*$/PS1=SINGLEQUOTESLASH[SLASHe[1;32mSLASH][SLASHu@SLASHh SLASHW]SLASH$SLASH[SLASHe[0mSLASH]SINGLEQUOTE/g' /etc/skel/.bashrc
sed -i "s/SINGLEQUOTE/'/g" /etc/skel/.bashrc
sed -i "s/SLASH/\\/g" /etc/skel/.bashrc

Doing it in two passes is less efficient, but a few more microseconds is unnoticeable to most people.