测试命令是否输出空字符串

bar*_*arp 206 bash shell

如何测试命令是否输出空字符串?

Wil*_*den 267

以前,问题是如何检查目录中是否有文件.以下代码实现了这一点,但请参阅rsp的答案以获得更好的解决方案.


空输出

命令不返回值 - 它们输出它们.您可以使用命令替换来捕获此输出; 例如$(ls -A).您可以在Bash中测试非空字符串,如下所示:

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

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

注意:正如注释中所指出的,命令替换不会捕获尾随换行符.因此,如果命令输出换行符,则替换将不捕获任何内容,并且测试将返回false.尽管不太可能,但在上面的示例中这是可能的,因为单个换行符是有效的文件名!本答案中的更多信息.


退出代码

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

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

更多信息在这里.

  • 对于仅输出换行符的命令,此方法为false. (4认同)
  • 你[可以省略](http://stackoverflow.com/a/23532711/3075942)`-n`,所以它只是`if [[$(ls -A)]]; then` (3认同)

rsp*_*rsp 81

TL; DR

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

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


这是一个老问题,但我发现至少有两件事情需要改进或至少有一些澄清.

第一个问题

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

出于这个原因你应该只使用ls -A- 为什么有人想要使用-l开关,这意味着"使用长列表格式"当你想要的只是测试是否有任何输出,无论如何?

所以这里的大多数答案都是不正确的.

第二个问题

第二个问题是,虽然一些答案做工精细(那些使用ls -alls -Al,但ls -A代替)他们都做这样的事情:

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

我建议做的是:

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

例如,而不是:

if [[ $(ls -A) ]]
Run Code Online (Sandbox Code Playgroud)

我会用:

if [[ $(ls -A | wc -c) -ne 0 ]]
# or:
if [[ $(ls -A | head -c1 | wc -c) -ne 0 ]]
Run Code Online (Sandbox Code Playgroud)

代替:

if [ -z "$(ls -lA)" ]
Run Code Online (Sandbox Code Playgroud)

我会用:

if [ $(ls -lA | wc -c) -eq 0 ]
# or:
if [ $(ls -lA | head -c1 | wc -c) -eq 0 ]
Run Code Online (Sandbox Code Playgroud)

等等.

对于小输出,它可能不是问题,但对于较大的输出,差异可能很大:

$ time [ -z "$(seq 1 10000000)" ]

real    0m2.703s
user    0m2.485s
sys 0m0.347s
Run Code Online (Sandbox Code Playgroud)

比较它:

$ time [ $(seq 1 10000000 | wc -c) -eq 0 ]

real    0m0.128s
user    0m0.081s
sys 0m0.105s
Run Code Online (Sandbox Code Playgroud)

甚至更好:

$ time [ $(seq 1 10000000 | head -c1 | wc -c) -eq 0 ]

real    0m0.004s
user    0m0.000s
sys 0m0.007s
Run Code Online (Sandbox Code Playgroud)

完整的例子

Will Vousden回答的更新示例:

if [[ $(ls -A | wc -c) -ne 0 ]]; then
    echo "there are files"
else
    echo "no files found"
fi
Run Code Online (Sandbox Code Playgroud)

netj建议后再次更新:

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

丢弃空白

如果您正在测试的命令可能会输出一些您想要视为空字符串的空格,那么而不是:

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
Run Code Online (Sandbox Code Playgroud)

你可以使用:

| wc -c
Run Code Online (Sandbox Code Playgroud)

或者grep:

| tr -d ' \n\r\t ' | wc -c
Run Code Online (Sandbox Code Playgroud)

或类似的东西.

摘要

  1. 首先,使用该命令的作品.

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

答案没有说明输出总是很小,因此也需要考虑大输出的可能性.

  • `[[$(... | head -c | wc -c)-gt 0]]`或`[[-n $(... | head -c1)]]`更好,因为`wc -c`必须消耗命令的整个输出. (3认同)

Veg*_*ger 35

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

这将运行该命令并检查返回的输出(字符串)是否具有零长度.您可能需要检查"测试"手册页以获取其他标志.

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

注意:它ls -la总是返回.,..因此使用它将不起作用,请参阅ls手册页.此外,虽然这看似简单方便,但我认为它很容易破解.根据结果​​编写一个返回0或1的小脚本/应用程序要可靠得多!


Ale*_*lex 21

对于那些想要一个优雅的,独立于bash版本的解决方案(实际上应该在其他现代shell中工作)和那些喜欢使用单行程来快速完成任务的人.开始了!

ls | grep . && echo 'files found' || echo 'files not found'
Run Code Online (Sandbox Code Playgroud)

(注意提到的评论之一,ls -al事实上,只是-l并且-a都将返回一些东西,所以在我的回答中我使用简单ls

  • 如果使用`grep -q ^`,换行字符也会匹配,grep不会向标准输出打印任何内容.此外,它会在收到任何输入后立即退出,而不是等待其输入流结束. (4认同)

use*_*ser 12

Bash参考手册

6.4 Bash条件表达式

-z string
     True if the length of string is zero.

-n string
string
     True if the length of string is non-zero.
Run Code Online (Sandbox Code Playgroud)

您可以使用速记版本:

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

  • @ 71GA:也许这很容易被忽视,但如果仔细观察,你会发现`string`是`-n string`的同义词. (4认同)

Bas*_*tch 10

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

例如,您可以将命令的输出放入shell变量中:

v=$(ls -Al)
Run Code Online (Sandbox Code Playgroud)

较旧的,不可嵌套的符号是

v=`ls -Al`
Run Code Online (Sandbox Code Playgroud)

但我更喜欢可嵌套的符号$(......)

您可以测试该变量是否为空

if [ -n "$v" ]; then
    echo there are files
else
    echo no files
fi
Run Code Online (Sandbox Code Playgroud)

你可以将两者结合起来 if [ -n "$(ls -Al)" ]; then


Jon*_*Lin 5

我猜想您需要ls -al命令的输出,因此在bash中,您将拥有类似以下内容的东西:

LS=`ls -la`

if [ -n "$LS" ]; then
  echo "there are files"
else
  echo "no files found"
fi
Run Code Online (Sandbox Code Playgroud)

  • @gniourf_gniourf - 是什么让你这么想?不可否认,反引号咒语不如 $( ) 那么漂亮或灵活,但它有效...... (2认同)