Simplemente dirígete a sort -rantes de for, o lávate ls -r.
David Schwartz
Respuestas:
27
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_arraysopció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];doeval"f=\${$i}"
bar "$f"
i=$((i-1))done
Una vez que esté utilizando parámetros posicionales, no hay necesidad de sus variables iy f; simplemente realice un shift, use $1para su llamada bary pruebe [ -z $1 ]en su while.
user1404316
@ user1404316 Esta sería una forma demasiado complicada de iterar sobre los elementos en orden ascendente . Además, incorrecto: ni [ -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.
Gilles 'SO- deja de ser malvado'
La pregunta específicamente dice que está iterando sobre los nombres de archivo en / var / log, por lo que es seguro asumir que ninguno de los parámetros sería "*" o vacío. Sin embargo, estoy corregido en el punto del orden inverso.
user1404316
7
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
¿Hay algún método que funcione con saltos de línea? (Sé que es raro, pero al menos por el bien del aprendizaje me gustaría saber si es posible escribir el código correcto.)
Mehrdad
Creativo para usar tac para revertir el flujo, y si desea deshacerse de algunos caracteres no deseados como saltos de línea, puede canalizar a tr -d '\ n'.
La respuesta más votada rompió la variable fen mi situación. Sin embargo, esta respuesta actúa más o menos como un reemplazo directo para la forlínea ordinaria .
Serge Stroobandt
2
Si alguien está tratando de descubrir cómo revertir la iteración sobre una lista de cadenas delimitadas por espacios, esto funciona:
No tengo tac en mi sistema; No sé si es robusto, pero he estado usando para x en $ {mylist}; do revv = "$ {x} $ {revv}"; hecho
arp
@arp Eso es algo impactante ya que taces parte de los coreutils de GNU. Pero su solución también es buena.
ACK_stoverflow
@ACK_stoverflow Existen sistemas sin herramientas de usuario de Linux.
Kusalananda
@Kusalananda ¿Estás diciendo que solo Linux usa GNU coreutils? Jajaja Incluso busybox tiene tac. Aunque por la cantidad de tacrespuestas 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.
ACK_stoverflow
@ACK_stoverflow Eso es lo que estoy diciendo, sí.
Kusalananda
1
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 -rimprime toda la entrada en stdout, y no solo las últimas 10 líneas, que es el valor predeterminado estándar. man tailpara obtener más información).
Luego lo canalizamos a 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).
Aquí, xargs espera ver argumentos separados por el carácter NUL, desde el cual pasó findy revirtió tail.
+1 gran respuesta. Sin embargo, parece que Ubuntu no es compatible tail -r... ¿Estoy haciendo algo mal?
Mehrdad
1
No, no creo que lo seas. No tengo mi máquina Linux activada, pero un google rápido para 'linux tail man' no lo muestra como una opción. Sunaku mencionó taccomo una alternativa, así que lo intentaría, en su lugar
tcdyl
También he editado la respuesta para incluir otra alternativa
tcdyl
whoops Olvidé hacer +1 cuando dije +1 :( ¡Listo! Lo siento por eso jaja :)
Mehrdad
44
tail -res 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.
Gilles 'SO- deja de ser malvado'
1
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
Oinvierte el orden especificado en el siguiente indicador; aes el orden normal de la matriz.
Como dijo @Gilles, Onrevertirá el orden de sus archivos globales, por ejemplo, con my/file/glob/*(On). Eso es porque Ones " orden de nombre inverso ".
Mac OSX no es compatible con el taccomando. La solución de @tcdyl funciona cuando se llama a un solo comando en un forbucle. 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 -rordena 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 trpara reemplazar todas las líneas nuevas para convertirse en este carácter y luego ordenarlas. El resultado sería el siguiente:
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
.Respuestas:
En bash o ksh, coloque los nombres de archivo en una matriz e itere sobre esa matriz en orden inverso.
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: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.
fuente
i
yf
; simplemente realice unshift
, use$1
para su llamadabar
y pruebe[ -z $1 ]
en suwhile
.[ -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":
fuente
f
en mi situación. Sin embargo, esta respuesta actúa más o menos como un reemplazo directo para lafor
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:
fuente
tac
es parte de los coreutils de GNU. Pero su solución también es buena.tac
. Aunque por la cantidad detac
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.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:
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.
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
: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.
fuente
tail -r
... ¿Estoy haciendo algo mal?tac
como una alternativa, así que lo intentaría, en su lugartail -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ónls
, 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 )
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, conmy/file/glob/*(On)
. Eso es porqueOn
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 /
fuente
Mac OSX no es compatible con el
tac
comando. La solución de @tcdyl funciona cuando se llama a un solo comando en unfor
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.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: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.fuente
una manera fácil es usar
ls -r
como lo menciona @David Schwartzfuente
Prueba esto:
Creo que es la forma más simple.
fuente
for
bucle en orden inverso".