如何反转 for 循环?

use*_*686 29 shell bash zsh wildcards control-flow

我如何正确地for以相反的顺序进行循环?

for f in /var/logs/foo*.log; do
    bar "$f"
done
Run Code Online (Sandbox Code Playgroud)

我需要一个不会因文件名中的时髦字符而中断的解决方案。

Gil*_*il' 32

在 bash 或 ksh 中,将文件名放在一个数组中,并以相反的顺序遍历该数组。

files=(/var/logs/foo*.log)
for ((i=${#files[@]}-1; i>=0; i--)); do
  bar "${files[$i]}"
done
Run Code Online (Sandbox Code Playgroud)

如果ksh_arrays设置了该选项(在 ksh 仿真模式下),上面的代码也适用于 zsh 。zsh 中有一个更简单的方法,就是通过 glob 限定符反转匹配的顺序:

for f in /var/logs/foo*.log(On); do bar $f; done
Run Code Online (Sandbox Code Playgroud)

POSIX 不包含数组,因此如果您想要可移植,直接存储字符串数组的唯一选择是位置参数。

set -- /var/logs/foo*.log
i=$#
while [ $i -gt 0 ]; do
  eval "f=\${$i}"
  bar "$f"
  i=$((i-1))
done
Run Code Online (Sandbox Code Playgroud)


小智 9

试试这个,除非你认为换行符是“时髦的字符”:

ls /var/logs/foo*.log | tac | while read f; do
    bar "$f"
done
Run Code Online (Sandbox Code Playgroud)

  • 如果文件名包含换行符、反斜杠或不可打印的字符,则会中断。请参阅 http://mywiki.wooledge.org/ParsingLs 和 [如何遍历文件的行?](http://unix.stackexchange.com/q/7011)(以及链接的线程)。 (4认同)

ACK*_*low 5

如果有人试图弄清楚如何反向迭代以空格分隔的字符串列表,那么这是可行的:

reverse() {
  tac <(echo "$@" | tr ' ' '\n') | tr '\n' ' '
}

list="a bb ccc"

for i in `reverse $list`; do
  echo "$i"
done
> ccc
> bb 
> a
Run Code Online (Sandbox Code Playgroud)

  • 我的系统上没有 tac;我不知道它是否强大,但我一直在 ${mylist}; 中使用 for x; 做 revv="${x} ${revv}"; 完毕 (2认同)