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
可以简单地替换为 !
但 -quit
在 busybox
中不存在例如。在这种情况下,由于我们有 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
返回值,即 0
或 1
:
[ 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:检查目录是不是仅包含具有特定后缀的文件的主要内容,如果未能解决你的问题,请参考以下文章
有没有一种好方法可以将文件中具有特定字符(不是文件名)的 .txt 文件移动到另一个目录?