bash for循环与GNU" ls -v"相同的顺序("版本号"排序)

时间:2017-11-07 23:57:11

标签: bash for-loop

在bash脚本中,我想在somedir"中做一个典型的" for文件。但我希望文件的处理顺序与" ls -v"归还他们。我知道使用" ls"作为一个功能。有没有办法复制" -v"没有使用" ls"?感谢。

1 个答案:

答案 0 :(得分:3)

假设这是"版本号"排序顺序,这也是由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"/*替换当前上下文中的参数列表(该上下文是运行进程替换的子shell!),结果为"$somedir"/*;因此,(默认情况下为非隐藏)变量somedir中命名的目录的内容。
  • 只有当glob扩展到至少一个项目时,
  • [[ -e $1 || -L $1 ]]才为真;如果它仍然是*(并且该名称不存在实际的文件系统对象),则此条件下的门控输出会阻止进程替换发出任何输出。
  • sort -z告诉sort用NUL分隔输入和输出中的元素 - 一个不允许存在于文件名中的字符。