今天在看acmeair的bash脚本的时候,发现里面有这么一行指令:

sed "s#IMAGE_NAME#${IMAGENAME}#g" ${YAML_FILE} > temp.yaml

当时想了一下,感觉那里不对劲:根据网上的教程来看的话,seds命令的用法不是类似于's/regexp/repl/g'这种格式吗?

然后仔细一想,既然能发布出来的代码,又是来自可信平台(IBM Cloud),肯定是有其原因的,或者说,至少是可以运行的。然后就动手尝试了一下:

echo '1 2' | sed -e 's/ / ^ /g'     #1
echo '1 2' | sed -e 's# # ^ #g'     #2
echo '1 2' | sed -e 's@ @ ^ @g'     #3
echo '1 2' | sed -e 's\ \ ^ \g'     #4
echo '1 2' | sed -e 's啊 啊 ^ 啊g'   #5

首先显而易见的,1是肯定可行的,可以将1 2这个字符串替换为1 ^ 2。意料之外的是,2-4全部可行,都能够正确地完成替换工作。5属于脑洞大开的想法。在发现前面1-4都能够使用任意单字符作为分隔符的话,那么中文字符可以完成相同的功能吗?

答案是否定的。sed给出了如下的错误信息:

sed: -e 表达式 #1, 字符 2: delimiter character is not a single-byte character↵
sed: -e expression #1, char 13: unknown option to `s'

其中第一行是在中文环境下的报错信息,第二行是英文环境。可以看到,在常见的环境下,都是不支持将多字节字符作为分隔符的。毕竟在计算机行业中,非英文语言体系的字符基本都可以视作“异端”,往往不能享受到英文字符的“优待”,需要使用一个以上字节进行信息的储存,所以对于只能使用单字节字符作为分隔符的sed来说自然会产生错误。

(思考题:那为何可以使用sed替换中文文本?) (答案是,只要sed将脚本序列和输入的数据流都视为单字节字符流,就可以使用字符序列替换的方法完成任务了)

实际上,在咕果上,能找到和sed分隔符相关的资料少之又少;有人在Unix论坛上发问了,虽然问题最终由作者自己看书解决,但是他并未分享自己看的是哪本书;StackOverflow上还有老哥说这就是注释,根本不能用的,等等。

直到后来看到了这个:https://backreference.org/2010/02/20/using-different-delimiters-in-sed/

博主说了这么一句:

It's a not-so-known fact that sed can use any character as separator for the "s" command.

真是not-so-known,网络上都没什么热门资料阐述这一点的= =

于是问题最终解决:

sed "s#IMAGE_NAME#${IMAGENAME}#g" ${YAML_FILE} > temp.yaml

等价于

sed "s/IMAGE_NAME/${IMAGENAME}/g" ${YAML_FILE} > temp.yaml

顺便给出上面使用的样例的升级版:(工作必备,除了你没人看得懂,专家职称、升职加薪预定

echo '1 2' | sed -e 's \  \ ^\  g'

附录:对于非ssed指令,仍然可以通过\*...*的方式,使用任意自定义的字符作为正则表达式的分隔符。

标签: none

添加新评论