
¿Alguien tiene una plantilla de script de shell para hacer algo con ls
una 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..done
bucle:
for f in *; do
echo "File -> $f"
done
Puede reemplazar *
con *.txt
o 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 do
bucle, simplemente haga referencia a la variable del bucle con el prefijo del signo de dólar (como $f
en el ejemplo anterior). Puedes echo
hacerlo o hacerle cualquier otra cosa que quieras.
Por ejemplo, para cambiar el nombre de todos los .xml
archivos 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 ls
para 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 null
carácter, y ls
no 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 echo
para 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 for
lee el bucle; incluso si hay un espacio, una nueva línea o cualquier otro carácter extraño en el nombre del archivo, for
verá 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 find
comando lo llamará echo
y 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 -exec
argumento parece un poco divertida. find
toma el primer argumento posterior -exec
y 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 -exec
es necesario ver. El primero es {}
; este argumento se reemplaza con un nombre de archivo que find
genera la parte anterior. El segundo es ;
, que permite find
saber que este es el final de la lista de argumentos a pasar al programa; find
necesita esto porque puede continuar con más argumentos destinados find
y 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 find
lugar 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