我有以下bash脚本:
if ls /Users/david/Desktop/empty > /dev/null
then
echo 'yes -- files'
else
echo 'no -- files'
fi
如果/Users/david/Desktop/empty
目录中有一个或多个文件,我如何修改顶线以使其评估为真?
答案 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'