bash - 除非删除引号,否则为什么 [ "$(ls *.jpg | wc -l)"= 0 ] 总是假的?

标签 bash shell

既然我当前工作目录下没有jpg文件,为什么jpg1.shjpg2.sh这两个脚本给不同的结果?如何理解差异?请注意,脚本之间的唯一区别是是否在 $() 命令替换周围使用双引号。

$ cat jpg1.sh
#!/bin/bash
if [ "$(ls *.jpg | wc -l)" = 0 ]; then
    echo "yes"
else
    echo "no"
fi

$ ./jpg1.sh
ls: *.jpg: No such file or directory
no

$ cat jpg2.sh
#!/bin/bash
if [ $(ls *.jpg | wc -l) = 0 ]; then
    echo "yes"
else
    echo "no"
fi

$ ./jpg2.sh
ls: *.jpg: No such file or directory
yes

跟进

我证明打勾的答案是切中要害的——wc -l 的返回值中有一些额外的空格。将 set -x 添加到两个脚本后,差异就显而易见了。

$ ./jpg1.sh
++ wc -l
++ ls '*.jpg'
ls: *.jpg: No such file or directory
+ '[' '       0' = 0 ']'
+ echo no
no

$ ./jpg2.sh
++ wc -l
++ ls '*.jpg'
ls: *.jpg: No such file or directory
+ '[' 0 = 0 ']'
+ echo yes
yes

顺便说一句,我的系统是 macOS Catalina。

最佳答案

在某些系统上这是错误的,因为 wc -l 用空格填充它的答案,而你正在比较的字符串 -- 0 -- 不包含任何空格。当您使用引号时,会比较确切的输出;当您将它们关闭时,输出会根据空格分成单独的单词,并且每个单词都会扩展为一个 glob,然后再将其放入 [ 命令行。要确定您是否在这样的系统上,请将 set -x 添加到您的脚本以启用跟踪级日志记录,这样您就可以看到 [ 被要求的确切值比较。

在目前的情况下,整个问题都被简单地避免了:没有理由为此目的使用 either lswc

#!/usr/bin/env bash

shopt -s nullglob
jpegs=( *.jpg )
if (( ${#jpegs[@]} == 0 )); then
  echo "No JPEG files were found"
else
  echo "Exactly ${#jpegs[@]} JPEG files were found"
fi

关于bash - 除非删除引号,否则为什么 [ "$(ls *.jpg | wc -l)"= 0 ] 总是假的?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/64429628/

相关文章:

shell - 如何在 shell 脚本中解析配置文件 (*.conf)?

linux - 验证文件记录 shell 脚本

linux - 如何通过脚本文件更改目录

php - 在不显示 shell 窗口的情况下执行 bash 脚本

linux - 读取文件中的第一行并将其附加到搜索字符串的第一次出现处并重复直到 EOF

python - 为什么 virtualenvwrapper 不能在 wing ide pro 终端内工作?

python - ">"无法将 python 命令的输出定向到文件

linux - 如何使用 grep 进行搜索和替换

linux - 如何使用 awk 命令验证文件的内容?

perl - 如何在不丢失颜色的情况下从 Perl 中的终端进行管道传输?