Bash:从输出中去除尾随的换行符

325

在Bash中执行命令(具体来说是wc -l < log.txt),输出会包含一个换行符。如何去掉它?


9个回答

431

如果你期望的输出是单行文本,你可以简单地将所有换行符从输出中移除。通常可以使用tr工具或者Perl进行处理:

wc -l < log.txt | tr -d '\n'

wc -l < log.txt | perl -pe 'chomp'

您还可以使用命令替换来删除尾随的换行符:

echo -n "$(wc -l < log.txt)"

printf "%s" "$(wc -l < log.txt)"

如果你的预期输出可能包含多行,那么你需要做出另一个决定:

如果你想要从文件末尾移除多个换行符,再次使用 cmd 替换:

printf "%s" "$(< log.txt)"

如果你想严格地从文件中删除最后一个换行符,请使用Perl:

perl -pe 'chomp if eof' log.txt

请注意,如果您确定要删除尾随的换行符,请使用GNU核心实用程序中的head选择除最后一个字节之外的所有内容。这应该非常快:

head -c -1 log.txt

此外,为了完整起见,您可以使用cat和“show-all”标志-A快速检查文件中的换行符(或其他特殊字符)的位置。美元符号表示每行的结尾:

cat -A log.txt

这会从输出中删除所有的换行符,而不仅仅是标题所要求的尾随换行符。 - Cody A. Ray
6
如果将短选项替换为长选项,这会更好。长选项不仅具有功能,还可以起到教育作用,例如 tr --delete '\n' - Elijah Lynn
3
我还执行了 | tr -d '\r' - AlikElzin-kilaka
值得注意的是,如果文件非常大,使用cmd替换解决方案可能会导致行过长。 - phk
2
我的赞同是给 head -c ... 版本的 -- 因为现在我可以将命令输入到剪贴板并保留格式,但不包括最后的 \n。例如:alias clip="head -c -1 | xclip -selection clipboard",效果还不错。现在你可以将 ls -l | clip 命令输出到 X-Server 的 clipboard 中,而不需要终止符 \n。因此...我可以将其粘贴到我的下一个命令中,并达到完美的效果。非常感谢! - will
显示剩余2条评论

96

一种方法:

wc -l < log.txt | xargs echo -n

26
更好的写法:echo -n \wc -l log.txt`` - Satya
11
在命令执行时使用反引号比使用管道更好的原因是什么? - Matthew Schinckel
4
这些命令不仅会删除末尾的换行符,还会将连续的空格(根据IFS定义)压缩为一个空格。例如: echo "a b" | xargs echo -n; echo -n $(echo "a b")。这可能对使用情况有影响,也可能没有。 - musiphil
16
如果输出以“-e”开头,那么它将被解释为“echo”的选项。使用“printf '%s'”始终更安全。 - musiphil
1
在我的系统上,xargs非常慢(我怀疑其他系统也是如此),因此使用printf '%s' $(wc -l log.txt)可能会更快,因为printf通常是内置的(而且没有信息重定向)。永远不要使用反引号,它们已经在新的POSIX版本中被弃用,并且有许多缺点。 - yyny

27
如果您想要移除只有最后一个换行符,可以通过管道使用以下命令:
sed -z '$ s/\n$//'
sed使用-z设置为NUL作为分隔符时,它不会在流的末尾添加\0。但是,为了创建一个POSIX文本文件(定义以\n结尾),它将始终在没有-z的情况下输出最后一个\n
例如:
$ { echo foo; echo bar; } | sed -z '$ s/\n$//'; echo tender
foo
bartender

为了证明没有添加NUL

$ { echo foo; echo bar; } | sed -z '$ s/\n$//' | xxd
00000000: 666f 6f0a 6261 72                        foo.bar

要删除多个末尾换行符,请使用以下管道:

sed -Ez '$ s/\n+$//'

9
我认为这是GNU扩展,Mac的sed不提供-z选项。 - Spidey
1
你可以在Mac上安装GNU版本的sed,名为gsed,并使用它,方法是按照这里所说的做 - Brad Parks
1
有人能解释一下 sed 表达式开头的 $ 是干什么用的吗? - what the
如果我理解正确,$ 是用于选择最后一行,从而避免在所有行上执行 sed 命令。请参阅 https://www.gnu.org/software/sed/manual/sed.html#Numeric-Addresses。 - dwettstein

24

Bash变量替换中也有直接支持删除空格的功能:

testvar=$(wc -l < log.txt)
trailing_space_removed=${testvar%%[[:space:]]}
leading_space_removed=${testvar##[[:space:]]}

4
您可以使用trailing_linebreak_removed=${testvar%?},它可以去除变量末尾的换行符。请注意,此命令将从原始变量中删除最后一个字符并将其存储在新变量 trailing_linebreak_removed 中。 - PurplProto
1
请注意,如果您正在使用命令替换,则无需执行任何操作来删除尾随换行符。Bash已经作为命令替换的一部分执行了该操作:https://www.gnu.org/software/bash/manual/html_node/Command-Substitution.html - Michael Burr

14

如果你想在Bash中输出任何内容但不带换行符,你可以使用-n开关进行echo操作。

如果你已经将内容存储在变量中,那么请使用裁剪了尾换行符的echo命令来输出变量内容:

$ testvar=$(wc -l < log.txt)
$ echo -n $testvar

或者你可以在一行中完成它:

$ echo -n $(wc -l < log.txt)

4
该变量从技术角度来说是不必要的。echo -n $(wc -l < log.txt) 可以达到同样的效果。 - chepner

11

printf 已经为您裁剪了末尾的换行符:

$ printf '%s' $(wc -l < log.txt)

详情:

  • printf会在%s字符串占位符的位置上打印您的内容。
  • 如果您不告诉它要打印一个换行符(%s\n),它就不会打印。

11
如果您在命令周围加上双引号,例如 "$(command)",则内部的换行符将被保留,只有尾部换行符将被删除。在这里,Shell负责所有工作,printf只是将命令替换的结果输出到标准输出流的一种方式。 - Brent Bradburn
3
并不是printf在这里去掉了换行符,而是shell使用$( )结构将其去除。 这是证明:printf "%s" "$(perl -e 'print "\n"')" - Flimm
值得注意的是,生成的命令行可能会变得太长。 - phk
这是@nobar的建议提供的方便解决方案:$ printf '%s' "$(wc -l < log.txt)" - Ilias Karim

10

如果你将其输出赋值给一个变量,bash 会自动去除空格:

linecount=`wc -l < log.txt`

13
确切来说,尾随换行符被剥离了。移除它们的是命令替换,而不是变量赋值。 - chepner
3
我在Cygwin的bash中看到当使用$(cmd /c echo %VAR%)时,尾随的空格未被删除。在这种情况下,我不得不使用${var%%[[:space:]]}。 - Andrey Taranov
1
注意:它不是变量赋值,而是表达式扩展会删除换行符。 - Ciro Santilli OurBigBook.com

9

这只是为了方便我个人参考而添加的 ^_^

您还可以使用bash扩展魔法从输出中删除换行符

VAR=$'helloworld\n'

CLEANED="${VAR%$'\n'}"

echo "${CLEANED}"

2

使用 Awk:

awk -v ORS="" '1' log.txt 

说明:

  1. -v指定ORS的值
  2. ORS被设置为空白。这将用""替换新行(输入记录分隔符)。

1
-1(虽然我实际上没有按下它的按钮,因为我只能更改一次)。这将删除所有换行符,而不仅仅是任何前导或尾随的换行符。 - Melab

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