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

ion*_*onn 105 unix bash shell

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

类似的东西

if [ -e /some/dir/* ]; then echo "huzzah"; fi;
Run Code Online (Sandbox Code Playgroud)

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

oli*_*bre 132

三个最好的技巧


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
Run Code Online (Sandbox Code Playgroud)

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

#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
Run Code Online (Sandbox Code Playgroud)

[ -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
Run Code Online (Sandbox Code Playgroud)

或单行基础版本:

[[ $(ls -A your/dir) ]] && echo "contains files" || echo "empty"
Run Code Online (Sandbox Code Playgroud)

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


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

这最后绝招是从灵感gravstar的答案在那里-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
Run Code Online (Sandbox Code Playgroud)

变种使用-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
Run Code Online (Sandbox Code Playgroud)

说明:

  • find -prunefind -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
Run Code Online (Sandbox Code Playgroud)

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

  • 我认为你可以将find选项简化为`[-n"$(find"your/dir"-prune -empty)"]`,以避免重复目录路径. (2认同)
  • 好吧,我发表评论的主要动机是因为感觉到不一致(因为“-n”变体出现在标题中,但不在下面的段落中)。所以,是的,没关系。 (2认同)
  • 我正在使用您的 -n 解决方案,但我的脚本仍然抱怨此“ls:无法访问'/path':没有这样的文件或目录”。有什么办法可以抑制这个消息吗?我愿意在那里默默地失败。 (2认同)

Bru*_*ine 63

该解决方案使用至今ls.这是一个全bash解决方案:

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

  • 为什么不使用子shell重置设置:`files = $(shopt -s nullglob; shopt -s dotglob; echo/some/dir/*)` (10认同)
  • 只要你记得在脚本结尾处将选项设置回原始值:) (8认同)
  • @teambob如果使用子shell:`files = $(shopt -s nullglob; shopt -s dotglob; echo/some/dir/*)`那么if语句应该改为`if [$ {#files} -gt 0];`或者你可能只是忘记了子shell命令周围的()?`files =($(shopt -s nullglob; shopt -s dotglob; echo/some/dir/*))` (6认同)
  • @stoutyhk $(...)恢复设置,不需要单独的子shell.使用$(...)生成一个shell的新实例.命令完成后,该新实例的环境将被丢弃.编辑:找到参考tldp.org/LDP/abs/html/commandsub.html"命令替换调用子shell." (2认同)

mwe*_*den 48

以下内容如何:

if find /some/dir/ -maxdepth 0 -empty | read v; then echo "Empty dir"; fi
Run Code Online (Sandbox Code Playgroud)

这样就不需要生成目录内容的完整列表.这read两者都是为了丢弃输出并使表达式仅在读取某些内容时被评估为真(即被/some/dir/发现为空find).

  • 然而,它确实依赖于非标准的`-maxdepth`和`-empty`原色. (7认同)
  • +1这是最优雅的解决方案.它不涉及解析`ls`输出,也不依赖于非默认的shell特性. (5认同)
  • 或者只是`find/some/dir/-maxdepth 0 -empty -exec echo"huzzah"\;` (3认同)

Gre*_*ill 21

尝试:

if [ ! -z `ls /some/dir/*` ]; then echo "huzzah"; fi
Run Code Online (Sandbox Code Playgroud)

  • 您可以使用`-n`代替`!-z`(它们都是等价的,但为什么不在它存在时使用较短的形式). (4认同)
  • 对于像我这样的 Bash 白痴,如果你想检查相反的 - 目录是空的 - 只需使用 if [ -z `ls /some/dir/*` ]; 然后回声“huzzah”;菲 (2认同)

小智 14

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

IMO最好的解决方案就是使用它

find /some/dir/ -maxdepth 0 -empty
Run Code Online (Sandbox Code Playgroud)


小智 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
}
Run Code Online (Sandbox Code Playgroud)


And*_*lor 9

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


DGM*_*DGM 5

你能比较一下它的输出吗?

 ls -A /some/dir | wc -l
Run Code Online (Sandbox Code Playgroud)


小智 5

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

if find /path/to/check/* -maxdepth 0 -type f | read
  then echo "Files Exist"
fi
Run Code Online (Sandbox Code Playgroud)


Dai*_*shi 5

这告诉我该目录是否为空,如果不是,它包含的文件和目录的数量。

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
Run Code Online (Sandbox Code Playgroud)

警告:如果目录不存在,此命令将失败。

  • 我没有对此投反对票,但猜测这是因为您正在[解析“ls”的输出](http://mywiki.wooledge.org/ParsingLs)。 (2认同)

Zor*_*war 5

中兴

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

测试非空目录

检查是否foo非空:

$ for i in foo(NF) ; do ... ; done
Run Code Online (Sandbox Code Playgroud)

其中,如果foo非空,for则将执行块中的代码。

测试空目录

检查是否foo为空:

$ for i in foo(N/^F) ; do ... ; done
Run Code Online (Sandbox Code Playgroud)

其中,如果为空,则将执行块foo中的代码。for

笔记

我们不需要引用foo上面的目录,但如果需要的话我们可以这样做:

$ for i in 'some directory!'(NF) ; do ... ; done
Run Code Online (Sandbox Code Playgroud)

我们还可以测试多个对象,即使它不是一个目录:

$ 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
Run Code Online (Sandbox Code Playgroud)

任何不是目录的内容都将被忽略。

附加功能

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

$ 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
Run Code Online (Sandbox Code Playgroud)

我们还可以检查放置在数组中的对象。以上述目录为例:

$ 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
Run Code Online (Sandbox Code Playgroud)

因此,我们可以测试可能已经在数组参数中设置的对象。

请注意,显然,块中的代码for是依次在每个目录上执行的。如果这不合需要,那么您可以简单地填充一个数组参数,然后对该参数进行操作:

$ for i in *(NF) ; do full_directories+=($i) ; done
$ do_something $full_directories
Run Code Online (Sandbox Code Playgroud)

解释

对于 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/
Run Code Online (Sandbox Code Playgroud)

限定符(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
Run Code Online (Sandbox Code Playgroud)

因此,要检查给定目录是否为空,您可以运行:

$ mkdir X
$ for i in X(/^F) ; do echo $i ; done ; echo "finished"
X
finished
Run Code Online (Sandbox Code Playgroud)

只是为了确保不会捕获非空目录:

$ mkdir Y
$ touch Y/.f
$ for i in Y(/^F) ; do echo $i ; done ; echo "finished"
zsh: no matches found: Y(/^F)
finished
Run Code Online (Sandbox Code Playgroud)

哎呀!由于Y不为空,zsh 找不到(/^F)(“空目录”)的匹配项,因此会输出一条错误消息,指出未找到 glob 的匹配项。因此,我们需要使用(N)glob 限定符来抑制这些可能的错误消息:

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

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

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