为什么sed在linux上提供“无效内容”错误但在mac上没有

时间:2017-01-25 05:54:17

标签: regex linux bash macos sed

我在sed脚本中替换了以下bash扩展正则表达式:

sed -i.bak -E 's~^[[:blank:]]*\\iftoggle{[[:alnum:]_]+}{\\input{([[:alnum:]_\/]+)}}{}~\\input{\1}~' file.txt

应该替换像

这样的字符串
\iftoggle{xx_yy}{\input{xx_yy/zz}}{}

\input{xx_yy/zz}

file.txt内。

这在OS X本地工作得很好,但脚本需要是POSIX。具体来说,它在我的远程Travis CI版本(使用Linux)上失败。虽然sed -E没有记录GNU sed,但它的行为与sed -r类似,似乎工作正常,允许带有扩展正则表达式的sed的POSIX版本。

给出的错误是:

sed: -e expression #1, char 81: Invalid content of \{\}

我也不确定错误从何处开始计算字符,是否是行的开头,还是仅包含在引号(表达式)中的部分?

2 个答案:

答案 0 :(得分:3)

这里你不需要ERE。使用BRE:

sed i.bak 's~^[[:blank:]]*\\iftoggle{[[:alnum:]_][[:alnum:]_]*}{\\input{\([[:alnum:]_\/][[:alnum:]_\/]*\)}}{}~\\input{\1}~' file.txt

{不需要在此处进行转义,(即可。

由于+不属于BRE,您可以将[[:alnum:]_]+替换为[[:alnum:]_][[:alnum:]_]*[[:alnum:]_]\{1,\}

作为旁注,\+可以与BRE中的GNU sed一起使用,但要记住它不是可移植的,它是GNU扩展。

答案 1 :(得分:1)

  

这不是直接回答sed的问题,而是在perl命令行正则表达式搜索和替换中提供了另一种更简单的方法。

perl -p -e 's|\iftoggle\{(\w+)\}\{\\input\{(\w+)/(\w+)\}\}\{\}|\input\{\2/\3\}|g' file
\input{xx_yy/zz}

将字词分隔符用作|\w+以匹配[[:alnum:]]个字符。

对于就地替换,请使用与-i

类似的sed标记
perl -p -i.bak -e 's|\iftoggle\{(\w+)\}\{\\input\{(\w+)/(\w+)\}\}\{\}|\input\{\2/\3\}|g' file

关于Word-characters(\w) in perl POSIX个字符类页面,

  

单词字符

     

A \ w匹配单个字母数字字符(字母字符或十进制数字);或连接标点字符,例如下划线(“_”);或者是一个附加在其中一个上面的“标记”字符(如某种口音)。它与整个单词不匹配。要匹配整个单词,请使用\ w +。这与匹配英文单词不同,但在ASCII范围内,它与Perl标识符字符串相同。

对于输入 - 在input内有多个文件夹,例如

cat file
\iftoggle{xx_yy}{\input{xx_yy/zz_yy_zz_kk/dude_hjgk}}{}

perl -p -e 's|\iftoggle\{(\w+)\}\{\\input\{(\w+)/(\w+)/(\w+)\}\}\{\}|\input\{\2/\3/\4\}|g' file
\input{xx_yy/zz_yy_zz_kk/dude_hjgk}

只需插入和播放所需的群组即可。