在sed中使用特殊字符转义变量 - 注释并取消注释任意一行源代码

时间:2017-01-20 08:11:50

标签: perl awk sed escaping comments

我需要通过脚本在crontab文件中注释掉一行,因此它包含目录,空格和符号。这个特定的行存储在一个变量中,我开始混淆如何转义变量。由于线路定期更改我不想在那里逃跑。我不想在它前面简单地添加#,因为我还需要切换它并在没有#的情况下再次替换原来的行。

所以我们的目标是用#$ line(comment)替换$ line,并且可以反过来(取消注释)。

所以我有一个变量:

line="* * * hello/this/line & /still/this/line"

这是在文件file.txt中出现的一行。我需要发表评论。

首先尝试:

sed -i "s/^${line}/#${line}/" file.txt

第二次尝试:

sed -i 's|'${line}'|'"#${line}"'|g' file.txt

2 个答案:

答案 0 :(得分:1)

Perl有办法为你做引用/转义:

line=$line perl -i~ -pe '$regex = quotemeta $ENV{line}; s/^$regex/#$ENV{line}/' -- input.txt

答案 1 :(得分:1)

choroba's helpful answer使用perl显示了有效的解决方案。

sed解决方案

如果您想使用sed,则必须使用单独的sed命令才能转义$line变量值,因为 {{ 1}}具有 no 内置方式来转义字符串以在正则表达式上下文中用作文字

sed

使用BSD / macOS lineEscaped=$(sed 's/[^^]/[&]/g; s/\^/\\^/g' <<<"$line") # escape $line for use in regex sed -i "s/^$lineEscaped\$/#&/" file.txt # Note the \$ to escape the end-of-line anchor $ ,使用sed代替-i ''进行就地更新,无需备份。

相反( un -commenting):

-i

请参阅我的this answer以获取用于转义的sed -i "s/^#\($lineEscaped\)\$/\1/" file.txt 命令的解释,该命令应该适用于任何输入字符串。

另请注意变量sed$lineEscaped命令的 regex 部分中仅引用一次,而替换-string 部分简单地引用了正则表达式匹配的内容(这避免了使用不同规则再次转义变量的需要):
替换字符串中的s表示整个匹配,&表示第一个捕获组(带括号的子表达式,\1)。

为简单起见,第二个\(...\)命令使用双引号将shell变量sed的值嵌入$lineEscaped脚本中,但通常最好使用单个引用的脚本,以避免在shell解释前与最终看到的sed之间产生混淆。

例如,sed对shell和$都是特殊的,在上面的脚本中,sed正则表达式中的行结束$必须因此可以sed进行转义,以防止shell解释它 避免混淆的一种方法是有选择地将双引号shell变量引用拼接到另一个单引号脚本中:

\$

sed -i 's/^'"$lineEscaped"'$/#&/' file.txt 解决方案

awk提供文字字符串匹配,无需转义:

awk

如果您有 GNU Awk v4.1 +,则可以使用awk -v line="$line" '$0 == line { $0 = "#" $0 } 1' file.txt > $$.tmp && mv $$.tmp file.txt 进行就地更新。

相反( un -commenting):

-i inplace