testing一个命令是否输出一个空string

我如何testing一个命令是否输出空string?

以前,问题是如何检查目录中是否有文件。 下面的代码实现了这一点,但看到更好的解决schemersp的答案 。


空输出

命令不返回值 – 他们输出它们。 您可以通过使用命令replace捕获此输出; 例如$(ls -A) 。 你可以像这样在Bash中testing一个非空string:

 if [[ $(ls -A) ]]; then echo "there are files" else echo "no files found" fi 

请注意,我使用了-A而不是-a ,因为它省略了符号的当前( . )和父( .. )目录条目。

注意:正如在注释中指出的那样,命令replace不会捕获尾随换行符 。 因此,如果命令输出换行符,则replace将不捕获任何内容,testing将返回false。 虽然不太可能,但在上面的例子中这是可能的,因为一个换行符是一个有效的文件名! 更多信息在这个答案 。


退出代码

如果你想检查命令是否成功完成,你可以检查$? ,其中包含最后一个命令的退出码(成功为零,失败为非零)。 例如:

 files=$(ls -A) if [[ $? != 0 ]]; then echo "Command failed." elif [[ $files ]]; then echo "Files found." else echo "No files found." fi 

更多信息在这里 。

TL; DR

if [[ $(ls -A | head -c1 | wc -c) -ne 0 ]]; then ...; fi

感谢netj提出了一个改进我原来的build议:
if [[ $(ls -A | wc -c) -ne 0 ]]; then ...; fi


这是一个老问题,但至less有两件事情需要改进或至less有一些澄清。

第一个问题

我看到的第一个问题是,这里提供的大多数示例都不起作用 。 他们使用ls -alls -Al命令 – 它们都在空目录中输出非空string。 这些例子总是报告, 即使没有文件,也有文件。

出于这个原因,你应该只使用ls -A – 为什么有人想要使用-l开关,这意味着“使用长列表格式”,当你想要的只是testing是否有任何输出,不pipe怎样?

所以这里的大部分答案都是不正确的。

第二个问题

第二个问题是,虽然有些答案工作正常(那些使用ls -alls -Al而是ls -A ),他们都做这样的事情:

  1. 运行一个命令
  2. 将其整个输出缓冲在RAM中
  3. 将输出转换成一个巨大的单行string
  4. 将该string与空string进行比较

我会build议做的,而不是:

  1. 运行一个命令
  2. 统计其输出中的字符而不存储它们
    • 甚至更好 – using head -c1计算最多1个字符的数量
      (感谢netj发表这个想法在下面的评论)
  3. 将该数字与零进行比较

例如,而不是:

 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的build议后再次更新:

 if [[ $(ls -A | head -c1 | wc -c) -ne 0 ]]; then echo "there are files" else echo "no files found" fi 

放弃空白

如果您正在testing的命令可能会输出一些空白string,而不是:

 | wc -c 

你可以使用:

 | tr -d ' \n\r\t ' | wc -c 

或与head -c1

 | tr -d ' \n\r\t ' | head -c1 | wc -c 

或类似的东西。

概要

  1. 首先,使用一个可行的命令。

  2. 其次,避免在RAM中不必要的存储和处理潜在的巨大数据。

答案并没有说明产出总是很小,所以也需要考虑大产出的可能性。

 if [ -z "$(ls -lA)" ]; then echo "no files found" else echo "There are files" fi 

这将运行命令和echt是否返回的输出(string)长度为零。 您可能要检查其他标志的“testing”手册页 。

在被检查的参数周围使用“”,否则空的结果会导致语法错误,因为没有第二个参数(检查)给出!

注意: ls -la总是返回...所以使用这将无法正常工作,请参阅ls手册页 。 此外,虽然这看起来方便和容易,但我认为它会轻易破裂。 编写一个小脚本/应用程序返回0或1取决于结果是更可靠!

对于那些想要一个优雅的,bash版本无关的解决scheme(实际上应该可以在其他现代shell中工作)以及那些喜欢使用单线程来执行快速任务的人。 开始了!

 ls | grep . && echo 'files found' || echo 'files not found' 

(注意作为提到的一个意见, ls -al ,实际上,只有-l-a都会返回一些东西,所以在我的回答中我使用简单的ls

Bash参考手册

6.4 Bash条件expression式

 -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 

正如Jon Lin评论的那样, ls -al将始终输出(for ... )。 你想要ls -Al避免这两个目录。

例如,你可以把命令的输出放到一个shellvariables中:

 v=$(ls -Al) 

一个更老的,不可嵌套的符号是

 v=`ls -Al` 

但我更喜欢可嵌套表示法$()

您可以testing该variables是否为空

 if [ -n "$v" ]; then echo there are files else echo no files fi 

你可以把两者结合起来,就if [ -n "$(ls -Al)" ]; then 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 

以下是针对更极端情况的解决scheme:

 if [ `command | head -c1 | wc -c` -gt 0 ]; then ...; fi 

这将工作

  • 所有Bourne炮弹
  • 如果命令输出全为零;
  • 有效的无论输出大小;

然而,

  • 一旦输出任何内容,命令或其subprocess将被终止。

我有完全相同的问题,但我正在做一个VBScript,所以这里是我的代码行,我需要知道,如果它发现了什么:crt.Screen.Send“猫myfile.txt | grep'L [0-9 ] *'“&vbcr

到目前为止给出的所有答案处理终止和输出非空string的命令。

大多数是在以下意义上被打破:

  • 他们不能正确处理只输出换行符的命令。
  • 从Bash≥4.4开始,如果命令输出空字节(因为它们使用命令replace),大多数情况下会发送垃圾邮件标准错误;
  • 大多数会淹没完整的输出stream,因此将等到命令在应答之前终止。 有些命令永远不会终止(例如, yes )。

所以要解决所有这些问题,并有效地回答以下问题,

我如何testing一个命令是否输出空string?

您可以使用:

 if read -n1 -d '' < <(command_here); then echo "Command outputs something" else echo "Command doesn't output anything" fi 

您也可以添加一些超时,以testing命令是否在给定的时间内使用read-t选项输出非空string。 例如,2.5秒超时:

 if read -t2.5 -n1 -d '' < <(command_here); then echo "Command outputs something" else echo "Command doesn't output anything" fi 

备注。 如果你认为你需要确定一个命令是否输出一个非空string,你很可能有一个XY问题。