我想用两个转义命令(ESC+E 和 ESC+F)将 Fortran 注释括起来。这意味着检测以 开头直到行尾的注释!
,并以 为前缀ESC+E
和后缀ESC+F
。
第一次尝试
$ echo "test line ! Enclose this in ESC commands" | sed 's/\(!.*\)/\033E\1\033F/'
test line 033E! Enclose this in ESC commands033F
ESC 字符本身没有生成,而是得到 033。
第二次尝试
$ echo "test line ! Enclose this in ESC commands" | sed $'s/\(!.*\)/\033E\1\033F/'
sh: Syntax error: Bad escape sequence
系统详情
答案1
失败的尝试
这里有两个层次需要理解。首先 shell 处理输入,然后将其传递给 Sed。
-
sed 's/\(!.*\)/\033E\1\033F/'
单引号保留内部所有字符的字面含义,因此在第一次尝试中,Sed 获取引号之间的所有字符。
但是,它失败了,因为 Sed 不理解
\033
ASCII 八进制 033 (ESC)。您可能已经假设了这一点,但是sed手册对此什么也没说。 -
sed $'s/\(!.*\)/\033E\1\033F/'
该
$'...'
构造是 ANSI C 引用。这是一个好主意,因为 shell 随后会转换$'\033'
为 ESC 字符。然而,FreeBSD 的 Sh 手册 包含有效反斜杠序列的列表,然后清楚地说任何其他以反斜杠开头的字符串都是错误的。
是否列出
\(
或\)
?不,因此出现错误消息。并且\1
,应该发送到 Sed,也会被解释为 ASCII 八进制 001 (SOH),这绝对不是您想要的。
解决方案
请注意,对于下面的选项 1 和 2,\033
也可以简单地写为\e
。
只有 ANSI 引用转义
\033
序列,将其余部分保留在正常引用中:sed 's/\(!.*\)/'$'\033''E\1'$'\033''F/' ^^^^^^^^^^^^ ^^^^^ ^^^^ ^^^^^^^ ^^^^^^^
不需要捕获组来捕获整个匹配的字符串。这是
&
默认的。sed $'s/!.*/\033E&\033F/'
(符合 POSIX)使用 Printf 生成 ESC。选择其中一项
esc=$(printf '\033'); sed "s/!.*/${esc}E&${esc}F/" sed "s/!.*/$(printf '\033')E&$(printf '\033')F/"
(符合 POSIX 标准)awk。
awk '{sub(/!.*/, "\033E&\033F"); print}'