Basta canalizar para sort -rantes forou lavar ls -r.
David Schwartz
Respostas:
27
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_arraysopçã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];doeval"f=\${$i}"
bar "$f"
i=$((i-1))done
Depois de usar parâmetros posicionais, não há necessidade de suas variáveis ie f; basta executar um shift, usar $1para sua chamada bare testar [ -z $1 ]no seu while.
user1404316
@ user1404316 Essa seria uma maneira excessivamente complicada de iterar os elementos em ordem crescente . Além disso, errado: [ -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.
Gilles 'SO- stop be evil'
A questão diz especificamente que está iterando sobre os nomes de arquivo em / var / log, portanto, é seguro assumir que nenhum dos parâmetros estaria "*" ou vazio. Eu permaneço corrigido, no entanto, no ponto da ordem inversa.
user1404316
7
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
Existe um método que funciona com quebras de linha? (Eu sei que é raro, mas pelo menos por uma questão de aprender Eu gostaria de saber se é possível escrever código correto.)
Mehrdad
Peça criativa para usar tac para reverter o fluxo e, se você quiser se livrar de caracteres indesejados, como quebras de linha, pode canalizar para tr-d '\ n'.
Eu não tenho tac no meu sistema; Não sei se é robusto, mas estou usando o x em $ {mylist}; revv = "$ {x} $ {revv}"; done
arp 11/01
@arp Isso é meio chocante, como tacfaz parte do coreutils do GNU. Mas sua solução também é boa.
ACK_stoverflow
@ACK_stoverflow Existem sistemas por aí sem as ferramentas de usuário do Linux.
Kusalananda
@Kusalananda Você está dizendo que apenas o Linux usa coreutils GNU? RI MUITO. Até o busybox tem tac. Embora pelo número de tacrespostas -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.
ACK_stoverflow 16/02
@ACK_stoverflow É o que estou dizendo, sim.
Kusalananda
1
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 -rimprime toda a entrada em stdout, e não apenas as últimas 10 linhas, que é o padrão padrão. man tailpara obter mais informações).
Em seguida, canalizamos isso para xargs -0:
-0Change xargs to expect NUL (``\0'') characters as separators, instead of spaces and newlines.This is expected to be used in concert with the
-print0 functionin find(1).
Aqui, o xargs espera ver argumentos separados pelo caractere NUL, dos quais você passou finde revertido tail.
+1 ótima resposta. Parece que o Ubuntu não suporta tail -r... estou fazendo algo errado?
Mehrdad
11
Não, eu não acho que você é. Eu não tenho minha máquina linux instalada, mas um google rápido para 'linux tail man' não mostra isso como uma opção. sunaku mencionado taccomo uma alternativa, por isso gostaria de tentar que, em vez
tcdyl
Também editei a resposta para incluir outra alternativa
tcdyl
whoops eu esqueci de +1 quando eu disse +1 :( Feito Desculpe por isso haha :)!
Mehrdad
4
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.
Gilles 'SO- stop be evil'
1
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
Oinverte a ordem especificada no próximo sinalizador; aé a ordem normal da matriz.
Como o @Gilles disse, Ona ordem inversa será de seus arquivos globbed, por exemplo, com my/file/glob/*(On). Isso Onocorre porque é " ordem reversa do nome ".
O Mac OSX não suporta o taccomando. A solução do @tcdyl funciona quando você está chamando um único comando em um forloop. 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 -rclassifica 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, '='), trsubstitua todas as novas linhas para se tornar esse caractere e faça a classificação. O resultado teria a seguinte aparência:
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
.Respostas:
No bash ou no ksh, coloque os nomes dos arquivos em uma matriz e itere sobre essa matriz na ordem inversa.
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: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.
fonte
i
ef
; basta executar umshift
, usar$1
para sua chamadabar
e testar[ -z $1 ]
no seuwhile
.[ -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":
fonte
f
na minha situação. Essa resposta, porém, funciona praticamente como um substituto para afor
linha comum .Se alguém está tentando descobrir como reverter a iteração em uma lista de cadeias delimitadas por espaço, isso funciona:
fonte
tac
faz parte do coreutils do GNU. Mas sua solução também é boa.tac
. Embora pelo número detac
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.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:
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.
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
:Aqui, o xargs espera ver argumentos separados pelo caractere NUL, dos quais você passou
find
e revertidotail
.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.
fonte
tail -r
... estou fazendo algo errado?tac
como uma alternativa, por isso gostaria de tentar que, em veztail -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 entradals
, 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 )
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, commy/file/glob/*(On)
. IssoOn
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 /
fonte
O Mac OSX não suporta o
tac
comando. A solução do @tcdyl funciona quando você está chamando um único comando em umfor
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.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: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.fonte
uma maneira fácil é usar
ls -r
como mencionado por @David Schwartzfonte
Tente o seguinte:
Eu acho que é a maneira mais simples.
fonte
for
loop na ordem inversa”.