如何测试命令是否输出空字符串?
我猜你想要ls -al命令的输出,所以在bash中,你会有这样的东西:
ls -al
LS=`ls -la` if [ -n "$LS" ]; then echo "there are files" else echo "no files found" fi
之前,问题询问如何检查目录中是否有文件。下面的代码实现了这一点,但请参阅rsp的答案以获得更好的解决方案。
命令不返回值-他们输出它们。你可以通过使用命令替换 .;例如$(ls -A)。你可以像这样在Bash中测试一个非空字符串:
$(ls -A)
if [[ $(ls -A) ]]; then echo "there are files" else echo "no files found" fi
注意,我使用了-A而不是-a,因为它省略了符号当前(.)和父目录(..)项。
-A
-a
.
..
正如注释中指出的,命令替换不捕获尾随换行符. 注意:。因此,如果命令输出只有换行符,替换将不会捕获任何内容,并且测试将返回false。虽然不太可能,但在上面的例子中这是可能的,因为一个换行符就是一个有效的文件名!更多信息在这个答案。
如果你想检查命令是否成功完成,你可以检查$?,它包含最后一个命令的退出码(0表示成功,非0表示失败)。例如:
$?
files=$(ls -A) if [[ $? != 0 ]]; then echo "Command failed." elif [[ $files ]]; then echo "Files found." else echo "No files found." fi
更多信息在这里。
正如Jon Lin所评论的,ls -al将始终输出(对于.和..)。你想要ls -Al避免这两个目录。
ls -Al
例如,你可以把命令的输出放到一个shell变量中:
v=$(ls -Al)
较旧的、非嵌套的符号是
v=`ls -Al`
但我更喜欢嵌套符号$(…)
$(
)
您可以测试该变量是否为非空
if [ -n "$v" ]; then echo there are files else echo no files fi
你可以将两者合并为if [ -n "$(ls -Al)" ]; then
if [ -n "$(ls -Al)" ]; then
有时候,ls可能是某个shell 别名。你可能更喜欢使用$(/bin/ls -Al)。参见ls (1)和昨天(7)和环境(7)和你的~/.bashrc(如果你的shell是GNU bash;我的交互式shell是zsh,在/etc/passwd中定义-参见$(/bin/ls -Al)0和$(/bin/ls -Al)1)。
ls
$(/bin/ls -Al)
~/.bashrc
/etc/passwd
if [ -z "$(ls -lA)" ]; then echo "no files found" else echo "There are files" fi
该命令将运行该命令并检查返回的输出(字符串)是否为零长度。 你可能想检查“测试”手册页是否有其他标志
在要检查的参数周围使用"",否则空结果将导致语法错误,因为没有给出第二个参数(要检查)!
注意:ls -la总是返回.和..,因此使用它将不起作用,请参阅Ls手册页。此外,虽然这可能看起来方便和容易,我想它会很容易坏。编写一个根据结果返回0或1的小脚本/应用程序要可靠得多!
ls -la
Bash Reference Manual . sh -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
-z string True if the length of string is zero. -n string string True if the length of string is non-zero.
你可以使用速记版:
适合那些想要优雅的、与bash版本无关的解决方案(实际上应该可以在其他现代shell中工作)以及喜欢使用一行程序执行快速任务的人。我们开始吧!
ls | grep . && echo 'files found' || echo 'files not found'
(注意,正如其中一个注释所提到的,ls -al和事实上,只有-l和-a都会返回一些东西,所以在我的回答中,我使用简单的ls
-l
下面是针对更极端情况的解决方案:
if [ `command | head -c1 | wc -c` -gt 0 ]; then ...; fi
这是可行的
然而,
if [[ $(ls -A | head -c1 | wc -c) -ne 0 ]]; then ...; fi
感谢netj 对于一个建议,以改善我的原始:if [[ $(ls -A | wc -c) -ne 0 ]]; then ...; fi
if [[ $(ls -A | wc -c) -ne 0 ]]; then ...; fi
这是一个老问题,但我认为至少有两件事需要改进或至少需要澄清。
我看到的第一个问题是这里提供的大多数示例根本不起作用。它们使用ls -al和ls -Al命令——这两个命令都在空目录中输出非空字符串。这些例子总是报告存在文件即使没有。
出于这个原因,你应该只使用ls -A -为什么有人想要使用-l开关,这意味着“使用长列表格式”,当你想要的只是测试是否有任何输出时,无论如何?
ls -A
所以大部分答案都是不正确的。
第二个问题是,虽然一些答案工作得很好(那些不使用ls -al或ls -Al而不是ls -A),但它们都是这样做的:
我的建议是:
using head -c1
比如,不用:
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将失败退出。我们可以利用这一点来稍微简化语法:
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:
head -c1
| tr -d ' \n\r\t ' | head -c1 | wc -c
或者类似的东西。
首先,使用一个命令works。
其次,避免在RAM中不必要的存储和处理潜在的巨大数据。
答案并没有说明输出总是很小,所以需要考虑大输出的可能性。
到目前为止给出的所有答案都涉及命令终止并输出一个非空字符串。
大多数是在以下意义上被打破的:
yes
所以为了解决所有这些问题,并有效地回答下面的问题,
你可以使用:
if read -n1 -d '' < <(command_here); then echo "Command outputs something" else echo "Command doesn't output anything" fi
你也可以使用read的-t选项添加一些超时,以测试一个命令是否在给定时间内输出一个非空字符串。例如,对于2.5秒的超时:
read
-t
if read -t2.5 -n1 -d '' < <(command_here); then echo "Command outputs something" else echo "Command doesn't output anything" fi
的话。如果你认为你需要确定一个命令是否输出一个非空字符串,你很可能有一个XY问题。
下面是另一种方法,将某些命令的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"
有时您希望保存输出(如果它是非空的),以便将其传递给另一个命令。如果是的话,你可以使用
list=`grep -l "MY_DESIRED_STRING" *.log ` if [ $? -eq 0 ] then /bin/rm $list fi
这样,如果列表为空,rm命令将不会挂起。
rm
作为由tripleee在问题评论中提到,使用moreutils ifne(如果输入不为空)。
ifne
在本例中,我们需要ifne -n,即否定测试:
ifne -n
ls -A /tmp/empty | ifne -n command-to-run-if-empty-input
当初始命令的输出为非空时,此方法相对于许多其他答案的优点。ifne将立即开始将其写入STDOUT,而不是缓冲整个输出,然后再写入,如果初始输出生成缓慢或非常长,并且会溢出shell变量的最大长度,这是很重要的。
moreutils中有一些utils可以说应该放在coreutils中——如果你花大量时间生活在shell中,它们值得一试。
对OP特别感兴趣的可能是dirempty/exists工具,该工具在撰写本文时仍在考虑中,并且已经有一段时间了(它可能会使用bump)。
dirempty/exists
有时“something"可能不是stdout,而是测试应用程序的stderr,所以这里有一个更通用的修复工作方式:
if [[ $(partprobe ${1} 2>&1 | wc -c) -ne 0 ]]; then echo "require fixing GPT parititioning" else echo "no GPT fix necessary" fi