Risposte:
In bash o ksh, metti i nomi dei file in un array e fai scorrere su quell'array in ordine inverso.
files=(/var/logs/foo*.log)
for ((i=${#files[@]}-1; i>=0; i--)); do
bar "${files[$i]}"
done
Il codice sopra funziona anche in zsh se l' ksh_arraysopzione è impostata (è in modalità di emulazione ksh). C'è un metodo più semplice in zsh, che è quello di invertire l'ordine delle partite attraverso un qualificatore glob:
for f in /var/logs/foo*.log(On); do bar $f; done
POSIX non include array, quindi se si desidera essere portatili, l'unica opzione per memorizzare direttamente un array di stringhe è i parametri posizionali.
set -- /var/logs/foo*.log
i=$#
while [ $i -gt 0 ]; do
eval "f=\${$i}"
bar "$f"
i=$((i-1))
done
ie f; basta eseguire un shift, utilizzare $1per la chiamata a bare testare [ -z $1 ]nel proprio while.
[ -z $1 ]ne [ -z "$1" ]sono le prove utili (cosa succede se il parametro è stato *, o una stringa vuota?). E in ogni caso non aiutano qui: la domanda è come fare il ciclo nell'ordine opposto.
Prova questo, a meno che non consideri le interruzioni di riga come "personaggi funky":
ls /var/logs/foo*.log | tac | while read f; do
bar "$f"
done
fnella mia situazione. Questa risposta, tuttavia, funge praticamente da rimpiazzo della forlinea ordinaria .
Se qualcuno sta cercando di capire come invertire l'iterazione su un elenco di stringhe delimitato da spazi, funziona:
reverse() {
tac <(echo "$@" | tr ' ' '\n') | tr '\n' ' '
}
list="a bb ccc"
for i in `reverse $list`; do
echo "$i"
done
> ccc
> bb
> a
tacfa parte dei coreutils GNU. Ma anche la tua soluzione è buona.
tac. Sebbene dal numero di tacrisposte senza risposta qui indovino che forse OSX non ha tac. Nel qual caso usa una variante della soluzione di @ arp - è comunque più facile da capire.
find /var/logs/ -name 'foo*.log' -print0 | tail -r | xargs -0 bar
Dovrebbe funzionare nel modo desiderato (questo è stato testato su Mac OS X e ho un avvertimento di seguito ...).
Dalla pagina man per trovare:
-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).
Fondamentalmente, stai trovando i file che corrispondono alla tua stringa + glob e terminando ciascuno con un carattere NUL. Se i tuoi nomi di file contengono nuove righe o altri strani caratteri, find dovrebbe gestirlo bene.
tail -r
prende l'input standard attraverso la pipe e lo inverte (si noti che tail -rstampa tutto l'input su stdout e non solo le ultime 10 righe, che è l'impostazione predefinita standard. man tailper maggiori informazioni).
Quindi lo instilliamo per 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).
Qui, xargs prevede di vedere gli argomenti separati dal carattere NUL, da cui è passato finde invertito tail.
Il mio avvertimento: ho letto che tailnon suona bene con le stringhe con terminazione null . Questo ha funzionato bene su Mac OS X, ma non posso garantire che sia il caso di tutti i * nix. Percorri attentamente.
Vorrei anche menzionare che GNU Parallel è spesso usato come xargsalternativa. Puoi verificarlo anche tu.
Potrei mancare qualcosa, quindi altri dovrebbero entrare.
tail -rperò ... sto facendo qualcosa di sbagliato?
taccome alternativa, quindi proverei questo, invece
tail -rè specifico di OSX e inverte l'input delimitato da nuova riga, non l'input delimitato da null. La tua seconda soluzione non funziona affatto (stai eseguendo il piping input ls, a cui non importa); non esiste una soluzione semplice che possa farlo funzionare in modo affidabile.
Nel tuo esempio stai eseguendo il loop su più file, ma ho trovato questa domanda a causa del suo titolo più generale che potrebbe anche coprire il loop su un array o l'inversione in base a un numero qualsiasi di ordini.
Ecco come farlo in Zsh:
Se esegui il looping degli elementi in un array, usa questa sintassi ( sorgente )
for f in ${(Oa)your_array}; do
...
done
Oinverte l'ordine specificato nella bandiera successiva; aè il normale ordine di array.
Come ha detto @Gilles, Oninvertirai l'ordine dei tuoi file danneggiati, ad es my/file/glob/*(On). Con . Questo perché Onè "inverso nome ordine."
Flag di ordinamento Zsh:
a ordine di arrayL lunghezza del filel numero di collegamentim data di modifican nome^oordine inverso ( oè ordine normale)O ordine inversoPer esempi, vedere https://github.com/grml/zsh-lovers/blob/master/zsh-lovers.1.txt e http://reasoniamhere.com/2014/01/11/outrageously-useful-tips- to-master-your-z-shell /
Mac OSX non supporta il taccomando. La soluzione di @tcdyl funziona quando si chiama un singolo comando in un forciclo. Per tutti gli altri casi, il seguente è il modo più semplice per aggirarlo.
Questo approccio non supporta l'inserimento di nuove righe nei nomi dei file. Il motivo di fondo è che tail -rordina i suoi input come delimitati da newline.
for i in `ls -1 [filename pattern] | tail -r`; do [commands here]; done
Tuttavia, esiste un modo per aggirare la limitazione di nuova riga. Se sai che i tuoi nomi di file non contengono un certo carattere (diciamo, "="), puoi usare trper sostituire tutte le nuove righe per diventare questo personaggio, quindi fare l'ordinamento. Il risultato sarebbe simile al seguente:
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: a seconda della versione di tr, potrebbe non essere supportato '\0'come personaggio. Questo di solito può essere aggirato cambiando le impostazioni locali in C (ma non ricordo esattamente come, dal momento che dopo averlo risolto una volta ora funziona sul mio computer). Se ricevi un messaggio di errore e non riesci a trovare la soluzione alternativa, pubblicalo come commento, così posso aiutarti a risolverlo.
sort -rpassare a prima delfor, o lavarsi attraversols -r.