如何在Bash中将换行符打印为\n?

10
基本上,我想实现与 echo -e 相反的功能。
我有一个变量存储了一个命令的输出,但我想将换行符打印为 \n。

1
该变量是否包含字面意义上的\n,或者你想将实际换行符转换成\n - Biffen
@Biffen 变量包含实际的换行符。 - BubuIIC
1
严格来说,echo -e 的反向操作也涉及将其他控制字符转换为它们的转义序列,例如将制表符转换为 '\t'。但根据被接受的答案,处理换行符在这种情况下已经足够了。 - mklement0
4个回答

10
这是我的解决方案:
sed 's/$/\\n/' | tr -d '\n'

这比awk的解决方案更简单。我会接受这个。 - BubuIIC
1
+1 - 聪明的;就像awk解决方案一样,你总是会得到一个尾随的文字\n序列;但与awk不同的是,抑制它非常简单:sed '$! s/$/\\n/' - mklement0

8

如果你的输入已经存在于一个(Bash)shell变量中,比如$varWithNewlines

echo "${varWithNewlines//$'\n'/\\n}"

这段代码简单地使用Bash的参数扩展功能,将所有换行符($'\n')替换为字面上的'\n'


如果你的输入来自于一个文件,请使用AWK:

awk -v ORS='\\n' 1

实际运用时,带注样例:

# Sample input with actual newlines created with ANSI C quoting ($'...'),
# which turns `\n` literals into actual newlines.
varWithNewlines=$'line 1\nline 2\nline 3'

# Translate newlines to '\n' literals.
# Note the use of `printf %s` to avoid adding an additional newline.
# By contrast, a here-string - <<<"$varWithNewlines" _always appends a newline_.
printf %s "$varWithNewlines" | awk -v ORS='\\n' 1
  • awk 逐行读取输入
  • 通过将输出记录分隔符设置为文字'\n'(使用附加的\转义,以免awk将其解释为转义序列),输入行将以该分隔符输出
  • 1只是{print}的简写,即所有输入行都会被打印出来,并以ORS终止。

注意:即使您的输入没有以换行符结尾,输出也总是以文字'\n'结尾。

这是因为AWK使用ORS终止每一行输出,无论输入行是否以换行符(在FS中指定的分隔符)结束。


以下是如何从输出中无条件地删除末尾的文字'\n'

# Translate newlines to '\n' literals and capture in variable.
varEncoded=$(printf %s "$varWithNewlines" | awk -v ORS='\\n' 1)

# Strip terminating '\n' literal from the variable value
# using Bash parameter expansion.
echo "${varEncoded%\\n}"

相比之下,如果你想要使终止文字'\n'的存在取决于输入是否以换行符结尾,则需要更多的工作。

# Translate newlines to '\n' literals and capture in variable.
varEncoded=$(printf %s "$varWithNewlines" | awk -v ORS='\\n' 1)

# If the input does not end with a newline, strip the terminating '\n' literal.
if [[ $varWithNewlines != *$'\n' ]]; then
  # Strip terminating '\n' literal from the variable value
  # using Bash parameter expansion.
  echo "${varEncoded%\\n}"
else
  echo "$varEncoded"
fi

1
一个Bash解决方案。
x=$'abcd\ne fg\nghi'
printf "%s\n" "$x"
abcd
e fg
ghi
y=$(IFS=$'\n'; set -f; printf '%s\\n' $x)
y=${y%??}
printf "%s\n" "$y"
abcd\ne fg\nghi

不幸的是,对 $x 的未引用引用使其值受到路径名扩展的影响,因此输入行(例如 *)会产生意外结果 - 您可以在子shell开头包含 set -f; 来抑制路径名扩展。 - mklement0
@mklement0,确实如此。已修复。 - iruvar

1
您可以使用 printf "%q"
eol=$'\n'
printf "%q\n" "$eol"
$'\n'

有没有不需要在字符串周围引入 $'' 的方法? - BubuIIC
仅作澄清:根据输入,printf %q 将输出一个_整体_ 未引用 的字符串,并使用\转义_shell元字符,或者 - 如果存在诸如换行符和_其他字符_(例如制表符)的控制字符,则输出一个 ANSI C-引用字符串($'...'),就像答案中所示。printf %的目的是获取一个字符串的表示形式,您可以安全地将其用作命令参数或源代码中的变量值 - 即,输出通常不是字面上使用的。 - mklement0

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接