在bash脚本中,我想做一个典型的"for file In somedir",但我希望文件的处理顺序与"ls-v"返回文件的顺序相同。我知道使用"ls"作为函数的缺点。有没有办法在不使用"ls"的情况下复制"-v"?谢谢
假设这是"版本号"排序顺序,这也是由GNUsort
实现的。因此,在GNU平台上:
somedir=/foo
while IFS= read -r -d '' filename; do
printf 'Processing file: %qn' "$filename"
done < <(set -- "$somedir"/*; [[ -e $1 || -L $1 ]] && printf '%s ' "$@" | sort -z -V)
如果真的想使用for
循环而不是while
循环,那么解析成一个数组并迭代:
files=( )
while IFS= read -r -d '' filename; do
files+=( "$filename" )
done < <(set -- "$somedir"/*; [[ -e $1 || -L $1 ]] && printf '%s ' "$@" | sort -z -V)
for filename in "${files[@]}"; do
printf 'Processing file: %qn' "$filename"
done
解释上面的一些魔术:
- 在
< <(...)
中,<(...)
是过程替换。它被替换为一个文件名,当从中读取时,该文件名将返回所附代码的输出。因此,< <(...)
将把该过程替换的输出作为while read
循环的输入。BashFAQ#1中描述了这种循环形式。使用这种重定向而不是管道进入循环的原因在BashFAQ#24中给出 set -- "$somedir"/*
用"$somedir"/*
的结果替换当前上下文中的参数列表(该上下文是运行进程替换的子shell!);因此,变量somedir
中命名的目录的内容(默认为非隐藏)- 只有当该glob扩展到至少一个项时,
[[ -e $1 || -L $1 ]]
才为真;如果它仍然是*
(并且不存在以该名称命名的实际文件系统对象),则在此条件下选通输出将阻止进程替换发出任何输出 sort -z
告诉sort
用NUL(文件名中不允许存在的字符)来分隔输入和输出中的元素