我有一个包含换行符的字符串。我想通过用两个字符的字符串替换所有换行符来转义该字符串中的所有换行符:“\n”。我怎样才能在 POSIX sh 中做到这一点?
这是目标:
$ printf 'a\nb\nc\nd' | escape_newlines | od -a
0000000 a \ n b \ n c \ n d
141 134 156 142 134 156 143 134 156 144
0000012
我该如何定义escape_newlines
?
我尝试过的方法:
tr
— 问题:无法将单个字符转换为多个字符。awk 'BEGIN{ORS="\\n"} {print}'
— 问题:即使字符串不以换行符结尾,也始终在字符串末尾插入两个字符的字符串“\n”。例子:$ printf 'hi\n' | awk 'BEGIN{ORS="\\n"} {print}' | od -ab 0000000 h i \ n 150 151 134 156 0000004 $ printf 'hi' | awk 'BEGIN{ORS="\\n"} {print}' | od -ab 0000000 h i \ n 150 151 134 156 0000004
sed -e ':a' -e 'N' -e '$!ba' -e 's/\n/\\n/g'
— 问题:如果字符串末尾有换行符,则不会被转换。例子:$ printf 'h\ni' | sed -e ':a' -e 'N' -e '$!ba' -e 's/\n/\\n/g' | od -ab 0000000 h \ n i 150 134 156 151 0000004 $ printf 'h\ni\n' | sed -e ':a' -e 'N' -e '$!ba' -e 's/\n/\\n/g' | od -ab 0000000 h \ n i nl 150 134 156 151 012 0000005
尝试
awk
使用:无论如何,请注意命令替换会删除所有尾随换行符。这里没问题,因为 的输出
awk
不包含任何内容,但这意味着我们也可以使用print
来代替printf "%s"
.和
sed
:请注意,根据 POSIX,
N
在最后一行使用意味着放弃模式空间并退出。GNU仅在环境中sed
时执行此操作,但在最后一行调用时仍会退出(但仍打印模式空间)。$POSIXLY_CORRECT
N
我们用来
LC_ALL=C
避免在用户区域设置的字符映射中解码字符串时出现潜在问题。sed
是一个文本实用程序,因此它需要文本输入并生成文本输出。不为空且不以换行符结尾的内容不是文本。在这里,我们向输入添加一个换行符,并依靠命令替换来删除sed
输出中添加的换行符。另请注意,如果输入的行长度以字节为单位大于 LINE_MAX(可以低至 1024),那么它也将成为非文本,并且行为未指定。IIRC,模式空间也不需要能够容纳超过 10 x LINE_MAX。
该
awk
方法也有一些限制,从 ARG_MAX 开始,它在系统上将低于 10 x LINE_MAX。There's no limit to the size of a shell variable though if it's exported to the environment, it will run against the ARG_MAX limit for all the external commands that are executed.
To process a stream, you'd need something like:
Though beware that output is not text so cannot be processed by a POSIX text utility.