Respuestas:
En bash o ksh, coloque los nombres de archivo en una matriz e itere sobre esa matriz en orden inverso.
files=(/var/logs/foo*.log)
for ((i=${#files[@]}-1; i>=0; i--)); do
bar "${files[$i]}"
done
El código anterior también funciona en zsh si la ksh_arrays
opción está configurada (está en modo de emulación ksh). Hay un método más simple en zsh, que es invertir el orden de las coincidencias a través de un calificador global:
for f in /var/logs/foo*.log(On); do bar $f; done
POSIX no incluye matrices, por lo que si desea ser portátil, su única opción para almacenar directamente una matriz de cadenas son los parámetros posicionales.
set -- /var/logs/foo*.log
i=$#
while [ $i -gt 0 ]; do
eval "f=\${$i}"
bar "$f"
i=$((i-1))
done
i
y f
; simplemente realice un shift
, use $1
para su llamada bar
y pruebe [ -z $1 ]
en su while
.
[ -z $1 ]
tampoco [ -z "$1" ]
son pruebas útiles (¿qué pasa si el parámetro era *
, o una cadena vacía?). Y en cualquier caso, no ayudan aquí: la pregunta es cómo hacer un bucle en el orden opuesto.
Intente esto, a menos que considere los saltos de línea como "personajes originales":
ls /var/logs/foo*.log | tac | while read f; do
bar "$f"
done
f
en mi situación. Sin embargo, esta respuesta actúa más o menos como un reemplazo directo para la for
línea ordinaria .
Si alguien está tratando de descubrir cómo revertir la iteración sobre una lista de cadenas delimitadas por espacios, esto 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
es parte de los coreutils de GNU. Pero su solución también es buena.
tac
. Aunque por la cantidad de tac
respuestas sin respuesta aquí, supongo que quizás OSX no tiene tac. En cuyo caso, use alguna variante de la solución de @ arp; de todos modos, es más fácil de entender.
find /var/logs/ -name 'foo*.log' -print0 | tail -r | xargs -0 bar
Debe funcionar de la manera que desee (esto se probó en Mac OS X y tengo una advertencia a continuación ...).
Desde la página del 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).
Básicamente, está buscando los archivos que coinciden con su cadena + glob y termina cada uno con un carácter NUL. Si sus nombres de archivo contienen nuevas líneas u otros caracteres extraños, find debería manejar esto bien.
tail -r
toma la entrada estándar a través de la tubería y la invierte (tenga en cuenta que tail -r
imprime toda la entrada en stdout, y no solo las últimas 10 líneas, que es el valor predeterminado estándar. man tail
para obtener más información).
Luego lo canalizamos a 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).
Aquí, xargs espera ver argumentos separados por el carácter NUL, desde el cual pasó find
y revirtió tail
.
Mi advertencia: he leído que tail
no funciona bien con cadenas terminadas en nulo . Esto funcionó bien en Mac OS X, pero no puedo garantizar que ese sea el caso para todos los * nixes. Ve con cuidado.
También debo mencionar que GNU Parallel se usa a menudo como una xargs
alternativa. También puedes comprobar eso.
Puede que me falte algo, por lo que otros deberían intervenir.
tail -r
... ¿Estoy haciendo algo mal?
tac
como una alternativa, así que lo intentaría, en su lugar
tail -r
es específico de OSX e invierte la entrada delimitada por nueva línea, no la entrada delimitada por nulos. Su segunda solución no funciona en absoluto (está canalizando información ls
, lo que no le importa); No hay una solución fácil que lo haga funcionar de manera confiable.
En su ejemplo, está recorriendo varios archivos, pero encontré esta pregunta debido a su título más general, que también podría abarcar la reproducción en bucle sobre una matriz o la inversión según cualquier número de órdenes.
Aquí se explica cómo hacerlo en Zsh:
Si está recorriendo los elementos en una matriz, use esta sintaxis ( fuente )
for f in ${(Oa)your_array}; do
...
done
O
invierte el orden especificado en el siguiente indicador; a
es el orden normal de la matriz.
Como dijo @Gilles, On
revertirá el orden de sus archivos globales, por ejemplo, con my/file/glob/*(On)
. Eso es porque On
es " orden de nombre inverso ".
Banderas de clasificación Zsh:
a
orden de la matrizL
longitud del archivol
número de enlacesm
fecha de modificaciónn
nombre^o
orden inverso ( o
es el orden normal)O
orden inversoPara ver ejemplos, consulte https://github.com/grml/zsh-lovers/blob/master/zsh-lovers.1.txt y http://reasoniamhere.com/2014/01/11/outrageously-useful-tips- para-dominar-tu-z-shell /
Mac OSX no es compatible con el tac
comando. La solución de @tcdyl funciona cuando se llama a un solo comando en un for
bucle. Para todos los demás casos, la siguiente es la forma más sencilla de evitarlo.
Este enfoque no admite tener nuevas líneas en sus nombres de archivo. La razón subyacente es que tail -r
ordena su entrada delimitada por nuevas líneas.
for i in `ls -1 [filename pattern] | tail -r`; do [commands here]; done
Sin embargo, hay una manera de evitar la limitación de la nueva línea. Si sabe que sus nombres de archivo no contienen un determinado carácter (por ejemplo, '='), puede usar tr
para reemplazar todas las líneas nuevas para convertirse en este carácter y luego ordenarlas. El resultado sería el siguiente:
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: dependiendo de su versión de tr
, es posible que no sea compatible '\0'
con un personaje. Esto generalmente se puede solucionar cambiando la configuración regional a C (pero no recuerdo exactamente cómo, ya que después de arreglarlo una vez ahora funciona en mi computadora). Si recibe un mensaje de error y no puede encontrar la solución, publíquelo como comentario para que pueda ayudarlo a solucionarlo.
sort -r
antes defor
, o lávatels -r
.