题
如何从 shell 脚本检查目录是否包含文件?
与此类似的东西
if [ -e /some/dir/* ]; then echo "huzzah"; fi;
但如果目录包含一个或多个文件,则该方法有效(上面的方法仅适用于 0 或 1 个文件)。
解决方案
到目前为止使用的解决方案 ls
. 。这是一个全 bash 解决方案:
#!/bin/bash
shopt -s nullglob dotglob # To include hidden files
files=(/some/dir/*)
if [ ${#files[@]} -gt 0 ]; then echo "huzzah"; fi
其他提示
三个最佳技巧
shopt -s nullglob dotglob; f=your/dir/*; ((${#f}))
这个技巧100% bash
并调用(生成)一个子 shell。这个想法来自 布鲁诺·德弗莱恩 并通过改进 团队鲍勃的评论。
files=$(shopt -s nullglob dotglob; echo your/dir/*)
if (( ${#files} ))
then
echo "contains files"
else
echo "empty (or does not exist or is a file)"
fi
笔记: 空目录和不存在的目录之间没有区别(即使提供的路径是一个文件)。
有一个类似的替代方案和更多详细信息(以及更多示例) '官方的' #bash IRC 频道常见问题解答:
if (shopt -s nullglob dotglob; f=(*); ((${#f[@]})))
then
echo "contains files"
else
echo "empty (or does not exist, or is a file)"
fi
[ -n "$(ls -A your/dir)" ]
这个技巧的灵感来自 尼克克拉夫特的文章 发布于 2007 年。添加 2>/dev/null
抑制输出错误 "No such file or directory"
.
也可以看看 安德鲁·泰勒的答案(2008)和 gr8can8dian的答案(2011)。
if [ -n "$(ls -A your/dir 2>/dev/null)" ]
then
echo "contains files (or is a file)"
else
echo "empty (or does not exist)"
fi
或者单行 bashism 版本:
[[ $(ls -A your/dir) ]] && echo "contains files" || echo "empty"
笔记: ls
回报 $?=2
当目录不存在时。但文件和空目录没有区别。
[ -n "$(find your/dir -prune -empty)" ]
最后一个技巧的灵感来自 重力星的回答 在哪里 -maxdepth 0
被替换为 -prune
并通过改进 菲尔斯的评论。
if [ -n "$(find your/dir -prune -empty 2>/dev/null)" ]
then
echo "empty (directory or file)"
else
echo "contains files (or does not exist)"
fi
使用的变体 -type d
:
if [ -n "$(find your/dir -prune -empty -type d 2>/dev/null)" ]
then
echo "empty directory"
else
echo "contains files (or does not exist or is not a directory)"
fi
解释:
find -prune
类似于find -maxdepth 0
使用较少的字符find -empty
打印空目录和文件find -type d
仅打印目录
笔记: 你也可以更换 [ -n "$(find your/dir -prune -empty)" ]
仅通过以下缩短版本:
if [ `find your/dir -prune -empty 2>/dev/null` ]
then
echo "empty (directory or file)"
else
echo "contains files (or does not exist)"
fi
最后的代码在大多数情况下都有效,但请注意,恶意路径可能会表达命令......
怎么样:
if find /some/dir/ -maxdepth 0 -empty | read v; then echo "Empty dir"; fi
这样就不需要生成目录内容的完整列表。这 read
就是丢弃输出并使表达式仅在读取内容时才计算为 true(即 /some/dir/
被发现为空 find
).
尝试:
if [ ! -z `ls /some/dir/*` ]; then echo "huzzah"; fi
# Works on hidden files, directories and regular files
### isEmpty()
# This function takes one parameter:
# $1 is the directory to check
# Echoes "huzzah" if the directory has files
function isEmpty(){
if [ "$(ls -A $1)" ]; then
echo "huzzah"
else
echo "has no files"
fi
}
小心包含大量文件的目录!可能需要一些时间来评估 ls
命令。
IMO 最好的解决方案是使用
find /some/dir/ -maxdepth 0 -empty
DIR="/some/dir"
if [ "$(ls -A $DIR)" ]; then
echo 'There is something alive in here'
fi
你能比较一下这个的输出吗?
ls -A /some/dir | wc -l
# Checks whether a directory contains any nonhidden files. # # usage: if isempty "$HOME"; then echo "Welcome home"; fi # isempty() { for _ief in $1/*; do if [ -e "$_ief" ]; then return 1 fi done return 0 }
一些实施说明:
- 这
for
循环避免调用外部ls
过程。它仍然读取所有目录条目一次。这只能通过编写显式使用 readdir() 的 C 程序来优化。 - 这
test -e
循环内部捕获空目录的情况,在这种情况下变量_ief
将被分配值“somedir/*”。仅当该文件存在时该函数才会返回“非空” - 该函数适用于所有 POSIX 实现。但请注意,Solaris /bin/sh 不属于该类别。它是
test
实施不支持-e
旗帜。
这告诉我该目录是否为空,如果不是,则它包含的文件数。
directory="/some/dir"
number_of_files=$(ls -A $directory | wc -l)
if [ "$number_of_files" == "0" ]; then
echo "directory $directory is empty"
else
echo "directory $directory contains $number_of_files files"
fi
这可能是一个非常晚的回应,但这是一个有效的解决方案。此行仅识别文件的存在!如果目录存在,它不会给您误报。
if find /path/to/check/* -maxdepth 0 -type f | read
then echo "Files Exist"
fi
我很惊讶的是 空目录的 woodedge 指南 没有被提及。对于 shell 类型的问题,本指南以及所有的羊毛材料都是必读的。
该页面值得注意的是:
切勿尝试解析 ls 输出。即使 ls -A 解决方案也可能会崩溃(例如在HP -UX上,如果您是root,则LS -A与您不植根的情况完全相反 - 不,我不能弥补一些令人难以置信的愚蠢的东西)。
事实上,人们可能希望完全避免直接的问题。通常人们想知道目录是否为空,因为他们想做一些涉及其中文件的事情,等等。看看更大的问题。例如,以下基于查找的示例之一可能是合适的解决方案:
# Bourne
find "$somedir" -type f -exec echo Found unexpected file {} \;
find "$somedir" -maxdepth 0 -empty -exec echo {} is empty. \; # GNU/BSD
find "$somedir" -type d -empty -exec cp /my/configfile {} \; # GNU/BSD
最常见的是,真正需要的是这样的:
# Bourne
for f in ./*.mpg; do
test -f "$f" || continue
mympgviewer "$f"
done
换句话说,提出问题的人可能认为需要明确的空目录测试,以避免像mympgviewer这样的错误消息:./*.mpg:实际上不需要此类测试时,没有此类文件或目录。
dir_is_empty() {
[ "${1##*/}" = "*" ]
}
if dir_is_empty /some/dir/* ; then
echo "huzzah"
fi
假设您没有名为 *
进入 /any/dir/you/check
, ,它应该可以工作 bash
dash
posh
busybox sh
和 zsh
但是(对于 zsh)需要 unsetopt nomatch
.
性能应该可以与任何 ls
哪个使用 *
(glob),我想在具有许多节点的目录上会很慢(我的 /usr/bin
3000 多个文件并没有那么慢),将至少使用足够的内存来分配所有目录/文件名(以及更多),因为它们都作为参数传递(解析)给函数,某些 shell 可能对参数数量有限制,并且/或参数的长度。
如果有一种可移植的快速 O(1) 零资源方法来检查目录是否为空,那就太好了。
更新
上面的版本不考虑隐藏文件/目录,以防需要更多测试,例如 is_empty
从 Rich 的 sh (POSIX shell) 技巧:
is_empty () (
cd "$1"
set -- .[!.]* ; test -f "$1" && return 1
set -- ..?* ; test -f "$1" && return 1
set -- * ; test -f "$1" && return 1
return 0 )
但是,相反,我正在考虑这样的事情:
dir_is_empty() {
[ "$(find "$1" -name "?*" | dd bs=$((${#1}+3)) count=1 2>/dev/null)" = "$1" ]
}
有些人担心尾随斜杠与参数和目录为空时的查找输出的差异,以及尾随换行符(但这应该很容易处理),遗憾的是我的 busybox
sh
显示可能存在的错误 find -> dd
输出被随机截断的管道(如果我使用 cat
输出总是相同的,似乎是 dd
与论证 count
).
小变化 布鲁诺的回答:
files=$(ls -1 /some/dir| wc -l)
if [ $files -gt 0 ]
then
echo "Contains files"
else
echo "Empty"
fi
这个对我有用
中兴
我知道这个问题被标记为 bash;不过,仅供参考,仅供参考 桀骜 用户:
测试非空目录
检查是否 foo
非空:
$ for i in foo(NF) ; do ... ; done
哪里,如果 foo
非空,则代码中 for
块将被执行。
测试空目录
检查是否 foo
是空的:
$ for i in foo(N/^F) ; do ... ; done
哪里,如果 foo
为空,代码中 for
块将被执行。
笔记
我们不需要引用目录 foo
如上所述,但如果我们需要的话,我们可以这样做:
$ for i in 'some directory!'(NF) ; do ... ; done
我们还可以测试多个对象,即使它不是一个目录:
$ mkdir X # empty directory
$ touch f # regular file
$ for i in X(N/^F) f(N/^F) ; do echo $i ; done # echo empty directories
X
任何不是目录的内容都将被忽略。
附加功能
由于我们是通配符,我们可以使用任何通配符(或大括号扩展):
$ mkdir X X1 X2 Y Y1 Y2 Z
$ touch Xf # create regular file
$ touch X1/f # directory X1 is not empty
$ touch Y1/.f # directory Y1 is not empty
$ ls -F # list all objects
X/ X1/ X2/ Xf Y/ Y1/ Y2/ Z/
$ for i in {X,Y}*(N/^F); do printf "$i "; done; echo # print empty directories
X X2 Y Y2
我们还可以检查放置在数组中的对象。以上述目录为例:
$ ls -F # list all objects
X/ X1/ X2/ Xf Y/ Y1/ Y2/ Z/
$ arr=(*) # place objects into array "arr"
$ for i in ${^arr}(N/^F); do printf "$i "; done; echo
X X2 Y Y2 Z
因此,我们可以测试可能已经在数组参数中设置的对象。
请注意,代码中 for
显然,块是依次在每个目录上执行的。如果这不合需要,那么您可以简单地填充一个数组参数,然后对该参数进行操作:
$ for i in *(NF) ; do full_directories+=($i) ; done
$ do_something $full_directories
解释
对于 zsh 用户有 (F)
全局限定符(参见 man zshexpn
),它匹配“完整”(非空)目录:
$ mkdir X Y
$ touch Y/.f # Y is now not empty
$ touch f # create a regular file
$ ls -dF * # list everything in the current directory
f X/ Y/
$ ls -dF *(F) # will list only "full" directories
Y/
预选赛 (F)
列出匹配的对象:是一个目录并且不为空。所以, (^F)
火柴:不是目录或为空。因此, (^F)
例如,单独也会列出常规文件。因此,正如上所解释的 zshexp
手册页,我们还需要 (/)
glob 限定符,仅列出目录:
$ mkdir X Y Z
$ touch X/f Y/.f # directories X and Y now not empty
$ for i in *(/^F) ; do echo $i ; done
Z
因此,要检查给定目录是否为空,您可以运行:
$ mkdir X
$ for i in X(/^F) ; do echo $i ; done ; echo "finished"
X
finished
只是为了确保不会捕获非空目录:
$ mkdir Y
$ touch Y/.f
$ for i in Y(/^F) ; do echo $i ; done ; echo "finished"
zsh: no matches found: Y(/^F)
finished
哎呀!自从 Y
不为空,zsh 找不到匹配项 (/^F)
(“空目录”),从而输出一条错误消息,指出未找到 glob 的匹配项。因此,我们需要使用以下命令来抑制这些可能的错误消息 (N)
全局限定符:
$ mkdir Y
$ touch Y/.f
$ for i in Y(N/^F) ; do echo $i ; done ; echo "finished"
finished
因此,对于非空目录,我们需要限定符 (N/^F)
, ,您可以将其读作:“不要警告我有关失败、目录未满的信息”。
同样,对于空目录,我们需要限定符 (NF)
, ,我们同样可以读作:“不要警告我有关失败、完整目录的信息”。
if ls /some/dir/* >/dev/null 2>&1 ; then echo "huzzah"; fi;
到目前为止,我还没有看到使用 grep 的答案,我认为它会给出一个更简单的答案(没有太多奇怪的符号!)。这是我将使用Bourne Shell中检查目录中是否存在任何文件:
这将返回目录中的文件数:
ls -l <directory> | egrep -c "^-"
写入目录的地方可以填写目录路径。管道的前半部分确保每个文件的输出的第一个字符是“-”。然后,EGREP使用正则表达式计数以该符号开头的行数。现在您所要做的就是存储您获得的数字并使用反引号进行比较,例如:
#!/bin/sh
fileNum=`ls -l <directory> | egrep -c "^-"`
if [ $fileNum == x ]
then
#do what you want to do
fi
x 是您选择的变量。
混合修剪的东西和最后的答案,我必须
find "$some_dir" -prune -empty -type d | read && echo empty || echo "not empty"
这也适用于带有空格的路径
简单回答 巴什:
if [[ $(ls /some/dir/) ]]; then echo "huzzah"; fi;
我会去 find
:
if [ -z "$(find $dir -maxdepth 1 -type f)" ]; then
echo "$dir has NO files"
else
echo "$dir has files"
这将检查仅在目录中查找文件的输出,而不遍历子目录。然后它使用以下命令检查输出 -z
选项取自 man test
:
-z STRING
the length of STRING is zero
查看一些结果:
$ mkdir aaa
$ dir="aaa"
空目录:
$ [ -z "$(find aaa/ -maxdepth 1 -type f)" ] && echo "empty"
empty
只是其中的目录:
$ mkdir aaa/bbb
$ [ -z "$(find aaa/ -maxdepth 1 -type f)" ] && echo "empty"
empty
目录中的一个文件:
$ touch aaa/myfile
$ [ -z "$(find aaa/ -maxdepth 1 -type f)" ] && echo "empty"
$ rm aaa/myfile
子目录中的文件:
$ touch aaa/bbb/another_file
$ [ -z "$(find aaa/ -maxdepth 1 -type f)" ] && echo "empty"
empty
尝试使用命令 find 。指定硬编码的目录或作为参数。然后启动find搜索该目录下的所有文件。检查 find 的返回是否为 null。回显find的数据
#!/bin/bash
_DIR="/home/user/test/"
#_DIR=$1
_FIND=$(find $_DIR -type f )
if [ -n "$_FIND" ]
then
echo -e "$_DIR contains files or subdirs with files \n\n "
echo "$_FIND"
else
echo "empty (or does not exist)"
fi
通过一些解决方法,我可以找到一种简单的方法来查找目录中是否有文件。这可以通过 grep 命令进行更多扩展,以专门检查 .xml 或 .txt 文件等。前任 : ls /some/dir | grep xml | wc -l | grep -w "0"
#!/bin/bash
if ([ $(ls /some/dir | wc -l | grep -w "0") ])
then
echo 'No files'
else
echo 'Found files'
fi
我不喜欢 ls - A
已发布解决方案。您很可能希望测试该目录是否为空,因为您不想删除它。下面就是这样做的。但是,如果您只想记录一个空文件,那么删除并重新创建它肯定比列出可能无限的文件更快吗?
这应该有效...
if ! rmdir ${target}
then
echo "not empty"
else
echo "empty"
mkdir ${target}
fi
测试特定目标目录
if [ -d $target_dir ]; then
ls_contents=$(ls -1 $target_dir | xargs);
if [ ! -z "$ls_contents" -a "$ls_contents" != "" ]; then
echo "is not empty";
else
echo "is empty";
fi;
else
echo "directory does not exist";
fi;
这对我来说效果很好(当目录存在时):
some_dir="/some/dir with whitespace & other characters/"
if find "`echo "$some_dir"`" -maxdepth 0 -empty | read v; then echo "Empty dir"; fi
经过全面检查:
if [ -d "$some_dir" ]; then
if find "`echo "$some_dir"`" -maxdepth 0 -empty | read v; then echo "Empty dir"; else "Dir is NOT empty" fi
fi