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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/12137431/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-09 22:36:14  来源:igfitidea点击:

Test if a command outputs an empty string

bashshell

提问by barp

How can I test if a command outputs an empty string?

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

回答by Will Vousden

Previously, the question asked how to check whether there are files in a directory. The following code achieves that, but see rsp's answerfor a better solution.

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



Empty output

空输出

Commands don't returnvalues – they output them. You can capture this output by using command substitution; e.g. $(ls -A). You can test for a non-empty string in Bash like this:

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

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

Note that I've used -Arather than -a, since it omits the symbolic current (.) and parent (..) directory entries.

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

Note:As pointed out in the comments, command substitution doesn't capture trailing newlines. Therefore, if the command outputs onlynewlines, the substitution will capture nothing and the test will return false. While very unlikely, this is possible in the above example, since a single newline is a valid filename! More information in this answer.

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



Exit code

退出代码

If you want to check that the command completed successfully, you can inspect $?, which contains the exit code of the last command (zero for success, non-zero for failure). For example:

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

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

More info here.

更多信息在这里

回答by rsp

TL;DR

TL; 博士

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

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

Thanks to netjfor a suggestion to improve my original:
if [[ $(ls -A | wc -c) -ne 0 ]]; then ...; fi

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



This is an old question but I see at least two things that need some improvement or at least some clarification.

这是一个老问题,但我认为至少有两件事需要改进或至少需要澄清。

First problem

第一个问题

First problem I see is that most of the examples provided here simply don't work. They use the ls -aland ls -Alcommands - both of which output non-empty strings in empty directories. Those examples alwaysreport that there are files even when there are none.

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

For that reason you should use just ls -A- Why would anyone want to use the -lswitch which means "use a long listing format" when all you want is test if there is any output or not, anyway?

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

So most of the answers here are simply incorrect.

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

Second problem

第二个问题

