如何在嵌入到Bash脚本中的sed脚本中转义反斜杠

8

我希望能够通过bash脚本中的sed脚本来编辑一个文件。我的目标是让这个脚本易于维护、易于理解和修改。替换字符串的格式如下:

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

在一个完美的世界中,它应该是这样的:
sed -i "s/^PS1.*$/PS1='\[\e[1;32m\][\u@\h \W]\$\[\e[0m\]'/g" /etc/skel/.bashrc

问题在于bash和sed会去除\,导致文件中出现以下结果:
PS1='[e[1;32m][@h W]$[e[0m]'

很明显,不能使用单引号。一种暴力解决方法是使用转义字符,但这样做会得到一行非常丑陋的代码:
sed -i "s/^PS1.*$/PS1='\\\\[\\\\e[1;32m\\\\][\\\\u@\\\\h \\\\W]\\\\$\\\\[\\\\e[0m\\\\]'/g" /etc/skel/.bashrc

我希望脚本易读且自包含(不使用外部文件)。有没有其他替代方案?

在正则表达式中,除非你确实需要将某些变量插入到字符串中,否则请使用单引号。即使需要插入变量,也请在大部分正则表达式周围使用单引号,并仅在必须插入的部分周围使用双引号。例如:sed -e 's/\.\*'"$1"'\*\./ab'"$2"'c'\''d/' $3 或类似的命令。序列 '\'' 是如何嵌入单引号到命令行中的;第一个单引号结束当前的单引号段;反斜杠-引号将单引号嵌入到字符串中;第三个单引号恢复单引号。 - Jonathan Leffler
4个回答

5
Bash的printf可以添加必要的转义字符,使字符串以可读、可编辑的形式插入。
sed -i "s/^PS1.*$/$(printf "%q" "PS1='\[\e[1;32m\][\u@\h \W]$\[\e[0m\]'")/g" /etc/skel/.bashrc

不要试图将所有内容都放在一行上,这样整个内容会更清晰易懂。
REPL=$(printf "%q" "PS1='\[\e[1;32m\][\u@\h \W]$\[\e[0m\]'")
sed -i "s/^PS1.*$/$REPL/g" /etc/skel/.bashrc

4
这可能对您有用:
echo "PS1=abc" |
sed 's/^PS1.*$/PS1='\''\\[\\e[1;32m\\][\\u@\\h \\W]\\$\\[\\e[0m\\]'\''/'
PS1='\[\e[1;32m\][\u@\h \W]\$\[\e[0m\]'

我发现单引号很难辨认,而且替换字符串需要转义,这使得它有点难以阅读。 - hauptmech

1

使用带有sed -f的sed脚本文件。这种替代方法也不太好看,因为它意味着要多一个文件,但至少可以避免shell转义。


不想使用外部文件。 - hauptmech
你可以在某些 sed 实现中使用 here document,例如 sed -f - <<'EOF' - tripleee

1
这样怎么样:
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

分两步完成虽然效率较低,但对大多数人来说,几微秒的时间差是无法察觉的。


我喜欢这个方向,但是sed需要转义's...这样它才能产生期望的输出。 - hauptmech
@hauptmech 我已经将其编辑为使用斜杠而不是 \。现在看起来有点难以辨认。您最好使用Python或Perl。 - Spencer Rathbun

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接