![测试目录中是否存在所有三种文件类型](https://linux22.com/image/224517/%E6%B5%8B%E8%AF%95%E7%9B%AE%E5%BD%95%E4%B8%AD%E6%98%AF%E5%90%A6%E5%AD%98%E5%9C%A8%E6%89%80%E6%9C%89%E4%B8%89%E7%A7%8D%E6%96%87%E4%BB%B6%E7%B1%BB%E5%9E%8B.png)
.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/031和http://mywiki.wooledge.org/BashGuide/TestsAndConditionals。除非你是为 POSIX sh 编写,否则我建议[[
使用示例:
[[ ${names[@]} ]] && echo 'SUCCESS'
无需像您尝试的那样计算出现的次数。