测试目录中是否存在所有三种文件类型

测试目录中是否存在所有三种文件类型

.png我想检测目录、.txt和中是否存在以下每种文件类型之一.tar.gz

测试其中两个时,以下工作正常

shopt -s nullglob
MYDIR=/some_dir
if [ $MYDIR/*.png] && [ $MYDIR/*.txt]; then
  echo "All files present"
else
  echo "At least one type is missing"
fi

但是如果我尝试使用来测试所有三个

if [ $MYDIR/*.png] && [ $MYDIR/*.txt] && [ $MYDIR/*.tar.gz]; then
...

或使用

if [[ $MYDIR/*.png && $MYDIR/*.txt && $MYDIR/*.tar.gz ]]; then
...

那么我没有得到正确的行为(即使其中一个文件丢失,它仍然返回 true)。

这里发生了什么?

答案1

您无法测试文件名通配模式是否匹配使用(并且在所有测试中[ ... ]最后一个之前都缺少空格,因此您的代码无论如何都无法工作)。][ ... ]

方法是执行匹配并计算匹配名称的数量。

shopt -s nullglob    # make globs expand to nothing if they don't match
shopt -s dotglob     # also match hidden names

error=false
for ext in png txt tar.gz; do
    set -- "$MYDIR"/*."$ext"
    if [ "$#" -eq 0 ]; then
        printf 'Nothing matches "%s"\n' "$MYDIR/*.$ext" >&2
        error=true
        break  # possibly, unless you want the user to see all patterns that fail
    fi
done

if "$error"; then
    echo 'Can not continue' >&2
    exit 1
fi

如果您觉得想要输入更多内容(或者只需要保留现有的位置参数列表),您可以使用命名数组。将set --行改为names=( "$MYDIR"/*."$ext" )"$#"改为"${#names[@]}"。请注意,所有引号都很重要。

答案2

你绝对需要使用:

shopt -s nullglob

在测试之前避免出现误报,就像$MYDIR/*.png字面意思一样。

但是你不能在 bash 测试中测试这样的通配符,你需要测试数组:

txt=( *.txt ) tgz=( *.tar.gz ) png=( *.png )
if [[ ${txt[@]} && ${png[@]} && ${tgz[@]} ]]; then
    echo SUCCESS
fi

使用 hack 测试通配符是否存在的另一种方法compgen

cd "$workdir"
if (compgen -W *.txt && compgen -W *.png && compgen -W *.tar.gz) &>/dev/null; then
    echo 'SUCCESS'
else
    echo >&2 'At least one filetype missed'
fi

不要忘记添加 bash 的 shebang:

#!/bin/bash

或者

#!/usr/bin/env bash

[[是一个 bash 关键字,类似于(但比)[命令更强大。看http://mywiki.wooledge.org/BashFAQ/031http://mywiki.wooledge.org/BashGuide/TestsAndConditionals。除非你是为 POSIX sh 编写,否则我建议[[

使用示例:

 [[ ${names[@]} ]] && echo 'SUCCESS'

无需像您尝试的那样计算出现的次数。

相关内容