134

从 shell 脚本中,如何检查目录是否包含文件?

类似的东西

if [ -e /some/dir/* ]; then echo "huzzah"; fi;

但如果目录包含一个或多个文件(上述文件仅适用于恰好 0 或 1 个文件),则此方法有效。

4

29 回答 29

160

三个最佳技巧


shopt -s nullglob dotglob; f=your/dir/*; ((${#f}))

这个技巧是 100%bash并调用(生成)一个子 shell。这个想法来自Bruno De Fraine,并由teambob的评论改进。

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 年发布的nixCraft 的文章。添加2>/dev/null以抑制输出错误"No such file or directory"
另请参见Andrew Taylor的回答 (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)" ]

最后一个技巧的灵感来自gravstar 的回答,其中被phils-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

最后一段代码在大多数情况下都有效,但请注意恶意路径可能会表达命令......

于 2013-07-27T22:16:46.973 回答
85

到目前为止的解决方案使用ls. 这是一个全 bash 解决方案:

#!/bin/bash
shopt -s nullglob dotglob     # To include hidden files
files=(/some/dir/*)
if [ ${#files[@]} -gt 0 ]; then echo "huzzah"; fi
于 2008-09-18T10:46:21.353 回答
51

以下情况如何:

if find /some/dir/ -maxdepth 0 -empty | read v; then echo "Empty dir"; fi

这样就不需要生成目录内容的完整列表。既要丢弃输出,read又要使表达式仅在读取某些内容时才计算为真(即/some/dir/通过 发现为空find)。

于 2008-09-18T11:05:35.957 回答
23

尝试:

if [ ! -z `ls /some/dir/*` ]; then echo "huzzah"; fi
于 2008-09-18T10:09:04.470 回答
16

注意有很多文件的目录!ls评估命令可能需要一些时间。

IMO 最好的解决方案是使用

find /some/dir/ -maxdepth 0 -empty
于 2008-09-18T11:31:03.557 回答
15
# 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
}
于 2011-01-24T03:05:58.523 回答
8
DIR="/some/dir"
if [ "$(ls -A $DIR)" ]; then
     echo 'There is something alive in here'
fi
于 2008-09-18T10:10:35.917 回答
6

你能比较一下这个的输出吗?

 ls -A /some/dir | wc -l
于 2008-09-18T10:12:31.983 回答
4

这可能是一个非常晚的响应,但这是一个有效的解决方案。此行仅识别文件的存在!如果目录存在,它不会给你一个误报。

if find /path/to/check/* -maxdepth 0 -type f | read
  then echo "Files Exist"
fi
于 2009-01-04T00:52:21.053 回答
4
# 检查目录是否包含任何非隐藏文件。
#
# 用法: if isempty "$HOME"; 然后回显“欢迎回家”;菲
#
是空的() {
    对于 $1/* 中的 _ief;做
        如果 [ -e "$_ief" ]; 然后
            返回 1
        菲
    完毕
    返回 0
}

一些实现说明:

  • for循环避免了对外部ls进程的调用。它仍然读取所有目录条目一次。这只能通过编写显式使用 readdir() 的 C 程序来优化。
  • 循环内部test -e捕获空目录的情况,在这种情况下,_ief将为变量分配值“somedir/*”。仅当该文件存在时,该函数才会返回“非空”
  • 此功能适用于所有 POSIX 实现。但请注意,Solaris /bin/sh 不属于该类别。它的test实现不支持该-e标志。
于 2010-03-08T17:04:28.510 回答
4

这告诉我目录是空的还是不是空的,它包含的文件数。

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
于 2015-04-24T07:34:27.340 回答
3

ZSH

我知道这个问题被标记为 bash;但是,仅供参考,对于zsh用户:

测试非空目录

检查是否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

任何不是目录的东西都将被忽略。

附加功能

由于我们是 glob,我们可以使用任何 glob(或大括号扩展):

$ 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)glob 限定符(参见 参考资料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)("directories that is empty") 的匹配项,因此会吐出一条错误消息,指出未找到 glob 的匹配项。因此,我们需要使用(N)glob 限定符抑制这些可能的错误消息:

$ mkdir Y
$ touch Y/.f
$ for i in Y(N/^F) ; do echo $i ; done ; echo "finished"
finished

因此,对于空目录,我们需要限定符(N/^F),您可以将其解读为:“不要警告我失败,目录未满”。

同样,对于非空目录,我们需要限定符(NF),我们也可以将其读作:“不要警告我失败,完整目录”。

于 2018-06-08T00:06:38.163 回答
2
dir_is_empty() {
   [ "${1##*/}" = "*" ]
}

