如何测试命令是否输出空字符串?
当前回答
博士TL;
if [[$(ls -A | head -c1 | wc -c) -ne 0]];然后…;fi
感谢netj if [[$(ls -A | wc -c) -ne 0]];然后…;fi
这是一个老问题,但我认为至少有两件事需要改进或至少需要澄清。
第一个问题
我看到的第一个问题是,这里提供的大多数示例根本不起作用。它们使用ls -al和ls -al命令——这两个命令都在空目录中输出非空字符串。这些例子总是报告存在文件,即使没有文件。
出于这个原因,你应该只使用ls - a -为什么有人想要使用-l开关,这意味着“使用长列表格式”,当你想要的只是测试是否有任何输出时,无论如何?
所以大部分答案都是不正确的。
第二个问题
第二个问题是,虽然有些答案很好(那些不使用ls -al或ls -al而是ls -A的答案),但它们都是这样做的:
运行命令 在RAM中缓冲它的全部输出 将输出转换为一个巨大的单行字符串 将该字符串与空字符串进行比较
我的建议是:
运行命令 计算输出中的字符,但不存储它们 或者甚至更好-使用head -c1来计算最多1个字符的数量(感谢netj在下面的评论中发布这个想法) 将这个数字与零进行比较
比如,不用:
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中不必要的存储和处理潜在的巨大数据。
答案并没有说明输出总是很小,所以需要考虑大输出的可能性。
其他回答
正如tripleee在问题评论中提到的,使用moreutils ifne(如果输入不为空)。
在这种情况下,我们想要ifne -n,它否定测试:
ls -A /tmp/empty | ifne -n command-to-run-if-empty-input
当初始命令的输出为非空时,此方法相对于许多其他答案的优点。ifne将立即开始将其写入STDOUT,而不是缓冲整个输出,然后再写入,如果初始输出生成缓慢或非常长,并且会溢出shell变量的最大长度,这是很重要的。
moreutils中有一些utils可以说应该放在coreutils中——如果你花大量时间生活在shell中,它们值得一试。
对OP特别感兴趣的可能是diempty /exists工具,在撰写本文时仍在考虑中,并且已经有一段时间了(它可能会使用bump)。
正如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
你可以把两者结合起来,就像[-n "$(ls -Al)"];然后
有时,ls可能是某个shell别名。您可能更喜欢使用$(/bin/ls -Al)。参见ls(1)和hier(7)和environ(7)和你的~/。bashrc(如果你的shell是GNU bash;我的交互式shell是zsh,定义在/etc/passwd -见passwd(5)和chsh(1))。
博士TL;
if [[$(ls -A | head -c1 | wc -c) -ne 0]];然后…;fi
感谢netj if [[$(ls -A | wc -c) -ne 0]];然后…;fi
这是一个老问题,但我认为至少有两件事需要改进或至少需要澄清。
第一个问题
我看到的第一个问题是,这里提供的大多数示例根本不起作用。它们使用ls -al和ls -al命令——这两个命令都在空目录中输出非空字符串。这些例子总是报告存在文件,即使没有文件。
出于这个原因,你应该只使用ls - a -为什么有人想要使用-l开关,这意味着“使用长列表格式”,当你想要的只是测试是否有任何输出时,无论如何?
所以大部分答案都是不正确的。
第二个问题
第二个问题是,虽然有些答案很好(那些不使用ls -al或ls -al而是ls -A的答案),但它们都是这样做的:
运行命令 在RAM中缓冲它的全部输出 将输出转换为一个巨大的单行字符串 将该字符串与空字符串进行比较
我的建议是:
运行命令 计算输出中的字符,但不存储它们 或者甚至更好-使用head -c1来计算最多1个字符的数量(感谢netj在下面的评论中发布这个想法) 将这个数字与零进行比较
比如,不用:
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中不必要的存储和处理潜在的巨大数据。
答案并没有说明输出总是很小,所以需要考虑大输出的可能性。
有时您希望保存输出(如果它是非空的),以便将其传递给另一个命令。如果是的话,你可以使用
list=`grep -l "MY_DESIRED_STRING" *.log `
if [ $? -eq 0 ]
then
/bin/rm $list
fi
这样,如果列表为空,rm命令就不会挂起。
到目前为止给出的所有答案都处理终止并输出非空字符串的命令。
大多数是在以下意义上被打破的:
它们不能正确地处理只输出换行符的命令; 从Bash≥4.4开始,如果命令输出null字节(因为他们使用命令替换),大多数将发送垃圾邮件标准错误; 大多数人将发出完整的输出流,所以会等到命令结束才回答。有些命令永远不会终止(例如,尝试,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问题。