我有以下bash脚本:
if ls /Users/david/Desktop/empty > /dev/null
then
echo 'yes -- files'
else
echo 'no -- files'
fi
Run Code Online (Sandbox Code Playgroud)
如果/Users/david/Desktop/empty
dir中有一个或多个文件,我如何修改顶行以使其评估为true ?
Cha*_*ffy 10
这在BashFAQ#004中有详细介绍.值得注意的是,为此目的使用的ls
是反模式,应该避免使用.
shopt -s dotglob # if including hidden files is desired
files=( "$dir"/* )
[[ -e $files || -L $files ]] && echo "Directory is not empty"
Run Code Online (Sandbox Code Playgroud)
[[ -e $files ]]
实际上并没有检查整个数组的内容是否存在; 相反,它检查返回的第一个名称 - 它处理没有文件匹配的情况,其中glob表达式本身作为唯一结果返回.
值得注意的是:
ls
,这需要使用fork()
生成子shell,execve()
替换子shell /bin/ls
,操作系统的动态链接器来加载ls
二进制使用的共享库等等.[这是一个非常大的目录,成千上万的文件 - 这种情况ls
也会很慢; 请参阅find
下面的基于解决方案的那些].ls
:globbing返回的文件列表保证与文件的文字名称完全匹配,而ls
可以使用隐藏字符来删除名称.如果第一个条目是有效的文件名,"${files[@]}"
则可以安全地迭代,并确保每个返回的值都是一个名称,并且如果本地ls
实现没有逃避它们,则无需担心文件系统在其名称中使用文字换行符膨胀计数.也就是说,另一种方法是使用find
,如果你有一个-empty
扩展(可从GNU查找和现代BSD,包括Mac OS):
[[ $(find -H "$dir" -maxdepth 0 -type d -empty) ]] || echo "Directory is not empty"
Run Code Online (Sandbox Code Playgroud)
...如果给出任何结果,则该目录是非空的.虽然比非常大的目录上的通用速度慢,但是对于在direntry缓存中不存在的极大目录来说,这比其中任何一个 ls
或全局更快,因为它可以在没有完整扫描的情况下返回结果.
强大的纯Bash解决方案:
有关背景为何与通配纯巴什解决方案是优于使用ls
,见查尔斯·达菲的有用的答案,其中还包含一个find
基于替代,这是更快,更少的内存密集型与大目录.[1]
也可以考虑anubhava的一样快stat
然而,基于内存效率的答案需要在Linux和BSD/OSX上使用不同的语法形式.
更新到更简单的解决方案,感谢从这个答案改编.
# 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
Run Code Online (Sandbox Code Playgroud)
compgen -G
通常用于制表符完成,但在这种情况下它也很有用:
注意compgen -G
它自己的 globbing,所以你必须在引号中传递glob(文件名模式),以输出所有匹配.在这种特殊情况下,即使在前面传递一个不带引号的模式也可以,但差别是没有价值的.
如果没有匹配,compgen -G
总是产生无输出(不论状态的nullglob
选项),并通过其退出代码指示至少1是否找到匹配,这是什么条件需要的优势(同时抑制任何标准输出输出,>/dev/null
).
# 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
Run Code Online (Sandbox Code Playgroud)
compgen -G
永远不会匹配隐藏的项目(无论dotglob
选项的状态如何),因此需要一个解决方法来查找隐藏的项目:
(...)
为条件创建子shell; 也就是说,子shell中执行的命令不会影响当前shell的环境,这允许我们以dotglob
本地化的方式设置选项.
shopt -s dotglob
导致*
也匹配隐藏的项目(除了.
和..
).
compgen -G *
与未加引号 *
,得益于的前期膨胀由外壳,要么通过至少一个的文件名,是否隐藏或不(附加文件名被忽略)或空字符串,如果既没有隐藏也不非隐藏物品存在.在前一种情况下,退出代码是0
(信令成功,因此是非空目录),在后面1
(发信号通知真正的空目录).
[1]这个答案最初错误地声称提供了一个基于以下方法的大型目录有效的Bash解决方案:(shopt -s nullglob dotglob; for f in "$dir"/*; do exit 0; done; exit 1)
.这是不是更有效,因为,在内部,猛砸仍然聚集在阵列中的所有比赛第一次进入循环之前-换句话说:for *
是不是懒洋洋地评估.