Respostas:
No bash ou no ksh, coloque os nomes dos arquivos em uma matriz e itere sobre essa matriz na ordem inversa.
files=(/var/logs/foo*.log)
for ((i=${#files[@]}-1; i>=0; i--)); do
bar "${files[$i]}"
done
O código acima também funciona no zsh se a ksh_arrays
opção estiver configurada (está no modo de emulação ksh). Existe um método mais simples no zsh, que é reverter a ordem das correspondências através de um qualificador global:
for f in /var/logs/foo*.log(On); do bar $f; done
O POSIX não inclui matrizes; portanto, se você deseja ser portátil, sua única opção para armazenar diretamente uma matriz de cadeias de caracteres são os parâmetros posicionais.
set -- /var/logs/foo*.log
i=$#
while [ $i -gt 0 ]; do
eval "f=\${$i}"
bar "$f"
i=$((i-1))
done
i
e f
; basta executar um shift
, usar $1
para sua chamada bar
e testar [ -z $1 ]
no seu while
.
[ -z $1 ]
nem [ -z "$1" ]
são testes úteis (e se o parâmetro fosse *
, ou uma string vazia?). E, de qualquer forma, eles não ajudam aqui: a questão é como fazer um loop na ordem oposta.
Tente isso, a menos que você considere quebras de linha como "caracteres descolados":
ls /var/logs/foo*.log | tac | while read f; do
bar "$f"
done
f
na minha situação. Essa resposta, porém, funciona praticamente como um substituto para a for
linha comum .
Se alguém está tentando descobrir como reverter a iteração em uma lista de cadeias delimitadas por espaço, isso funciona:
reverse() {
tac <(echo "$@" | tr ' ' '\n') | tr '\n' ' '
}
list="a bb ccc"
for i in `reverse $list`; do
echo "$i"
done
> ccc
> bb
> a
tac
faz parte do coreutils do GNU. Mas sua solução também é boa.
tac
. Embora pelo número de tac
respostas -less aqui, eu acho que talvez o OSX não tenha tac. Nesse caso, use alguma variante da solução do @ arp - é mais fácil entender de qualquer maneira.
find /var/logs/ -name 'foo*.log' -print0 | tail -r | xargs -0 bar
Deve operar da maneira que você deseja (isso foi testado no Mac OS X e eu tenho uma ressalva abaixo ...).
Na página do manual para encontrar:
-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).
Basicamente, você encontra os arquivos que correspondem à sua string + glob e termina cada um com um caractere NUL. Se os seus nomes de arquivo contiverem novas linhas ou outros caracteres estranhos, o find deve lidar com isso muito bem.
tail -r
leva a entrada padrão através do pipe e a inverte (observe que tail -r
imprime toda a entrada em stdout, e não apenas as últimas 10 linhas, que é o padrão padrão. man tail
para obter mais informações).
Em seguida, canalizamos isso para 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).
Aqui, o xargs espera ver argumentos separados pelo caractere NUL, dos quais você passou find
e revertido tail
.
Minha ressalva: li que tail
não funciona bem com seqüências terminadas em nulo . Isso funcionou bem no Mac OS X, mas não posso garantir que esse seja o caso de todos os * nixes. Pisar com cuidado.
Também devo mencionar que o GNU Parallel é frequentemente usado como uma xargs
alternativa. Você pode verificar isso também.
Posso estar faltando alguma coisa, para que outras pessoas entrem na conversa.
tail -r
... estou fazendo algo errado?
tac
como uma alternativa, por isso gostaria de tentar que, em vez
tail -r
é específico para OSX e reverte a entrada delimitada por nova linha, e não a delimitada por nulo. Sua segunda solução não funciona (você está direcionando a entrada ls
, o que não importa); não há uma solução fácil que o faça funcionar de maneira confiável.
No seu exemplo, você está repetindo vários arquivos, mas eu encontrei essa pergunta por causa de seu título mais geral, que também pode abranger um loop sobre uma matriz ou reverter com base em qualquer número de pedidos.
Veja como fazer isso no Zsh:
Se você estiver fazendo um loop sobre os elementos em uma matriz, use esta sintaxe ( origem )
for f in ${(Oa)your_array}; do
...
done
O
inverte a ordem especificada no próximo sinalizador; a
é a ordem normal da matriz.
Como o @Gilles disse, On
a ordem inversa será de seus arquivos globbed, por exemplo, com my/file/glob/*(On)
. Isso On
ocorre porque é " ordem reversa do nome ".
Sinalizadores de classificação Zsh:
a
ordem da matrizL
comprimento do arquivol
número de linksm
modificação de datan
nome^o
ordem inversa ( o
é ordem normal)O
ordem reversaPara obter exemplos, consulte https://github.com/grml/zsh-lovers/blob/master/zsh-lovers.1.txt e http://reasoniamhere.com/2014/01/11/outrageously-useful-tips- para dominar seu z-shell /
O Mac OSX não suporta o tac
comando. A solução do @tcdyl funciona quando você está chamando um único comando em um for
loop. Para todos os outros casos, a seguir é a maneira mais simples de contornar isso.
Essa abordagem não suporta ter novas linhas nos seus nomes de arquivos. A razão subjacente é que tail -r
classifica sua entrada como delimitada por novas linhas.
for i in `ls -1 [filename pattern] | tail -r`; do [commands here]; done
No entanto, existe uma maneira de contornar a limitação da nova linha. Se você souber que seus nomes de arquivos não contêm um determinado caractere (digamos, '='), tr
substitua todas as novas linhas para se tornar esse caractere e faça a classificação. O resultado teria a seguinte aparência:
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
Nota: dependendo da sua versão tr
, ele pode não ser compatível '\0'
como personagem. Geralmente, isso pode ser resolvido alterando o código do idioma para C (mas não me lembro exatamente como, pois depois de corrigi-lo, ele agora funciona no meu computador). Se você receber uma mensagem de erro e não conseguir encontrar a solução alternativa, poste-a como um comentário, para que eu possa ajudá-lo a solucionar o problema.
sort -r
antesfor
ou lavarls -r
.