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_arrays
opzione è 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
i
e f
; basta eseguire un shift
, utilizzare $1
per la chiamata a bar
e 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
f
nella mia situazione. Questa risposta, tuttavia, funge praticamente da rimpiazzo della for
linea 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
tac
fa parte dei coreutils GNU. Ma anche la tua soluzione è buona.
tac
. Sebbene dal numero di tac
risposte 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 -r
stampa tutto l'input su stdout e non solo le ultime 10 righe, che è l'impostazione predefinita standard. man tail
per 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 find
e invertito tail
.
Il mio avvertimento: ho letto che tail
non 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 xargs
alternativa. Puoi verificarlo anche tu.
Potrei mancare qualcosa, quindi altri dovrebbero entrare.
tail -r
però ... sto facendo qualcosa di sbagliato?
tac
come 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
O
inverte l'ordine specificato nella bandiera successiva; a
è il normale ordine di array.
Come ha detto @Gilles, On
invertirai 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^o
ordine 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 tac
comando. La soluzione di @tcdyl funziona quando si chiama un singolo comando in un for
ciclo. 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 -r
ordina 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 tr
per 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 -r
passare a prima delfor
, o lavarsi attraversols -r
.