Answers:
在bash或ksh中,将文件名放入一个数组中,并以相反的顺序遍历该数组。
files=(/var/logs/foo*.log)
for ((i=${#files[@]}-1; i>=0; i--)); do
bar "${files[$i]}"
done
如果ksh_arrays
设置了该选项(在ksh仿真模式下),则上面的代码也可以在zsh中工作。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
i
和了f
。只是执行shift
,使用$1
为您的来电bar
,并测试[ -z $1 ]
你的while
。
[ -z $1 ]
也不[ -z "$1" ]
是有用的测试(参数为*
还是空字符串会怎样?)。无论如何,它们都无济于事:问题是如何以相反的顺序循环。
除非您认为换行符是“笨拙的字符”,否则请尝试以下操作:
ls /var/logs/foo*.log | tac | while read f; do
bar "$f"
done
f
在我的情况下,投票率最高的答案打破了变数。不过,这个答案几乎可以替代普通产品for
线。
如果有人试图弄清楚如何对以空格分隔的字符串列表进行反向迭代,则可以这样做:
reverse() {
tac <(echo "$@" | tr ' ' '\n') | tr '\n' ' '
}
list="a bb ccc"
for i in `reverse $list`; do
echo "$i"
done
> ccc
> bb
> a
tac
GNU coreutils的一部分一样令人震惊。但是您的解决方案也是一个很好的解决方案。
tac
。尽管从tac
这里的-less响应数量来看,我猜想OSX可能没有tac。在这种情况下,请使用@arp解决方案的某些变体-无论如何都更容易理解。
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
以null终止的字符串效果不佳。这在Mac OS X上效果很好,但是我不能保证所有* nix都是如此。小心踩一下。
我还应该提到,经常使用GNU Parallel作为xargs
替代。您也可以检查一下。
我可能想念一些东西,所以其他人也应该插话。
tail -r
...我做错什么了吗?
tac
了sunaku 作为替代方案,所以我会尝试这样做
tail -r
特定于OSX,并反转换行符分隔的输入,而不是空分隔符的输入。您的第二个解决方案根本不起作用(您正在将输入传递给ls
,这无关紧要);没有简单的修补程序可以使它可靠地工作。
在您的示例中,您正在遍历多个文件,但由于存在更笼统的标题(可能涵盖遍历数组或根据任意数量的顺序进行求逆),所以我发现了这个问题。
这是在Zsh中执行此操作的方法:
如果要遍历数组中的元素,请使用以下语法(source)
for f in ${(Oa)your_array}; do
...
done
O
与下一个标志中指定的顺序相反;a
是正常的数组顺序。
就像@Gilles所说的那样,On
将反转您的文件,例如使用my/file/glob/*(On)
。那是因为On
是“反向名称顺序”。
Zsh排序标志:
a
排列顺序L
文件长度l
链接数m
修改日期n
名称^o
逆序(o
正常顺序)O
相反的顺序有关示例,请参见https://github.com/grml/zsh-lovers/blob/master/zsh-lovers.1.txt和http://reasoniamhere.com/2014/01/11/outrageously-useful-tips-掌握您的Z-shell /
Mac OSX不支持该tac
命令。当您在for
循环中调用单个命令时,@ tcdyl的解决方案有效。对于所有其他情况,以下是解决该问题的最简单方法。
此方法不支持文件名中包含换行符。根本原因是,tail -r
它按换行符分隔输入内容。
for i in `ls -1 [filename pattern] | tail -r`; do [commands here]; done
但是,有一种方法可以解决换行限制。如果您知道文件名不包含某个字符(例如'='),则可以使用tr
替换所有换行符以使其成为该字符,然后进行排序。结果如下所示:
for i in `find [directory] -name '[filename]' -print0 | tr '\n' '=' | tr '\0' '\n'
| tail -r | tr '\n' '\0' | tr '=' '\n' | xargs -0`; do [commands]; done
注意:根据您的版本tr
,它可能不支持'\0'
作为字符。通常可以通过将语言环境更改为C来解决此问题(但我不记得具体如何,因为修复一次后,它现在就可以在我的计算机上使用了)。如果收到错误消息,但找不到解决方法,请将其作为注释发布,以便我们帮助您进行故障排除。
sort -r
之前移至for
或清洗即可ls -r
。