Bash 脚本:测试空目录

Ant*_*ong 150 bash

我想测试一个目录是否不包含任何文件。如果是这样,我将跳过一些处理。

我尝试了以下方法:

if [ ./* == "./*" ]; then
    echo "No new file"
    exit 1
fi
Run Code Online (Sandbox Code Playgroud)

这给出了以下错误:

line 1: [: too many arguments
Run Code Online (Sandbox Code Playgroud)

有解决方案/替代方案吗?

And*_*pin 199

if [ -z "$(ls -A /path/to/dir)" ]; then
   echo "Empty"
else
   echo "Not Empty"
fi
Run Code Online (Sandbox Code Playgroud)

此外,检查该目录之前是否存在会很酷。

ps

ls -A 表示列出所有但...

  • 当 /path/to/dir 包含空格并且需要引用时,我无法使用此方法。我使用了 `[ $(ls -A "$path" | wc -l) -ne 0]`,受到@ztank1013 的回答的启发。 (4认同)
  • 这会检查目录是否存在,并处理路径中的空格(注意子shell中的嵌套引号):`if [ -d "/path/to/dir" ] && [ -n "$(ls -A "/路径/到/目录")" ]; 然后回显“非空文件夹”否则回显“空或不是文件夹”fi` (3认同)
  • 对于那些正在寻找单行的人: [ "$(ls -A ./path/to/dir)" ] && echo 'NOT EMPTY' || 回显“空” (2认同)
  • 以防万一有人会寻找“正确/稳定”的一个班轮:`[ -z "$(ls -A /path/to/dir)" ] && { echo "Not Empty" ; 你的命令A ; 真的 ; } || {回声“空”;你的命令B ; }`。 (2认同)
  • 老实说,在这一点上,如果是我自己的系统,我只需编写一个快速的 10 行 Python 脚本,将其符号链接到 `/usr/local/bin` 或其他东西,然后像 `if isNotEmpty "$directory"; 这样调用它;然后...fi` (2认同)
  • 不适合我,bash 5.0,来自 coreutils 8.30 的 ls,它返回目录不为空,即使它是空的 (2认同)
  • 如果您想检查目录是否不为空(即与原始问题相反),请将 -z 更改为 -n。 (2认同)
  • 你能解释一下为什么使用“-z”吗?我在本教程中看到 - https://www.cyberciti.biz/faq/linux-unix-shell-check-if-directory-empty/ - 几乎相同的方法,但不使用“-z” (2认同)
  • `adb` 上的 `/sdcard/WhatsApp/.trash/` 为空,但 `-z` 不会检测到空状态,删除 -z 将起作用。`[ -z "$(ls -A /sdcard/WhatsApp/.trash/ ) " ] && echo "there` 没有操作。但是` [ "$(ls -A /sdcard/WhatsApp/.trash/) " ] && echo "there" ` There` 也许你没有想到隐藏的目录。相应地更新答案 (2认同)
  • @user1874594 抱歉,这是非常具体的“adb”。我想让答案更通用 (2认同)
  • @ManuelJordan 检查编辑历史记录。后来添加了“-z”只是为了使其更加明确。 (2认同)

slh*_*hck 33

无需计算任何东西或贝壳球。您也可以readfind. 如果find的输出为空,您将返回false

if find /some/dir -mindepth 1 -maxdepth 1 | read; then
   echo "dir not empty"
else
   echo "dir empty"
fi
Run Code Online (Sandbox Code Playgroud)

这应该是便携式的。

  • PSA 不适用于 `set -o pipefail` (6认同)

uzs*_*olt 25

if [ -n "$(find "$DIR_TO_CHECK" -maxdepth 0 -type d -empty 2>/dev/null)" ]; then
    echo "Empty directory"
else
    echo "Not empty or NOT a directory"
fi
Run Code Online (Sandbox Code Playgroud)

  • 它需要引号 (2x) 和测试 `-n` 是正确和安全的(使用名称中带有空格的目录进行测试,使用名称为 '0 = 1' 的非空目录进行测试)。`... [ -n "$(find "$DIR_TO_CHECK" -maxdepth 0 -type d -empty 2>/dev/null)" ]; ...` (4认同)
  • 写“find "$DIR_TO_CHECK" -maxdepth 0 -type d -empty | 可能更简单 grep .`,并依赖于 grep 的退出状态。无论您采用哪种方式,这都是这个问题的正确答案。 (4认同)
  • @ivan_pozdeev 这不是真的,至少对于 GNU find 来说是这样。您可能会想到“grep”。 https://serverfault.com/questions/225798/can-i-make-find-return-non-0-when-no-matching-files-are-found (2认同)
  • 我喜欢这不需要列出/读取/遍历目录中的所有文件。与基于“ls”的解决方案不同,当目录有大量文件时,这应该工作得更快。 (2认同)
  • 从搜索中发现了这个问题,放弃了糟糕的答案,直到我找到了这个,尝试了一下,发现它不能与 GNU find 一起使用,去添加一条评论以实现这一效果......并发现我已经这样做了两年前。虽然它应该是`grep -q .`。再次感谢乌德瓦里先生! (2认同)

小智 17

#!/bin/bash
if [ -d /path/to/dir ]; then
    # the directory exists
    [ "$(ls -A /path/to/dir)" ] && echo "Not Empty" || echo "Empty"
else
    # You could check here if /path/to/dir is a file with [ -f /path/to/dir]
fi
Run Code Online (Sandbox Code Playgroud)

  • 一定是这样,不需要解析 ls 输出,看看它是否为空。使用 find 对我来说感觉有点矫枉过正。 (4认同)

小智 12

使用 FIND(1)(在 Linux 和 FreeBSD 下),您可以通过“-maxdepth 0”非递归地查看目录条目,并使用“-empty”测试它是否为空。应用于这个问题:

if test -n "$(find ./ -maxdepth 0 -empty)" ; then
    echo "No new file"
    exit 1
fi
Run Code Online (Sandbox Code Playgroud)

  • 它可能不是 100% 便携,但很优雅。 (2认同)
  • 这也会在大型目录中提前完成,与 pipelinefail 一起使用:`set -o pipelinefail; { 查找“$DIR”-min深度 1 ||真的 ; } |头 -n1 |读取 && 回显NOMPTY ||回显空` (2认同)

Dan*_*eck 6

使用以下内容:

count="$( find /path -mindepth 1 -maxdepth 1 | wc -l )"
if [ $count -eq 0 ] ; then
   echo "No new file"
   exit 1
fi
Run Code Online (Sandbox Code Playgroud)

这样,您就独立于ls. -mindepth跳过目录本身,-maxdepth防止递归防御子目录以加快速度。


zta*_*013 5

这将在当前工作目录 (.) 中完成工作:

[ `ls -1A . | wc -l` -eq 0 ] && echo "Current dir is empty." || echo "Current dir has files (or hidden files) in it."
Run Code Online (Sandbox Code Playgroud)

或将相同的命令拆分为三行以提高可读性:

[ `ls -1A . | wc -l` -eq 0 ] && \
echo "Current dir is empty." || \
echo "Current dir has files (or hidden files) in it."
Run Code Online (Sandbox Code Playgroud)

如果您需要在不同的目标文件夹上运行它,只需替换 ls -1A . | wc -lls -1A <target-directory> | wc -l

编辑:我替换-1a-1A(见@Daniel 评论)

  • 它不会受到伤害,但如果不将其输出到终端,则暗示了这一点。由于您将其通过管道传输到另一个程序,因此它是多余的。 (3认同)
  • 改用`ls -A`。根据文档,某些文件系统没有 `.` 和 `..` 符号链接。 (2认同)
  • 谢谢@Daniel,我根据您的建议编辑了我的答案。我知道“1”也可能被删除。 (2认同)
  • `-1` 绝对是多余的。即使“ls”在通过管道传输时不会每行打印一项,也不会影响检查它是否生成零行或多行的想法。 (2认同)

gle*_*man 5

使用数组:

files=( * .* )
if (( ${#files[@]} == 2 )); then
    # contents of files array is (. ..)
    echo dir is empty
fi
Run Code Online (Sandbox Code Playgroud)

  • 非常好的解决方案,但请注意,它需要 `shopt -s nullglob` (6认同)
  • `${#files[@]} == 2` 假设并不代表根目录(您可能不会测试它是否为空,但某些不知道该限制的代码可能会测试)。 (3认同)
  • @ivan_pozdeev:你是什么意思?当我执行 cd / &amp;&amp; files=(* .*)`` 时,我得到根目录中所有文件和目录的枚举,其中包括 **`.`** 和 **`..`* *。所以``${#files[@]} == 2`` 测试是有效的。 (2认同)

Alo*_*dal 5

一种hacky,但只支持bash,无PID的方式:

is_empty() {
    test -e "$1/"* 2>/dev/null
    case $? in
        1)   return 0 ;;
        *)   return 1 ;;
    esac
}
Run Code Online (Sandbox Code Playgroud)

这利用了以下事实:test如果在 之后给出多个参数,则内置函数以 2 退出-e:首先,"$1"/*bash 扩展了 glob。这导致每个文件有一个参数。所以

  • 如果没有文件,则中的星号test -e "$1"*不会扩展,因此 Shell 会回退到尝试文件 named *,该文件返回 1。

  • ...除非实际上有一个文件名为 exact *,然后星号扩展为好,星号,最终与上述调用相同,即。test -e "dir/*",只是这次返回 0。(感谢 @TrueY 指出这一点。)

  • 如果有一个文件,test -e "dir/file"则运行,返回 0。

  • 但是如果文件多于 1,test -e "dir/file1" "dir/file2" 则运行,bash 将其报告为使用错误,即 2。

case 包装整个逻辑,以便只有第一种情况,退出状态为 1 报告为成功。

我没有检查过的可能问题:

  • 文件数量多于允许的参数数量——我想这可能与 2+ 个文件的情况类似。

  • 或者实际上有一个空名称的文件——我不确定在任何正常的 OS/FS 上是否可行。

  • 小修正:如果 dir/ 中没有文件,则调用 `test -e dir/*`。如果 dir 中唯一的文件是“*”,则 test 将返回 0。如果有更多文件,则返回 2。所以它的工作原理如下。 (2认同)
  • 如果目录包含名为“*”的单个文件,则此操作将不起作用。这是一个病态的案例,但我见过更糟糕的情况。 (2认同)

小智 5

如何测试目录是否存在并且在一个 if 语句中不为空

if [[ -d path/to/dir && -n "$(ls -A path/to/dir)" ]]; then 
  echo "directory exists"
else
  echo "directory doesn't exist"
fi
Run Code Online (Sandbox Code Playgroud)