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?
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
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\]'
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.
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.