![如何反转 for 循环?](https://linux22.com/image/19814/%E5%A6%82%E4%BD%95%E5%8F%8D%E8%BD%AC%20for%20%E5%BE%AA%E7%8E%AF%EF%BC%9F.png)
我如何适当地以相反的顺序循环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
替代方案。你也可以检查一下。
我可能遗漏了一些东西,所以其他人应该插话。