如何反转 for 循环?

如何反转 for 循环?

我如何适当地以相反的顺序循环for

for f in /var/logs/foo*.log; do
    bar "$f"
done

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

答案1

在 bash 或 ksh 中,将文件名放入数组中,然后以相反的顺序迭代该数组。

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

如果设置了该选项,上面的代码也可以在 zsh 中运行ksh_arrays(处于 ksh 模拟模式)。 zsh 中有一个更简单的方法,即通过 glob 限定符反转匹配的顺序:

for f in /var/logs/foo*.log(On); do bar $f; done

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

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

答案2

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

ls /var/logs/foo*.log | tac | while read f; do
    bar "$f"
done

答案3

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

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

list="a bb ccc"

for i in `reverse $list`; do
  echo "$i"
done
> ccc
> bb 
> a

答案4

find /var/logs/ -name 'foo*.log' -print0 | tail -r | xargs -0 bar

应该按照你想要的方式操作(这是在 Mac OS X 上测试的,我在下面有一个警告......)。

从查找的手册页中:

-print0
         This primary always evaluates to true.  It prints the pathname of the current file to standard output, followed by an ASCII NUL character (charac-
         ter code 0).

基本上,您正在查找与字符串 + glob 匹配的文件,并以 NUL 字符终止每个文件。如果您的文件名包含换行符或其他奇怪的字符, find 应该可以很好地处理这个问题。

tail -r

通过管道获取标准输入并将其反转(注意tail -r打印全部stdout 的输入,而不仅仅是最后 10 行,这是标准默认值。man tail了解更多信息)。

然后我们将其通过管道传输到xargs -0

-0      Change xargs to expect NUL (``\0'') characters as separators, instead of spaces and newlines.  This is expected to be used in concert with the
         -print0 function in find(1).

在这里, xargs 期望看到由 NUL 字符分隔的参数,您从 传递该参数find并用 反转tail

我的警告:我读过,它tail不能很好地处理以空结尾的字符串。这在 Mac OS X 上运行良好,但我不能保证所有 *nix 都是如此。小心行事。

我还应该提到的是GNU 并行经常被用作xargs替代方案。你也可以检查一下。

我可能遗漏了一些东西,所以其他人应该插话。

相关内容