如何测试命令是否输出空字符串?
ifne
为此提供了实用程序。joeyh.name/code/moreutils
如何测试命令是否输出空字符串?
ifne
为此提供了实用程序。joeyh.name/code/moreutils
Answers:
以前,该问题询问如何检查目录中是否有文件。以下代码可以实现这一点,但是请参见rsp的答案以获得更好的解决方案。
命令不返回值,而是输出它们。您可以使用命令替换捕获此输出;例如$(ls -A)
。您可以像这样在Bash中测试非空字符串:
if [[ $(ls -A) ]]; then
echo "there are files"
else
echo "no files found"
fi
请注意,我使用-A
而不是-a
,因为它省略了符号当前(.
)和父(..
)目录条目。
注意:如注释中所指出,命令替换不会捕获结尾的换行符。因此,如果命令仅输出换行符,则替换将不捕获任何内容,并且测试将返回false。虽然不太可能,但这在上面的示例中是可能的,因为单个换行符是有效的文件名!有关此答案的更多信息。
如果要检查命令是否成功完成,可以检查$?
,其中包含最后一个命令的退出代码(成功则为零,失败则为非零)。例如:
files=$(ls -A)
if [[ $? != 0 ]]; then
echo "Command failed."
elif [[ $files ]]; then
echo "Files found."
else
echo "No files found."
fi
更多信息在这里。
if [[ $(ls -A | head -c1 | wc -c) -ne 0 ]]; then ...; fi
感谢netj
提出改善我的原著的建议:if [[ $(ls -A | wc -c) -ne 0 ]]; then ...; fi
这是一个老问题,但我认为至少有两件事需要改进或至少需要澄清。
我看到的第一个问题是这里提供的大多数例子根本不起作用。它们使用ls -al
和ls -Al
命令-两者都在空目录中输出非空字符串。这些示例始终报告即使没有文件,也有文件。
出于这个原因,您应该只使用ls -A
-为什么-l
当您只想测试是否有任何输出时,为什么有人要使用表示“使用长列表格式” 的开关?
因此,这里的大多数答案都是错误的。
第二个问题是,尽管某些答案很好用(那些不使用ls -al
或ls -Al
而是使用的答案ls -A
),但它们都可以执行以下操作:
我建议做的是:
using head -c1
因此,例如,代替:
if [[ $(ls -A) ]]
我会用:
if [[ $(ls -A | wc -c) -ne 0 ]]
# or:
if [[ $(ls -A | head -c1 | wc -c) -ne 0 ]]
代替:
if [ -z "$(ls -lA)" ]
我会用:
if [ $(ls -lA | wc -c) -eq 0 ]
# or:
if [ $(ls -lA | head -c1 | wc -c) -eq 0 ]
等等。
对于较小的输出,这可能不是问题,但是对于较大的输出,差异可能是很大的:
$ time [ -z "$(seq 1 10000000)" ]
real 0m2.703s
user 0m2.485s
sys 0m0.347s
将其与:
$ time [ $(seq 1 10000000 | wc -c) -eq 0 ]
real 0m0.128s
user 0m0.081s
sys 0m0.105s
甚至更好:
$ time [ $(seq 1 10000000 | head -c1 | wc -c) -eq 0 ]
real 0m0.004s
user 0m0.000s
sys 0m0.007s
更新了Will Vousden的答案示例:
if [[ $(ls -A | wc -c) -ne 0 ]]; then
echo "there are files"
else
echo "no files found"
fi
在netj建议后再次更新:
if [[ $(ls -A | head -c1 | wc -c) -ne 0 ]]; then
echo "there are files"
else
echo "no files found"
fi
jakeonfire的附加更新:
grep
如果没有匹配项,将退出并失败。我们可以利用它来简化语法:
if ls -A | head -c1 | grep -E '.'; then
echo "there are files"
fi
if ! ls -A | head -c1 | grep -E '.'; then
echo "no files found"
fi
如果您要测试的命令可以输出一些空白,而您希望将其视为空字符串,请使用:
| wc -c
您可以使用:
| tr -d ' \n\r\t ' | wc -c
或搭配head -c1
:
| tr -d ' \n\r\t ' | head -c1 | wc -c
或类似的东西。
首先,用命令的作品。
其次,避免不必要的存储在RAM中和处理潜在的巨大数据。
答案并没有说明输出总是很小,因此也需要考虑产生大输出的可能性。
[[ $(... | head -c | wc -c) -gt 0 ]]
还是[[ -n $(... | head -c1) ]]
更好,因为wc -c
必须消耗命令的整个输出。
if [ -z "$(ls -lA)" ]; then
echo "no files found"
else
echo "There are files"
fi
这将运行命令并检查返回的输出(字符串)的长度是否为零。您可能需要检查“测试”手册页中是否有其他标志。
在要检查的参数周围使用“”,否则空结果将导致语法错误,因为没有给定第二个参数(要检查)!
注意:ls -la
总是返回.
,..
因此使用它将不起作用,请参见ls手册页。此外,尽管这看起来很方便且容易,但我想它会很容易损坏。编写一个小脚本/应用程序,根据结果返回0或1更加可靠!
$(
而不是反引号,因为$(
嵌套效果更好
对于那些想要一个优雅的,独立于bash版本的解决方案的人(实际上应该在其他现代shell中工作)以及那些喜欢使用单行代码完成快速任务的人。开始了!
ls | grep . && echo 'files found' || echo 'files not found'
(请注意,作为提及的评论之一,ls -al
实际上,正义-l
和正义-a
都会返回一些东西,因此在我的回答中,我使用简单ls
grep -q ^
改用,换行符也将匹配,并且grep不会在标准输出中显示任何内容。此外,它将在收到任何输入后立即退出,而不是等待其输入流结束。
ls -A
,如果你想包括点文件(或目录)
-z string
True if the length of string is zero.
-n string
string
True if the length of string is non-zero.
您可以使用简写版本:
if [[ $(ls -A) ]]; then
echo "there are files"
else
echo "no files found"
fi
string
的同义词-n string
。
正如乔恩·林(Jon Lin)所说,ls -al
将始终输出(for .
和..
)。您要ls -Al
避免这两个目录。
例如,您可以将命令的输出放入shell变量中:
v=$(ls -Al)
较旧的非嵌套符号为
v=`ls -Al`
但我更喜欢可嵌套的表示法$(
...)
您可以测试该变量是否为非空
if [ -n "$v" ]; then
echo there are files
else
echo no files
fi
您可以将两者结合为 if [ -n "$(ls -Al)" ]; then
我猜想您想要ls -al
命令的输出,因此在bash中,您将拥有类似以下内容的东西:
LS=`ls -la`
if [ -n "$LS" ]; then
echo "there are files"
else
echo "no files found"
fi
ls
永远不会执行。您仅检查变量 的扩展是否LS
为非空。
-a
交换机将不会返回任何内容(即是否有文件或不将返回的内容),因为总有隐性.
和..
目录存在。
鉴于到目前为止处理所有的答案是命令终止并输出一个非空字符串。
大多数在以下方面被打破:
yes
)。因此,要解决所有这些问题并有效回答以下问题,
如何测试命令是否输出空字符串?
您可以使用:
if read -n1 -d '' < <(command_here); then
echo "Command outputs something"
else
echo "Command doesn't output anything"
fi
您还可以使用read
的-t
选项添加一些超时,以测试命令在给定时间内是否输出非空字符串。例如,对于2.5秒的超时:
if read -t2.5 -n1 -d '' < <(command_here); then
echo "Command outputs something"
else
echo "Command doesn't output anything"
fi
备注。如果您认为需要确定命令是否输出非空字符串,则很可能会遇到XY问题。
seq 1 10000000
,seq 1 20
,和printf""
)。这种读取方法唯一不能赢得的比赛是-z "$(command)"
空输入的方法。即使那样,它只会损失大约10-15%。他们似乎收支平衡seq 1 10
。无论如何,随着输入大小的增加,该-z "$(command)"
方法变得如此缓慢,以至于我会避免将其用于任何可变大小的输入。
这是一种替代方法,该方法将某些命令的std-out和std-err写入一个临时文件,然后检查该文件是否为空。这种方法的优点是它捕获了两个输出,并且不使用子外壳或管道。后面这两个方面很重要,因为它们可能会干扰捕获bash出口的操作(例如,此处)
tmpfile=$(mktemp)
some-command &> "$tmpfile"
if [[ $? != 0 ]]; then
echo "Command failed"
elif [[ -s "$tmpfile" ]]; then
echo "Command generated output"
else
echo "Command has no output"
fi
rm -f "$tmpfile"