recorrer `ls` da como resultado el script de shell bash

recorrer `ls` da como resultado el script de shell bash

¿Alguien tiene una plantilla de script de shell para hacer algo con lsuna lista de nombres de directorios y recorrer cada uno de ellos y hacer algo?

Estoy planeando hacer ls -1d */para obtener la lista de nombres de directorios.

Respuesta1

Editado para no usar ls donde serviría un globo, como sugirieron @shawn-j-goff y otros.

Solo usa un for..do..donebucle:

for f in *; do
  echo "File -> $f"
done

Puede reemplazar *con *.txto cualquier otro globo que devuelva una lista (de archivos, directorios o cualquier otra cosa), un comando que genere una lista, por ejemplo, $(cat filelist.txt)o reemplazarlo con una lista.

Dentro del dobucle, simplemente haga referencia a la variable del bucle con el prefijo del signo de dólar (como $fen el ejemplo anterior). Puedes echohacerlo o hacerle cualquier otra cosa que quieras.

Por ejemplo, para cambiar el nombre de todos los .xmlarchivos en el directorio actual a .txt:

for x in *.xml; do 
  t=$(echo $x | sed 's/\.xml$/.txt/'); 
  mv $x $t && echo "moved $x -> $t"
done

O incluso mejor, si estás usando Bash, puedes usar expansiones de parámetros de Bash en lugar de generar una subcapa:

for x in *.xml; do 
  t=${x%.xml}.txt
  mv $x $t && echo "moved $x -> $t"
done

Respuesta2

Usar la salida de lspara obtener nombres de archivos es una mala idea. Puede provocar scripts que funcionen mal e incluso sean peligrosos. Esto se debe a que un nombre de archivo puede contener cualquier carácter excepto /y el nullcarácter, y lsno utiliza ninguno de esos caracteres como delimitadores, por lo que si un nombre de archivo tiene un espacio o una nueva línea,voluntadobtener resultados inesperados.

Hay dos formas muy buenas de iterar sobre archivos. Aquí, lo he usado simplemente echopara demostrar cómo hacer algo con el nombre del archivo; Aunque puedes usar cualquier cosa.

La primera es utilizar las funciones globales nativas del shell.

for dir in */; do
  echo "$dir"
done

El shell se expande */en argumentos separados que forlee el bucle; incluso si hay un espacio, una nueva línea o cualquier otro carácter extraño en el nombre del archivo, forverá cada nombre completo como una unidad atómica; No está analizando la lista de ninguna manera.

Si desea ir recursivamente a subdirectorios, esto no funcionará a menos que su shell tenga algunas funciones globales extendidas (como bash's globstar. Si su shell no tiene estas características, o si desea asegurarse de que su script funcione en una variedad de sistemas, entonces la siguiente opción es usar find.

find . -type d -exec echo '{}' \;

Aquí, el findcomando lo llamará echoy le pasará un argumento del nombre del archivo. Lo hace una vez por cada archivo que encuentra. Como en el ejemplo anterior, no hay análisis de una lista de nombres de archivos; en cambio, un nombre de archivo se envía completamente como argumento.

La sintaxis del -execargumento parece un poco divertida. findtoma el primer argumento posterior -execy lo trata como el programa a ejecutar, y cada argumento posterior, lo toma como un argumento para pasar a ese programa. Hay dos argumentos especiales que -execes necesario ver. El primero es {}; este argumento se reemplaza con un nombre de archivo que findgenera la parte anterior. El segundo es ;, que permite findsaber que este es el final de la lista de argumentos a pasar al programa; findnecesita esto porque puede continuar con más argumentos destinados findy no destinados al programa ejecutado. La razón es \que el shell también lo trata ;de manera especial: representa el final de un comando, por lo que debemos escapar de él para que el shell lo proporcione como argumento en findlugar de consumirlo por sí mismo; Otra forma de hacer que el shell no lo trate especialmente es ponerlo entre comillas: ';'funciona igual de bien que \;para este propósito.

Respuesta3

Para archivos con espacios, deberá asegurarse de citar la variable como:

 for i in $(ls); do echo "$i"; done; 

o puede cambiar la variable de entorno del separador de campos de entrada (IFS):

 (IFS=$'\n';for i in $(ls); do echo $i; done) # subshell to restore IFS

Finalmente, dependiendo de lo que estés haciendo, es posible que ni siquiera necesites el ls:

 for i in *; do echo "$i"; done;

Respuesta4

Solo para agregar a la respuesta de CoverosGene, aquí hay una manera de enumerar solo los nombres de los directorios:

for f in */; do
  echo "Directory -> $f"
done

información relacionada