我有以下案例:
我想检查目录 $1
中的文件直到其中一个满足我的条件。
详细说明:我想测试目录是否包含音频文件。一旦找到第一个音频文件,process_audio_dir
就应该发生;如果目录中没有音频文件,则会发生process_noaudio
。
到目前为止我的解决方案:
if [[ -z $(file -b "$1"/* | grep -i audio) ]]; then
echo "there are no audio files"; process_noaudio
else
echo "at least one audio file"; process_audio_dir
fi
file -b
告诉我文件的文件类型。
我用 set -x
观察它的猜测是,这将在所有文件上运行 file -b
,将结果放在一行中并 greps一场比赛的行。 (也许这是一个错误的假设)。
我宁愿有一个循环,直到它找到第一个音频文件(一个足以匹配条件)并在那里停止/中断,或者,如果没有音频文件,继续 process_noaudio
.
我觉得 while/until 是实现这一目标的方法,但我想不通。
检查目录中每个文件直到第一个匹配项的(您的首选|最佳实践|最优雅|成本最低|最快)方法是什么?
最佳答案
可能最安全的方法是直接迭代 glob 结果,这样您就不会受到包含特殊字符的文件名的攻击:
for path in "$1"/*; do
if file -b -- "$path" | grep -qi audio; then
printf 'Found an audio file %s\n' "$path"
process_audio_dir
exit
fi
done
# since we didn't exit above, most be no audio files
printf "Didn't find any audio files\n"
process_noaudio
或者,如果你不想在那里退出,你可以设置一个标志表明你找到了它并在循环后检查它,并且只需在 if 中使用一个
找到一个后退出循环。break
您将 grep
应用于所有 file
结果的输出的原因是 glob 首先扩展,因此您然后运行命令,例如
file -b dir/file1 dir/file2 dir/file3 ...
然后该命令的输出将被馈送到 grep
我的解决方案将 glob 放在命令的“外部”,因此我们将在每个文件上单独运行它。当然,多次启动 file
会产生更多的开销,所以我现在还不清楚哪个会更有效率。这可能取决于有多少文件,第一个音频文件通常在列表中的位置等等。
正如评论中所提到的,从 find
或 ls
中遍历打印的文件名结果是危险的,因为这些结果会受到分词和潜在的影响通配符取决于您的操作方式。通常推荐使用上面的 for
循环。有关更多信息,请参阅 Don't Parse ls
关于bash:迭代目录内容直到条件匹配的最佳实践,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40822725/