sed分隔符
今天在看acmeair
的bash脚本的时候,发现里面有这么一行指令:
sed "s#IMAGE_NAME#${IMAGENAME}#g" ${YAML_FILE} > temp.yaml
当时想了一下,感觉那里不对劲:根据网上的教程来看的话,sed
的s
命令的用法不是类似于'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'
附录:对于非s
的sed
指令,仍然可以通过\*...*
的方式,使用任意自定义的字符作为正则表达式的分隔符。