if dir_is_empty /some/dir/* ; then
   echo "huzzah"
fi

假设您没有名为*into的文件/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" ]
}

当 dir 为空时,一些关于尾随斜杠与参数和 find 输出的差异以及尾随换行符(但这应该很容易处理)的担忧,遗憾的是,在我的busybox sh节目中,可能是find -> dd管道上的一个错误,输出被随机截断(如果我使用cat的输出总是相同的,似乎是dd与论点count)。

于 2014-09-13T01:09:50.873 回答
1

我很惊讶没有提到空目录的羊毛指南。本指南,以及所有的wooleedge,都是shell类型问题的必读。

该页面的注意事项:

永远不要尝试解析 ls 输出。甚至 ls -A 解决方案也可能中断(例如,在 HP-UX 上,如果您是 root 用户,则 ls -A 的作用与您不是 root 用户的情况完全相反——不,我无法编造出令人难以置信的东西愚蠢的)。

事实上,人们可能希望完全避免直接的问题。通常人们想知道一个目录是否为空,因为他们想做一些涉及其中文件的事情,等等。看看更大的问题。例如,这些基于查找的示例之一可能是合适的解决方案:

   # 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: No such file or directory 而实际上不需要这样的测试的错误消息。

于 2014-08-01T17:00:22.767 回答
1

布鲁诺答案的小变化:

files=$(ls -1 /some/dir| wc -l)
if [ $files -gt 0 ] 
then
    echo "Contains files"
else
    echo "Empty"
fi

这个对我有用

于 2015-09-16T08:43:18.287 回答
1

通过一些解决方法,我可以找到一种简单的方法来找出目录中是否有文件。这可以通过 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
于 2018-07-18T12:32:54.353 回答
1

从 olibre 的回答中得到一个提示(或几个),我喜欢 Bash 函数:

function isEmptyDir {
  [ -d $1 -a -n "$( find $1 -prune -empty 2>/dev/null )" ]
}

因为虽然它创建了一个子外壳,但它与我想象的 O(1) 解决方案一样接近,并且给它一个名称使其可读。然后我可以写

if isEmptyDir somedir
then
  echo somedir is an empty directory
else
  echo somedir does not exist, is not a dir, is unreadable, or is  not empty
fi

至于 O(1) 存在异常情况:如果一个大目录已经删除了所有或所有但最后一个条目,“查找”可能必须读取整个内容以确定它是否为空。我相信预期的性能是 O(1),但最坏的情况是目录大小是线性的。我没有测量过这个。

于 2019-07-18T03:21:43.337 回答
1
if [[ -s somedir ]]; then
    echo "Files present"
fi

在我使用 bash 5.0.17 进行的测试中,如果有任何孩子,[[ -s somedir ]]将返回 true 。somedir也是如此[ -s somedir ]。请注意,如果存在隐藏文件或子目录,这也将返回 true。它也可能依赖于文件系统。

于 2021-04-23T14:49:11.643 回答
0

到目前为止,我还没有看到使用 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 是您选择的变量。

于 2014-08-05T19:11:10.773 回答
0

混合修剪的东西和最后的答案,我得

find "$some_dir" -prune -empty -type d | read && echo empty || echo "not empty"

也适用于带空格的路径

于 2016-03-16T16:26:39.743 回答
0

简单的答案bash

if [[ $(ls /some/dir/) ]]; then echo "huzzah"; fi;
于 2016-04-28T00:56:30.587 回答
0

我会去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
于 2016-05-20T08:57:09.360 回答
0

在另一个线程How to test if a directory is empty with find我提出了这个

[ "$(cd $dir;echo *)" = "*" ] && echo empty || echo non-empty

理由是,$dir 确实存在,因为问题是“从 shell 脚本检查目录是否包含文件”,而且 * 即使在大目录上也没有那么大,在我的系统上 /usr/bin/* 只有 12Kb。

更新:感谢@hh skladby,已修复。

[ "$(cd $dir;echo .* *)" = ". .. *" ] && echo empty || echo non-empty
于 2021-03-07T10:07:42.303 回答
0

无需调用 ls、 find 等工具:

POSIX 安全,即不依赖于您的 Bash / xyz shell / ls / 等版本:

dir="/some/dir"
[ "$(echo $dir/*)x" != "$dir/*x" ] || [ "$(echo $dir/.[^.]*)x" != "$dir/.[^.]*x" ] || echo "empty dir"

想法:

  • echo *列出非点文件
  • echo .[^.]*列出“.”以外的点文件 和 ”..”
  • 如果echo找不到匹配项,则返回搜索表达式,即此处*.[^.]*-两者都不是真正的字符串,并且必须与例如字母连接以强制字符串
  • ||交替短路的可能性:至少有一个非点文件或目录或至少一个点文件或目录或目录为空 - 在执行级别:“如果第一种可能性失败,请尝试下一个,如果失败, 试试下一个"; 从技术上讲,这里 Bash “尝试执行” echo "empty dir",将您对空目录的操作放在这里(例如退出)。

使用符号链接进行检查,但尚未使用更奇特的可能文件类型进行检查。

于 2021-10-06T10:16:34.523 回答
-1
if ls /some/dir/* >/dev/null 2>&1 ; then echo "huzzah"; fi;
于 2008-09-18T10:14:53.520 回答
-1

测试特定的目标目录

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;
于 2013-04-30T19:25:32.853 回答
-1

尝试使用命令查找。指定硬编码的目录或作为参数。然后启动 find 搜索目录内的所有文件。检查 find 的返回是否为空。回显 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
于 2017-03-17T12:08:17.203 回答
-2

我不喜欢ls - A发布的解决方案。您很可能希望测试该目录是否为空,因为您不想删除它。以下是这样做的。但是,如果您只想记录一个空文件,那么删除和重新创建它肯定比列出可能无限的文件更快吗?

这应该工作...

if !  rmdir ${target}
then
    echo "not empty"
else
    echo "empty"
    mkdir ${target}
fi
于 2012-01-21T16:59:58.210 回答
-2

这对我很有效(当 dir 存在时):

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
于 2015-02-04T22:24:30.417 回答