如何将 POSIX sh 字符串中的所有换行符转换为“\n”

如何将 POSIX sh 字符串中的所有换行符转换为“\n”

我有一个包含换行符的字符串。我想通过用两个字符的字符串替换所有换行符来转义该字符串中的所有换行符:“\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
    

答案1

尝试awk使用:

string='x
y
'
new_string=$(
  LC_ALL=C awk -- '
    BEGIN {
      gsub("\n", "\\n", ARGV[1])
      printf "%s", ARGV[1]
    }' "$string"
)

无论如何,请注意命令替换会删除所有尾随换行符。这里没问题,因为 的输出awk不包含任何内容,但这意味着我们也可以使用 来print代替printf "%s".

sed

new_string=$(
  printf '%s\n' "$string" |
    LC_ALL=C sed '
      :1
      $ ! {
        N
        b1
      }
      s/\n/\\n/g'
)

请注意,根据 POSIX,N在最后一行使用意味着放弃模式空间并退出。 GNU仅在环境中sed时执行此操作,但在最后一行调用时仍会退出(但仍打印模式空间)。$POSIXLY_CORRECTN

我们用来LC_ALL=C避免在用户区域设置的字符映射中解码字符串时出现潜在问题。

sed是一个文本实用程序,因此它需要文本输入并生成文本输出。不为空且不以换行符结尾的内容不是文本。在这里,我们向输入添加一个换行符,并依靠命令替换来删除sed输出中添加的换行符。

另请注意,如果输入的行长度以字节为单位大于 LINE_MAX(可以低至 1024),那么它也将成为非文本,并且行为未指定。 IIRC,模式空间也不需要能够容纳超过 10 x LINE_MAX。

awk方法也有一些限制,从 ARG_MAX 开始,它在系统上将低于 10 x LINE_MAX。该限制sed也适用于printf非内置 shell(例如基于 ksh88 或 pdksh 的 shell)。

shell 变量的大小没有限制,但如果将其导出到环境中,它将针对所有执行的外部命令运行 ARG_MAX 限制。

要处理流,您需要类似的东西:

... | (cat; echo) | LC_ALL=C awk '
  {printf "%s", sep $0; sep = "\\n"}'

但请注意,输出不是文本,因此无法由 POSIX 文本实用程序处理。

相关内容