我需要通过脚本在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
答案 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