Iterando sobre cada línea de la salida ls -l

119

Quiero iterar sobre cada línea en la salida de: ls -l /some/dir/*

Ahora mismo estoy intentando: for x in $(ls -l $1); do echo $x; done

Sin embargo, esto itera sobre cada elemento en la línea por separado, así que obtengo:

-r--r-----
1
ivanevf
eng
1074
Apr
22
13:07
File1

-r--r-----
1
ivanevf
eng
1074
Apr
22
13:17
File2

Pero quiero iterar sobre cada línea como un todo. ¿Cómo puedo hacer eso?

Iván
fuente
1
Siempre cite las variables (y la salida del comando) a menos que tenga una razón específica para no hacerlo.
Glenn Jackman

Respuestas:

246

Establezca IFS en una nueva línea, así:

IFS='
'
for x in `ls -l $1`; do echo $x; done

Coloque un sub-shell a su alrededor si no desea configurar IFS permanentemente:

(IFS='
'
for x in `ls -l $1`; do echo $x; done)

O utilizar while | leer en su lugar:

ls -l $1 | while read x; do echo $x; done

Una opción más, que ejecuta while / read en el mismo nivel de shell:

while read x; do echo $x; done << EOF
$(ls -l $1)
EOF
Randy Proctor
fuente
12
Tenga cuidado al conectar a while, el while se ejecutará en una subcapa, lo que significa que no podría cambiar las variables en el proceso principal
Reorx
1
¿Qué hace el dólar aquí? Necesito usar esto en un script que estoy escribiendo que acepta argumentos. El $ 1 está tirando las cosas. ¿Qué puedo poner allí en lugar de $ 1 para obtener el mismo efecto? Me gustaría usar la segunda solución.
novato necesitado
@ noob-in-need Reemplácelo con el directorio que desee enumerar
vpzomtrrfrt
1
Es posible que desee hacerlo read -ro, de lo contrario, bash eliminará las barras invertidas sin escape de los datos.
Brian Gordon
6

Depende de lo que quieras hacer con cada línea. awk es una utilidad útil para este tipo de procesamiento. Ejemplo:

 ls -l | awk '{print $9, $5}'

.. en mi sistema imprime el nombre y tamaño de cada elemento en el directorio.

Adam Holmberg
fuente
3

Como ya se mencionó, awk es la herramienta adecuada para esto. Si no desea usar awk, en lugar de analizar la salida de "ls -l" línea por línea, puede iterar sobre todos los archivos y hacer un "ls -l" para cada archivo individual como este:

for x in * ; do echo `ls -ld $x` ; done
Axel
fuente
3

También puede probar el findcomando. Si solo desea archivos en el directorio actual:

find . -d 1 -prune -ls

¿Ejecutar un comando en cada uno de ellos?

find . -d 1 -prune -exec echo {} \;

¿Contar líneas, pero solo en archivos?

find . -d 1 -prune -type f -exec wc -l {} \;

David Koski
fuente
encontrar está roto. A menudo recibo algunos mensajes de error extraños. quiere ayudarme cuando la línea de comandos es perfectamente válida, y parece que una vez que comienza a hacer esto, no se detendrá hasta el próximo reinicio QUIZÁS. a veces parece de naturaleza aleatoria en lo que respecta a los errores. No estoy seguro de cómo puedo informar del error.
Jim Michaels
1

La utilidad read (1) junto con la redirección de salida del comando ls (1) hará lo que desee.

Steve Emmerson
fuente
-1

Entonces, ¿por qué nadie sugirió simplemente usar opciones que eliminen las partes que no quiere procesar?

En Debian moderno, solo obtiene su archivo con:

ls --format=single-column 

Además, no tiene que prestar atención al directorio en el que lo está ejecutando si usa el directorio completo:

ls --format=single-column /root/dir/starting/point/to/target/dir/

Este último comando estoy usando el anterior y obtengo el siguiente resultado:

bot@dev:~/downloaded/Daily# ls --format=single-column /home/bot/downloaded/Daily/*.gz
/home/bot/downloaded/Daily/Liq_DailyManifest_V3_US_20141119_IENT1.txt.gz
/home/bot/downloaded/Daily/Liq_DailyManifest_V3_US_20141120_IENT1.txt.gz
/home/bot/downloaded/Daily/Liq_DailyManifest_V3_US_20141121_IENT1.txt.gz
BradChesney79
fuente