bash:迭代目录内容直到条件匹配的最佳实践

标签 bash loops iteration

我有以下案例:

我想检查目录 $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 会产生更多的开销,所以我现在还不清楚哪个会更有效率。这可能取决于有多少文件,第一个音频文件通常在列表中的位置等等。

正如评论中所提到的,从 findls 中遍历打印的文件名结果是危险的,因为这些结果会受到分词和潜在的影响通配符取决于您的操作方式。通常推荐使用上面的 for 循环。有关更多信息,请参阅 Don't Parse ls

关于bash:迭代目录内容直到条件匹配的最佳实践,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40822725/

相关文章:

loops - Tomcat 无限重定向循环

javascript - 嵌套 for 循环和多维数组

php - Sql 多链表

java - 将从文本文件读取的字符串拆分为二维字符数组

linux - 使用 linux 删除文件名中的第一个单词

linux - find 命令在 zsh 和 bash 中的工作方式不同

linux - 可能 "loop"和 "output"在我的 bash 脚本中无法正常工作

javascript - 从具有相似值的对象数组中获取所有对象

linux - grep 有问题

linux - 在期待交互命令时出现异常