如果目录包含文件,则从shell脚本进行检查

时间:2008-09-18 10:05:52

标签: bash unix shell

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

与此类似的东西

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

但是如果目录包含一个或多个文件(上面的文件仅适用于0或1个文件),则可以使用。

28 个答案:

答案 0 :(得分:121)

三个最好的技巧


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

注意:空目录和不存在目录之间没有区别(即使提供的路径是文件)。

'official' FAQ for #bash IRC channel上有一个类似的替代方案和更多细节(以及更多示例):

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's article。添加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

或单行基础版:

[[ $(ls -A your/dir) ]] && echo "contains files" || echo "empty"

注意: ls在目录不存在时返回$?=2。但是文件和空目录之间没有区别。


[ -n "$(find your/dir -prune -empty)" ]

最后一招是受gravstar's answer启发,其中-maxdepth 0-prune取代,并由phils的评论改进。

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

最后一段代码适用于大多数情况,但要注意恶意路径可以表达命令......

答案 1 :(得分:61)

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

#!/bin/bash
shopt -s nullglob dotglob     # To include hidden files
files=(/some/dir/*)
if [ ${#files[@]} -gt 0 ]; then echo "huzzah"; fi

答案 2 :(得分:48)

以下内容如何:

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

这样就不需要生成目录内容的完整列表。 read是放弃输出并仅在读取内容时使表达式求值为true(即/some/dir/发现find为空。

答案 3 :(得分:19)

尝试:

if [ ! -z `ls /some/dir/*` ]; then echo "huzzah"; fi

答案 4 :(得分:14)

# 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
}

答案 5 :(得分:13)

注意包含大量文件的目录!评估ls命令可能需要一些时间。

IMO最好的解决方案是使用

的解决方案
find /some/dir/ -maxdepth 0 -empty

答案 6 :(得分:9)

DIR="/some/dir"
if [ "$(ls -A $DIR)" ]; then
     echo 'There is something alive in here'
fi

答案 7 :(得分:6)

你能比较一下吗?

 ls -A /some/dir | wc -l

答案 8 :(得分:4)

# 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标记。

答案 9 :(得分:3)

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

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

答案 10 :(得分:2)

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

if find /path/to/check/* -maxdepth 0 -type f | read
  then echo "Files Exist"
fi

答案 11 :(得分:1)

Bruno's answer的小变化:

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

它对我有用

答案 12 :(得分:1)

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(或大括号扩展):

$ 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),匹配" full" (非空)目录:

$ 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)列出匹配的对象:是目录AND不为空。因此,(^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)("空目录和#34;)的匹配项,因此会发出错误消息,指出找不到匹配的glob。因此,我们需要使用(N) glob限定符来抑制这些可能的错误消息:

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

因此,对于非空目录,我们需要限定符(N/^F),您可以将其读作:&#34;不要警告我有关失败的信息,不完整的目录&#34;。< / p>

同样,对于空目录,我们需要限定符(NF),我们也可以将其视为:&#34;不要警告我有关失败,完整目录&#34;。

答案 13 :(得分:1)

dir_is_empty() {
   [ "${1##*/}" = "*" ]
}

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

假设您没有名为*的文件到/any/dir/you/check,它应该适用于bash dash posh busybox sh和{ {1}}但是(对于zsh)需要zsh

性能应该与使用unsetopt nomatch(glob)的任何ls相媲美,我想在有很多节点的目录上会很慢(我的*有3000多个文件并没有那么慢),将使用至少足够的内存来分配所有目录/文件名(以及更多),因为它们都作为参数传递(解析)到函数中,某些shell可能对参数数量和/或参数长度有限制。

检查目录是否为空的便携式快速O(1)零资源方式将是很好的。

<强>更新

以上版本不考虑隐藏文件/目录,以防需要进行更多测试,例如来自Rich’s sh (POSIX shell) tricks/usr/bin

is_empty

但是,相反,我正在考虑这样的事情:

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为空时跟踪参数和查找输出的斜线差异有些担忧,并且尾随换行符(但这应该很容易处理),遗憾的是我的dir_is_empty() { [ "$(find "$1" -name "?*" | dd bs=$((${#1}+3)) count=1 2>/dev/null)" = "$1" ] } busybox显示了什么可能是sh管道上的错误,输出被随机截断(如果我使用find -> dd输出总是相同的,似乎cat带有参数dd

答案 14 :(得分: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

只是dirs:

$ 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

答案 15 :(得分:0)

if [[ -s somedir ]]; then
    echo "Files present"
fi

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

答案 16 :(得分:0)

尝试使用命令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

答案 17 :(得分:0)

通过一些解决方法,我可以找到一种简单的方法来查找目录中是否有文件。使用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

答案 18 :(得分:0)

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

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

由于它创建了一个子shell,因此它与我所能想到的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),但最坏情况是目录大小呈线性。我还没有测量。

答案 19 :(得分:0)

在另一个话题 How to test if a directory is empty with find 中我提出了这个

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

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

答案 20 :(得分:0)

bash的简单回答

app.UseMvc(routes =>
{
    routes.MapRoute(
      name: "areaRoute",
      template: "{area:exists}/{controller}/{action}");


    routes.MapRoute(
      name: "default",
      template: "{area=Doctors}/{controller=Home}/{action=Index}");
});

答案 21 :(得分:0)

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

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

适用于带空格的路径

答案 22 :(得分:0)

到目前为止,我还没有看到使用grep的答案,我认为这会给出更简单的答案(没有太多奇怪的符号!)。这就是我的意思 使用bourne shell检查目录中是否存在任何文件:

这将返回目录中的文件数:

ls -l <directory> | egrep -c "^-"

您可以填写编写目录的目录路径。管道的前半部分确保输出的第一个字符是&#34; - &#34;对于每个文件。然后egrep计算以该开头的行数 使用正则表达式的符号现在你所要做的就是存储你获得的数字,并使用反引号进行比较,如:

 #!/bin/sh 
 fileNum=`ls -l <directory> | egrep -c "^-"`  
 if [ $fileNum == x ] 
 then  
 #do what you want to do
 fi

x是您选择的变量。

答案 23 :(得分:0)

我很惊讶wooledge guide on empty directories没有被提及。对于shell类型的问题,本指南以及所有的wooledge都是必读的。

该页面的注释:

  

永远不要尝试解析ls输出。即使是ls -A解决方案也可能中断(例如,在HP-UX上,如果你是root用户,那么-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:实际上没有这样的文件或目录   这样的测试是必需的。

答案 24 :(得分:0)

if ls /some/dir/* >/dev/null 2>&1 ; then echo "huzzah"; fi;

答案 25 :(得分:-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;

答案 26 :(得分:-1)

我不喜欢发布的ls - A解决方案。您很可能希望测试目录是否为空,因为您不希望将其删除。以下是这样的。但是,如果您只想记录一个空文件,请确保删除并重新创建它更快,然后列出可能无限的文件?

这应该有用......

if !  rmdir ${target}
then
    echo "not empty"
else
    echo "empty"
    mkdir ${target}
fi

答案 27 :(得分:-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