为什么空变量的 wc -l 结果为 1

lin*_*k89 2 bash

给出以下 bash 代码

grep match_nothing file.txt | wc -l
Run Code Online (Sandbox Code Playgroud)

结果0是正确的。但是下面的代码

LINES=$(grep match_nothing file.txt)
wc -l <<< "$LINES"
Run Code Online (Sandbox Code Playgroud)

将返回 1。为什么会发生这种情况以及我该如何纠正。

更新:

这个问题只是grep作为一个例子。让我困惑的是为什么将输出分配给变量会导致不同的结果。

Ed *_*ton 6

关于:

为什么会发生这种情况

Here-string 的目的是将字符串转换为工具可以作为输入读取的内容,就像读取文件一样,并且根据 POSIX,有效的文本文件始终以换行符结尾,因此here-string 构造在字符串末尾添加换行符。如果它不这样做,那么它的输出将不是有效的 POSIX 文本“文件”,因此您无法可靠地将它用作任何文本处理工具(例如 sed、awk 等)的输入。

关于:

我怎样才能做对

它已经是正确的,但如果您不想添加换行符,则使用带有 a 的命令替换printf来生成输入:

$ lines=''

$ wc -l <<< "$lines"
1

$ wc -l < <(printf '%s' "$lines")
0
Run Code Online (Sandbox Code Playgroud)

但请注意,关于各种工具如何处理它,输出不是每个 POSIX 和 YMMV 的有效文本文件,例如给定非空字符串:

$ lines='foo'
Run Code Online (Sandbox Code Playgroud)

典型的预期行为将由此处的字符串提供:

$ wc -l <<< "$lines"
1

$ while IFS= read -r var; do echo "$var"; done <<< "$lines"
foo
Run Code Online (Sandbox Code Playgroud)

使用带有 a 的命令替换printf可能不是您所期望的:

$ wc -l < <(printf '%s' "$lines")
0

$ while IFS= read -r var; do echo "$var"; done < <(printf '%s' "$lines")
$
Run Code Online (Sandbox Code Playgroud)

如果您想提供在填充变量时添加换行的输入,但在其他情况下不添加换行,那么您可以考虑类似以下内容:

$ lines=''

$ wc -l < <(printf '%s' "$lines"; (( ${#lines} )) && printf '\n')
0

$ while IFS= read -r var; do echo "$var"; done < <(printf '%s' "$lines"; (( ${#lines} )) && printf '\n')
$
Run Code Online (Sandbox Code Playgroud)

$ lines='foo'

$ wc -l < <(printf '%s' "$lines"; (( ${#lines} )) && printf '\n')
1

$ while IFS= read -r var; do echo "$var"; done < <(printf '%s' "$lines"; (( ${#lines} )) && printf '\n')
foo
Run Code Online (Sandbox Code Playgroud)