¿Alguien tiene un script de shell de plantilla para hacer algo con lsuna lista de nombres de directorio y recorrer cada uno y hacer algo?
Estoy planeando hacer ls -1d */para obtener la lista de nombres de directorio.
¿Alguien tiene un script de shell de plantilla para hacer algo con lsuna lista de nombres de directorio y recorrer cada uno y hacer algo?
Estoy planeando hacer ls -1d */para obtener la lista de nombres de directorio.
Respuestas:
Editado para no usar ls donde lo harí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 el *con *.txto cualquier otro pegote que devuelve una lista (de los archivos, directorios o lo que fuera), un comando que genera una lista, por ejemplo, $(cat filelist.txt)o en realidad sustituirla por una lista.
Dentro del dobucle, solo se refiere a la variable del bucle con el prefijo del signo de dólar ( $fen el ejemplo anterior). Puedes echohacerlo o hacer 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á usando Bash, puede usar expansiones de parámetros de Bash en lugar de generar una subshell:
for x in *.xml; do
t=${x%.xml}.txt
mv $x $t && echo "moved $x -> $t"
done
forbucles, y un error típico de tratar de analizar la salida de ls. @ DanielA.White, podría considerar no aceptar esta respuesta si no fue útil (o es potencialmente engañosa), ya que, como dijo, está actuando en los directorios. La respuesta de Shawn J. Goff debería proporcionar una solución más sólida y funcional a su problema.
lssalida , no debe leer la salida en un forbucle , debe usar en $()lugar de `` y Usar más comillas ™ . Estoy seguro de que @CoverosGene tenía buenas intenciones, pero esto es simplemente terrible.
lses ls -1 | while read line; do stuff; done. Al menos ese no se romperá por espacios en blanco.
mv -vusted no necesitaecho "moved $x -> $t"
Usar la salida de lspara obtener nombres de archivos es una mala idea . Puede provocar un mal funcionamiento e incluso scripts peligrosos. Esto se debe a un nombre de archivo puede contener cualquier carácter excepto /y el nullcarácter, y lsno utilizar cualquiera de esos caracteres como delimitadores, por lo que si un nombre de archivo tiene un espacio o una nueva línea, que va a obtener resultados inesperados.
Hay dos formas muy buenas de iterar sobre archivos. Aquí, he usado simplemente echopara demostrar que estoy haciendo algo con el nombre del archivo; Sin embargo, puedes usar cualquier cosa.
El primero es usar las características de globbing 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, entonces esto no funcionará a menos que su shell tenga algunas características de globbing extendidas (como bash's globstar. Si su shell no tiene estas características, o si quiere asegurarse de que su script funcionará en una variedad de sistemas, entonces la siguiente opción es usar find.
find . -type d -exec echo '{}' \;
Aquí, el findcomando llamará echoy le pasará un argumento del nombre del archivo. Hace esto una vez por cada archivo que encuentra. Al igual que con el ejemplo anterior, no se analiza una lista de nombres de archivo; en cambio, un fileneame se envía completamente como argumento.
La sintaxis del -execargumento parece un poco divertida. findtoma el primer argumento después -execy lo trata como el programa a ejecutar, y cada argumento posterior, toma como un argumento para pasar a ese programa. Hay dos argumentos especiales que -exechay que ver. El primero es {}; este argumento se reemplaza con un nombre de archivo que findgenera las partes anteriores . El segundo es ;, que permite findsaber que este es el final de la lista de argumentos para pasar al programa; findnecesita esto porque puede continuar con más argumentos destinados findy no destinados al programa ejecutado. La razón de esto \es que la cáscara también trata;especialmente: representa el final de un comando, por lo que debemos escapar para que el shell lo ofrezca 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 tan bien como \;para este propósito.
find. Hay magia que se puede hacer, e incluso las limitaciones percibidas -execse pueden solucionar. La -print0opción también es valiosa para usar con xargs.
Para los 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 campo de entrada (IFS):
IFS=$'\n';for file in $(ls); do echo $i; done
Finalmente, dependiendo de lo que esté haciendo, es posible que ni siquiera necesite el ls:
for i in *; do echo "$i"; done;
\nes insuficiente. Nunca es una buena idea recomendar analizar la salida de ls.
Si tiene instalado GNU Parallel http://www.gnu.org/software/parallel/ , puede hacer esto:
ls | parallel echo {} is in this dir
Para cambiar el nombre de todo .txt a .xml:
ls *.txt | parallel mv {} {.}.xml
Mire el video de introducción de GNU Parallel para obtener más información: http://www.youtube.com/watch?v=OpaiGYxkSuQ
¿Por qué no establecer IFS en una nueva línea y luego capturar la salida de lsen una matriz? Establecer IFS en nueva línea debería resolver problemas con caracteres divertidos en los nombres de archivo; usar lspuede ser bueno porque tiene una función de clasificación incorporada.
(En las pruebas, tuve problemas para configurar IFS \npero funciona como backspace de nueva línea, como se sugiere en otro lugar aquí):
Por ejemplo (suponiendo lsque se pasa el patrón de búsqueda deseado $1):
SAVEIFS=$IFS
IFS=$(echo -en "\n\b")
FILES=($(/bin/ls "$1"))
for AFILE in ${FILES[@]}
do
... do something with a file ...
done
IFS=$SAVEIFS
Esto es especialmente útil en OS X, por ejemplo, para capturar una lista de archivos ordenados por fecha de creación (más antigua a más reciente), el lscomando es ls -t -U -r.
\nes insuficiente. Las únicas soluciones válidas utilizan un bucle for con expansión de nombre de ruta, o find.
Así es como lo hago, pero probablemente hay formas más eficientes.
ls > filelist.txt
while read filename; do echo filename: "$filename"; done < filelist.txt
ls | while read i; do echo filename: $i; done