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 -al
和ls -Al
命令 – 它们都在空目录中输出非空string。 这些例子总是报告, 即使没有文件,也有文件。
出于这个原因,你应该只使用ls -A
– 为什么有人想要使用-l
开关,这意味着“使用长列表格式”,当你想要的只是testing是否有任何输出,不pipe怎样?
所以这里的大部分答案都是不正确的。
第二个问题
第二个问题是,虽然有些答案工作正常(那些不使用ls -al
或ls -Al
而是ls -A
),他们都做这样的事情:
- 运行一个命令
- 将其整个输出缓冲在RAM中
- 将输出转换成一个巨大的单行string
- 将该string与空string进行比较
我会build议做的,而不是:
- 运行一个命令
- 统计其输出中的字符而不存储它们
- 甚至更好 –
using 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的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
或类似的东西。
概要
-
首先,使用一个可行的命令。
-
其次,避免在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问题。