The second problem is that while someanswers work fine (those that don'tuse ls -alor ls -Albut ls -Ainstead) they all do something like this:

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

  1. run a command
  2. buffer its entire output in RAM
  3. convert the output into a huge single-line string
  4. compare that string to an empty string
  1. 运行命令
  2. 在 RAM 中缓冲其整个输出
  3. 将输出转换为一个巨大的单行字符串
  4. 将该字符串与空字符串进行比较

What I would suggest doing instead would be:

我建议做的是:

  1. run a command
  2. count the characters in its output without storing them
    • or even better - count the number of maximally 1 character using head -c1
      (thanks to netjfor posting this idea in the comments below)
  3. compare that number with zero
  1. 运行命令
  2. 计算其输出中的字符而不存储它们
    • 甚至更好 - 计算最多 1 个字符的数量using head -c1
      (感谢netj在下面的评论中发布这个想法)
  3. 将该数字与零进行比较

So for example, instead of:

因此,例如,而不是:

if [[ $(ls -A) ]]

I would use:

我会用:

if [[ $(ls -A | wc -c) -ne 0 ]]
# or:
if [[ $(ls -A | head -c1 | wc -c) -ne 0 ]]

Instead of:

代替:

if [ -z "$(ls -lA)" ]

I would use:

我会用:

if [ $(ls -lA | wc -c) -eq 0 ]
# or:
if [ $(ls -lA | head -c1 | wc -c) -eq 0 ]

and so on.

等等。

For small outputs it may not be a problem but for larger outputs the difference may be significant:

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

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

real    0m2.703s
user    0m2.485s
sys 0m0.347s

Compare it with:

与它进行比较:

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

real    0m0.128s
user    0m0.081s
sys 0m0.105s

And even better:

甚至更好:

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

real    0m0.004s
user    0m0.000s
sys 0m0.007s

Full example

完整示例

Updated example from the answer by Will Vousden:

来自 Will Vousden 的答案的更新示例:

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

Updated again after suggestions by netj:

根据netj 的建议再次更新:

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

Additional update by jakeonfire:

jakeonfire 的额外更新:

grepwill exit with a failure if there is no match. We can take advantage of this to simplify the syntax slightly:

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

Discarding whitespace

丢弃空格

If the command that you're testing could output some whitespace that you want to treat as an empty string, then instead of:

如果您正在测试的命令可能会输出一些您希望将其视为空字符串的空格,则不要:

| wc -c

you could use:

你可以使用:

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

or with head -c1:

或与head -c1

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

or something like that.

或类似的东西。

Summary

概括

  1. First, use a command that works.

  2. Second, avoid unnecessary storing in RAM and processing of potentially huge data.

  1. 首先,用命令的作品

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

The answer didn't specify that the output is always small so a possibility of large output needs to be considered as well.

答案没有指定输出总是很小,因此还需要考虑大输出的可能性。

回答by Veger

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

This will run the command and check whether the returned output (string) has a zero length. You might want to check the 'test' manual pagesfor other flags.

这将运行命令并检查返回的输出(字符串)是否具有零长度。您可能需要查看“测试”手册页以了解其他标志。

Use the "" around the argument that is being checked, otherwise empty results will result in a syntax error as there is no second argument (to check) given!

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

Note: that ls -laalways returns .and ..so using that will not work, see ls manual pages. Furthermore, while this might seem convenient and easy, I suppose it will break easily. Writing a small script/application that returns 0 or 1 depending on the result is much more reliable!

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

回答by Alex

For those who want an elegant, bash version-independent solution (in fact should work in other modern shells) and those who love to use one-liners for quick tasks. Here we go!

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

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

(note as one of the comments mentioned, ls -aland in fact, just -land -awill all return something, so in my answer I use simple ls

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

回答by user

Bash Reference Manual

Bash 参考手册

6.4 Bash Conditional Expressions

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.

You can use shorthand version:

您可以使用速记版本:

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

回答by Basile Starynkevitch

As Jon Lin commented, ls -alwill always output (for .and ..). You want ls -Alto avoid these two directories.

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

You could for example put the output of the command into a shell variable:

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

v=$(ls -Al)

An older, non-nestable, notation is

一个较旧的、不可嵌套的符号是

v=`ls -Al`

but I prefer the nestable notation $(... )

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

The you can test if that variable is non empty

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

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

And you could combine both as if [ -n "$(ls -Al)" ]; then

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

回答by Jon Lin

I'm guessing you want the output of the ls -alcommand, so in bash, you'd have something like:

我猜你想要ls -al命令的输出,所以在 bash 中,你会有类似的东西:

LS=`ls -la`

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

回答by Curt

Here's a solution for more extreme cases:

这是针对更极端情况的解决方案:

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

This will work

这将工作

  • for all Bourne shells;
  • if the command output is all zeroes;
  • efficiently regardless of output size;
  • 适用于所有 Bourne 炮弹;
  • 如果命令输出全为零;
  • 无论输出大小如何都有效;

however,

然而,

  • the command or its subprocesses will be killed once anything is output.
  • 一旦输出任何内容,该命令或其子进程将被终止。

回答by gniourf_gniourf

All the answers given so far deal with commands that terminateand output a non-empty string.

鉴于到目前为止处理所有的答案是命令终止并输出一个非空字符串。

Most are broken in the following senses:

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

  • They don't deal properly with commands outputting only newlines;
  • starting from Bash≥4.4 most will spam standard error if the command output null bytes (as they use command substitution);
  • most will slurp the full output stream, so will wait until the command terminates before answering. Some commands never terminate (try, e.g., yes).
  • 他们没有正确处理只输出换行符的命令;
  • 从 Bash≥4.4 开始,如果命令输出空字节(因为它们使用命令替换),大多数情况下会出现垃圾邮件标准错误;
  • 大多数人会吞下完整的输出流,因此会等到命令终止后再回答。一些命令永远不会终止(尝试,例如,yes)。

So to fix all these issues, and to answer the following question efficiently,

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

How can I test if a command outputs an empty string?

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

you can use:

您可以使用:

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

You may also add some timeout so as to test whether a command outputs a non-empty string within a given time, using read's -toption. E.g., for a 2.5 seconds timeout:

您还可以使用read's-t选项添加一些超时以测试命令是否在给定时间内输出非空字符串。例如,对于 2.5 秒的超时:

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


Remark.If you think you need to determine whether a command outputs a non-empty string, you very likely have an XY problem.

评论。如果您认为需要确定命令是否输出非空字符串,则很可能存在 XY 问题。

回答by Darren Smith

Here's an alternative approach that writes the std-out and std-err of some command a temporary file, and then checks to see if that file is empty. A benefit of this approach is that it captures both outputs, and does not use sub-shells or pipes. These latter aspects are important because they can interfere with trapping bash exit handling (e.g. here)

这是另一种方法,它将某些命令的 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"