Bash命令查看dir中是否有任何文件 - 测试目录是否为空

时间:2016-02-09 01:45:16

标签: bash shell unix

我有以下bash脚本:

if ls /Users/david/Desktop/empty > /dev/null
then
    echo 'yes -- files'
else
    echo 'no -- files'
fi

如果/Users/david/Desktop/empty目录中有一个或多个文件,我如何修改顶线以使其评估为真?

3 个答案:

答案 0 :(得分:10)

BashFAQ #004详细介绍了这一点。值得注意的是,use of ls for this purpose is an antipattern and should be avoided

shopt -s dotglob   # if including hidden files is desired
files=( "$dir"/* )
[[ -e $files || -L $files ]] && echo "Directory is not empty"

[[ -e $files ]]实际上并不检查整个数组的内容是否存在;相反,它检查返回的第一个名称 - 它处理没有文件匹配的情况,其中glob表达式本身作为唯一结果返回。

值得注意的是:

  • 远远快于调用ls ,这需要使用fork()来生成子shell,execve()/bin/ls替换子shell ,操作系统的动态链接器,用于加载ls二进制文件等使用的共享库。[例外情况是一个非常大的目录,包含数万个文件 - {{1}也会很慢;请参阅下面基于ls的解决方案。
  • 这比调用find 更正确:globbing返回的文件列表保证与文件的文字名称完全匹配,而ls可以使用隐藏的角色。如果第一个条目是有效的文件名,ls可以安全地迭代,并确保每个返回的值都是一个名称,并且不需要担心文件系统在其名称中使用文字换行符,如果本地名称膨胀计数"${files[@]}"实施不会逃脱它们。

也就是说,另一种方法是使用ls,如果你有一个find扩展名(可从GNU find和现代BSD包括Mac OS获得):

-empty

...如果给出任何结果,则该目录为非空。虽然比非常大的目录慢,但是这比 [[ $(find -H "$dir" -maxdepth 0 -type d -empty) ]] || echo "Directory is not empty" 或者对于在direntry缓存中不存在的极大目录更快,因为它可以在没有完整的情况下返回结果扫描。

答案 1 :(得分:9)

强大的纯Bash 解决方案:

有关 原因的背景带有globbing的纯Bash解决方案优于使用ls ,请参阅 Charles Duffy's helpful answer < / strong>,其中还包含一个基于 find的替代使用大型目录更快,内存更少 [1]
还要考虑 anubhava同样快速且内存效率高stat-based answer ,但在Linux和BSD / OSX上需要不同的语法形式。

更新更简单的解决方案,感谢改编自this answer

# EXCLUDING hidden files and folders - note the *quoted* use of glob '*'
if compgen -G '*' >/dev/null; then
  echo 'not empty'
else
  echo 'empty, but may have hidden files/dirs.'
fi
  • compgen -G通常用于制表标签,但在这种情况下它也很有用:

    • 请注意compgen -G执行拥有通配符,因此必须将引号中的glob(文件名模式)传递给它才能输出所有内容火柴。在这种特殊情况下,即使预先传递未引用的模式也行不通,但差别无效。

    • 如果没有匹配,compgen -G 始终会产生输出(无论nullglob选项的状态如何),以及它通过其退出代码指示是否找到至少1个匹配,这是条件利用的(同时使用>/dev/null抑制任何stdout输出)。

# INCLUDING hidden files and folders - note the *unquoted* use of glob *
if (shopt -s dotglob; compgen -G * >/dev/null); then
  echo 'not empty'
else
  echo 'completely empty'
fi
  • compgen -G 从不匹配隐藏的项目(无论dotglob选项的状态如何),因此需要解决方法找到隐藏的项目:

    • (...)为条件创建子shell;也就是说,子shell中执行的命令不会影响当前shell的环境,这允许我们以本地化的方式设置dotglob选项。

    • shopt -s dotglob导致*也匹配隐藏的项目(...除外)。

    • compgen -G * 未加引号 *,感谢shell的 up-front 扩展,要么至少传递一个文件名,无论是否隐藏(忽略其他文件名)或空字符串(如果不存在隐藏或非隐藏项目)。在前一种情况下,退出代码是0(信号成功,因此是非空目录),在后面的1中(表示真正空目录)。

[1] 这个答案最初 falsely 声称基于以下方法提供了一个对大型目录有效的Bash解决方案:(shopt -s nullglob dotglob; for f in "$dir"/*; do exit 0; done; exit 1)。 这不是更有效,因为在内部,Bash 仍然在进入循环之前首先收集数组中的所有匹配项 - 换句话说:for * 评估懒洋洋。 功能

答案 2 :(得分:3)

这是一个基于stat命令的解决方案,如果针对目录(或指向目录的链接)运行,则可以返回硬链接数。它开始从3增加硬链接数,因为前两个是...条目,因此从此数字中减去2给出了实际的条目数给定目录(这也包括符号链接)。

所以把它们放在一起:

(( ($(stat -Lc '%h' "$dir") - 2) > 0)) && echo 'not empty' || echo 'empty'

根据man stat使用的选项是:

%h     number of hard links
-L     --dereference, follow links

编辑:要使其与BSD / OSX兼容,请使用:

(( ($(stat -Lf '%l' "$dir") - 2) > 0)) && echo 'not empty' || echo 'empty'