Bash:检查目录是不是仅包含具有特定后缀的文件

Posted

技术标签:

【中文标题】Bash:检查目录是不是仅包含具有特定后缀的文件【英文标题】:Bash: Check if a directory contains only files with a specific suffixBash:检查目录是否仅包含具有特定后缀的文件 【发布时间】:2019-08-24 19:09:26 【问题描述】:

我正在尝试编写一个脚本来检查一个目录是否只包含 特定类型的文件(和/或文件夹),将返回 1 为 false,0 为 true。

IE:我想检查 /my/dir/ 是否只包含 *.gz 文件而不包含其他文件。

这是我目前所拥有的,但它似乎没有按预期工作:

# Basic vars
readonly       THIS_JOB=$0##*/
readonly       ARGS_NBR=1


declare        dir_in=$1


dir_in=$1"/*.gz"
#echo $dir_in

files=$(shopt -s nullglob dotglob; echo ! $dir_in)
echo $files

if (( $#files ))
then
    echo "Success: Directory contains files."
    exit 0
else
    echo "Failure: Directory is empty (or does not exist or is a file)"
    exit 1
fi

【问题讨论】:

【参考方案1】:

有些人建议计算所有与通配符模式*.gz 不匹配的文件。根据文件的数量,这可能非常低效。对于您的工作,只需找到一个与您的通配模式不匹配的文件就足够了。使用find-quite 动作在第一场比赛后退出:

if [ -z "$(find /usr/share/man/man1/* -not -name '*.gz' -print -quit)" ]
then echo only gz
fi

【讨论】:

我认为 -not-quit 不符合 POSIX。 -not 可以简单地替换为 !-quitbusybox 中不存在例如。在这种情况下,由于我们有 bash,我想它可以替换为 -exec bash -c 'kill -PIPE $PPID' \;(或只是 find ... | head -n 1 @jhnc 一个使用 GNU 工具 Bash 的人,可能也使用其他 GNU 工具,并且不关心 POSIX 合规性。 我在 freebsd 上使用 bash,但许多实用程序不是 GNU【参考方案2】:

由于您使用的是 bash,因此您可以使用另一个设置:GLOBIGNORE

#!/bin/bash

containsonly()
    dir="$1"
    glob="$2"

    if [ ! -d "$dir" ]; then
        echo 1>&2 "Failure: directory does not exist"
        return 2
    fi

    local res=$(
        cd "$dir"
        GLOBIGNORE=$glob"
        shopt -s nullglob dotglob
        echo *
    )
    if [ $#res = 0 ]; then
        echo 1>&2 "Success: directory contains no extra files"
        return 0
    else
        echo 1>&2 "Failure: directory contains extra files"
        return 1
    fi


# ...

containsonly myfolder '*.gz'

【讨论】:

【参考方案3】:

使用 Bash 的 extglob!(*.gz)grep

$ if grep -qs . path/!(*.gz) ; then echo yes ; else echo nope ; fi

man grep:

-q, --quiet, --silent
       Quiet;  do  not  write  anything  to  standard   output.    Exit
       immediately  with  zero status if any match is found, even if an
       error was detected.  Also see the -s or --no-messages option.

-s, --no-messages
       Suppress error messages about nonexistent or unreadable files.

【讨论】:

【参考方案4】:

我想检查 /my/dir/ 是否只包含 *.gz 文件而不包含其他文件。

使用find 而不是通配符。使用find 和解析查找输出真的更容易。 Globulation 对于简单脚本来说很简单,但是一旦你想解析“目录中的所有文件”并进行一些过滤等,使用find 会更容易(也更安全):

find "$1" -mindepth 1 -maxdepth 1 \! -name '*.gz' -o \! -type f | wc -l | xargs test 0 -eq

这会在目录中找到所有未命名为 *.gz 或不是文件的“事物”(因此考虑了 mkdir a.gz),对它们进行计数,然后测试它们的计数是否等于 0。如果计数等于 0,xargs test 0 -eq 将返回 0,否则将返回 1 - 125 之间的状态。如果您愿意,可以使用简单的|| return 1 处理非零返回状态。

您可以通过简单的 bash 替换删除 xargs,并使用 this thread 中的方法稍微加快速度并获得 test 返回值,即 01

[ 0 -eq "$(find "$1" -mindepth 1 -maxdepth 1 \! -name '*.gz' -o \! -type f -print '.' | wc -c)" ]

请记住,脚本的退出状态是最后执行的命令的退出状态。因此,如果您愿意,您的脚本中不需要任何其他内容,只需一个 shebang 和这个 oneliner 就足够了。

【讨论】:

不确定你能保证 xargs 会返回 123(freebsd 返回 1),但肯定应该是 1..125 之间的值

以上是关于Bash:检查目录是不是仅包含具有特定后缀的文件的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 Bash 检查文件是不是包含特定字符串

有没有一种好方法可以将文件中具有特定字符(不是文件名)的 .txt 文件移动到另一个目录?

检查传递的参数是不是是 Bash 中的文件或目录

将文件名中具有特定字符串的目录中的所有文件复制到Bash中的不同目录[关闭]

检查字符串是不是仅包含特定字符? [复制]

MySQL 检查表是不是仅包含此特定类型