Sed内联动态替换表达式抛出:无与伦比的'|'

时间:2018-05-05 12:35:35

标签: bash sed sh substitution

我有一个缩小的js文件。包含特殊字符,如管道,破折号,斜线等。

另外,我还有另一个包含评论的HTML文件:

<!--#MY_SNIPPET#-->

我正在尝试使用sed来注入我的js文件并将其替换为上面的注释。

my.js

的示例
<script>whatever|@</script><script>-my</script>

我现在正在做:

VARIABLE=$(cat my.js)
sed -i "s|<!--#MY_SNIPPET#-->|${VARIABLE}|" index.html

但我得到了sed: unmatched '|'

我认为sed正在尝试评估字符串,这就是失败的原因,但我想知道是否有一种简单的方法可以使用sed,因为我想避免使用Perl或其他任何内容。

分隔符无关紧要,它总是会抛出同样的错误。

3 个答案:

答案 0 :(得分:1)

在某些情况下,构建动态sed表达式即使不是不可能也很困难。你的问题有两个:双引号里面(或外面)的感叹号!有特殊用途,例如:在控制台上试试这些

!!这个重复最后执行的命令(小心!:D)
echo "!$"回显上一个命令的最后一个参数
!5087在bash历史记录中执行命令5087。

另一个 big 问题是你的变量几乎可能包含任何字符,所以你不能确定那里没有sed表达式分隔符,对于你的特定例子,这是有效的

sed -ri "s~<[!]--#MY_SNIPPET#-->~${var}~" test.html

PS:分隔符必须是单字节字符:(

sed -ri "sЖ<[!]--#MY_SNIPPET#-->Ж${var}Ж" test.html

sed: -e expression #1, char 2: delimiter character is not a single-byte character

另一个扭曲的选项可能是在VARIABLE中替换所选的分隔符,然后将其恢复

sed -ri "s@<[!]--#MY_SNIPPET#-->@$(echo "${var}" | tr '@' 'ж')@" test.html
cat test.html | tr 'ж' '@' > test2.html
mv test2.html test.html

答案 1 :(得分:0)

永远不要将整个脚本用双引号括起来,然后将整个脚本暴露给shell进行解释,这可能会产生像你现在体验到的无法预料的后果。如果/当您需要shell执行特定任务时,仅将脚本打开到shell,例如在您的情况下扩展变量。用单引号括起脚本,而不是加倍。

所以,不要写:

sed -i "s|<!--#MY_SNIPPET#-->|${VARIABLE}|" index.html

改为写这个:

sed -i 's|<!--#MY_SNIPPET#-->|'"${VARIABLE}"'|' index.html

现在您的下一个问题是VARIABLE包含您在脚本|中使用的分隔符。要解决此问题,只需更改脚本中的分隔符,例如从|~

sed -i 's~<!--#MY_SNIPPET#-->~'"${VARIABLE}"'~' file

那将&#34;工作&#34;只要VARIABLE不包含任何~&\<number>字符/字符串。对于更强大的解决方案,您需要执行它在Is it possible to escape regex metacharacters reliably with sed上显示的内容或切换到awk,因为awk可以在文字字符串上操作,而sed则不能。

答案 2 :(得分:0)

无论您使用s///命令的分隔符,您的变量可能包含该字符的风险。最好的做法是在变量中转义任何这样的字符:

$ var='<script>whatever|@</script><script>-my</script>'
$ echo "${var//|/\\|}"
<script>whatever\|@</script><script>-my</script>
# ..............^^

然后

sed -i "s|<!--#MY_SNIPPET#-->|${var//|/\\|}|" index.html