bash for 循环的顺序与 GNU "ls -v"("version-number"排序相同)

标签 bash for-loop

在 bash 脚本中,我想做一个典型的“for file in somedir”,但我希望按照“ls -v”返回文件的相同顺序处理文件。我知道使用“ls”作为函数的缺点。有没有办法在不使用“ls”的情况下复制“-v”?谢谢。

最佳答案

假设这是“版本号”排序顺序,这也是 GNU 实现的 sort 。因此,在 GNU 平台上:

somedir=/foo
while IFS= read -r -d '' filename; do
  printf 'Processing file: %q\n' "$filename"
done < <(set -- "$somedir"/*; [[ -e $1 || -L $1 ]] && printf '%s\0' "$@" | sort -z -V)

如果您真的想要使用for循环而不是while循环,解析为数组并迭代它:

files=( )
while IFS= read -r -d '' filename; do
  files+=( "$filename" )
done < <(set -- "$somedir"/*; [[ -e $1 || -L $1 ]] && printf '%s\0' "$@" | sort -z -V)

for filename in "${files[@]}"; do
  printf 'Processing file: %q\n' "$filename"
done

解释上面的一些魔法:

  • < <(...) , <(...)流程替换。它被替换为一个文件名,当读取该文件名时,将返回所包含代码的输出。因此,< <(...)将该进程替换的输出作为 while read 的输入环形。此循环形式在BashFAQ #1中描述。 。 BashFAQ #24 中给出了使用这种重定向而不是通过管道进入循环的原因。 .
  • set -- "$somedir"/*"$somedir"/* 的结果替换当前上下文中的参数列表(该上下文是运行进程替换的子 shell!) ;因此,(默认情况下,非隐藏)变量 somedir 中指定的目录的内容.
  • [[ -e $1 || -L $1 ]]仅当该 glob 扩展到至少一项时才为 true;如果仍然存在* (并且不存在具有该名称的实际文件系统对象),在这种情况下控制输出可以防止进程替换发出任何输出。
  • sort -z告诉sort使用 NUL 来分隔输入和输出中的元素 - NUL 是不允许存在于文件名中的字符。

关于bash for 循环的顺序与 GNU "ls -v"("version-number"排序相同),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47169365/

相关文章:

linux - 如何为 Redhat Linux bash shell 编写 shell 脚本

c++ - 将bash参数传递给C++

mysql - 在 Terraform 中使用 Bash 连接到 MySQL 失败但通过 SSH 工作

java - 如何在执行主类时使 bash 自动完成 java 限定类名

JavaScript 从嵌套对象中获取值

regex - 使用 Bash 从文件名中的特定位置移动数字

c++ - 如何在不遍历全长的情况下仅将数组迭代到填充的位置

c++ - 基于范围的声明的正确样式

c++ - C++ 中的矩阵库与 For 循环

替换数据框列表中的列值