GNU/Linux >> Tutoriales Linux >  >> Linux

Cómo escribir un bucle en Bash

Una razón común por la que la gente quiere aprender el shell de Unix es desbloquear el poder del procesamiento por lotes. Si desea realizar un conjunto de acciones en muchos archivos, una de las formas de hacerlo es mediante la construcción de un comando que itere sobre esos archivos. En terminología de programación, esto se denomina control de ejecución, y uno de los ejemplos más comunes es el for bucle.

Un para loop es una receta que detalla qué acciones desea que realice su computadora para cada objeto de datos (como un archivo) que especifique.

El clásico bucle for

La terminal de Linux

  • Los 7 mejores emuladores de terminal para Linux
  • 10 herramientas de línea de comandos para el análisis de datos en Linux
  • Descargar ahora:hoja de referencia de SSH
  • Hoja de trucos de comandos avanzados de Linux
  • Tutoriales de línea de comandos de Linux

Un bucle fácil de probar es uno que analiza una colección de archivos. Probablemente no sea un bucle útil por sí solo, pero es una forma segura de probarse a sí mismo que tiene la capacidad de manejar cada archivo en un directorio individualmente. Primero, cree un entorno de prueba simple creando un directorio y colocando algunas copias de algunos archivos en él. Cualquier archivo funcionará inicialmente, pero los ejemplos posteriores requieren archivos gráficos (como JPEG, PNG o similares). Puede crear la carpeta y copiar archivos en ella usando un administrador de archivos o en la terminal:

$ mkdir example
        $ cp ~/Pictures/vacation/*.{png,jpg} example

Cambie el directorio a su nueva carpeta, luego enumere los archivos en él para confirmar que su entorno de prueba es lo que espera:

$ cd example
$ ls -1
cat.jpg
design_maori.png
otago.jpg
waterfall.png

La sintaxis para recorrer cada archivo individualmente en un bucle es:crear una variable (f para archivo, por ejemplo). A continuación, defina el conjunto de datos por el que desea que pase la variable. En este caso, recorra todos los archivos en el directorio actual usando * carácter comodín (el * el comodín coincide con todo ). Luego termine esta cláusula introductoria con un punto y coma (; ).

$ for f in * ;

Según sus preferencias, puede optar por presionar Return aquí. El shell no intentará ejecutar el ciclo hasta que se complete sintácticamente.

A continuación, defina lo que desea que suceda con cada iteración del ciclo. Para simplificar, utilice el archivo comando para obtener un poco de información sobre cada archivo, representado por la f variable (pero precedida de un $ para decirle al shell que intercambie el valor de la variable por lo que sea que la variable contenga actualmente):

do file $f ;

Termine la cláusula con otro punto y coma y cierre el ciclo:

done

Presiona Regresar para iniciar el ciclo de shell a través de todo en el directorio actual. El para loop asigna cada archivo, uno por uno, a la variable f y ejecuta su comando:

$ for f in * ; do
        > file $f ;
        > done
        cat.jpg: JPEG image data, EXIF standard 2.2
        design_maori.png: PNG image data, 4608 x 2592, 8-bit/color RGB, non-interlaced
        otago.jpg: JPEG image data, EXIF standard 2.2
        waterfall.png: PNG image data, 4608 x 2592, 8-bit/color RGB, non-interlaced

También puedes escribirlo de esta manera:

$ for f in *; do file $f; done
        cat.jpg: JPEG image data, EXIF standard 2.2
        design_maori.png: PNG image data, 4608 x 2592, 8-bit/color RGB, non-interlaced
        otago.jpg: JPEG image data, EXIF standard 2.2
        waterfall.png: PNG image data, 4608 x 2592, 8-bit/color RGB, non-interlaced

Tanto el formato multilínea como el formato de una sola línea son iguales a su shell y producen exactamente los mismos resultados.

Un ejemplo practico

Aquí hay un ejemplo práctico de cómo un bucle puede ser útil para la informática diaria. Suponga que tiene una colección de fotos de vacaciones que desea enviar a sus amigos. Sus archivos de fotos son enormes, lo que los hace demasiado grandes para enviarlos por correo electrónico e inconvenientes para cargarlos en su servicio para compartir fotos. Quiere crear versiones web más pequeñas de sus fotos, pero tiene 100 fotos y no quiere perder el tiempo reduciendo cada foto, una por una.

Primero, instala el ImageMagick comando usando su administrador de paquetes en Linux, BSD o Mac. Por ejemplo, en Fedora y RHEL:

$ sudo dnf install ImageMagick

En Ubuntu o Debian:

$ sudo apt install ImageMagick

En BSD, use puertos o pkgsrc. En Mac, usa Homebrew o MacPorts.

Una vez que instala ImageMagick, tiene un conjunto de nuevos comandos para operar en las fotos.

Cree un directorio de destino para los archivos que está a punto de crear:

$ mkdir tmp

Para reducir cada foto al 33 % de su tamaño original, prueba este bucle:

$ for f in * ; do convert $f -scale 33% tmp/$f ; done

Luego mira en el tmp carpeta para ver tus fotos a escala.

Puede usar cualquier cantidad de comandos dentro de un bucle, por lo que si necesita realizar acciones complejas en un lote de archivos, puede colocar todo su flujo de trabajo entre las do y hecho declaraciones de un para círculo. Por ejemplo, suponga que desea copiar cada foto procesada directamente a un directorio de fotos compartidas en su proveedor de alojamiento web y eliminar el archivo de fotos de su sistema local:

$ for f in * ; do 
    convert $f -scale 33% tmp/$f
    scp -i seth_web tmp/$f [email protected]:~/public_html
    trash tmp/$f ;
  done

Para cada archivo procesado por for bucle, su computadora ejecuta automáticamente tres comandos. Esto significa que si procesa solo 10 fotos de esta manera, se ahorra 30 comandos y probablemente al menos la misma cantidad de minutos.

Limitando tu bucle

Un bucle no siempre tiene que mirar todos los archivos. Es posible que desee procesar solo los archivos JPEG en su directorio de ejemplo:

$ for f in *.jpg ; do convert $f -scale 33% tmp/$f ; done
$ ls -m tmp
cat.jpg, otago.jpg

O, en lugar de procesar archivos, es posible que deba repetir una acción una cantidad específica de veces. Un para La variable del bucle se define por los datos que le proporcione, por lo que puede crear un bucle que itera sobre números en lugar de archivos:

$ for n in {0..4}; do echo $n ; done
0
1
2
3
4

Más bucles

Ahora sabe lo suficiente como para crear sus propios bucles. Hasta que se sienta cómodo con los bucles, utilícelos en copias de los archivos que desea procesar y, con la mayor frecuencia posible, use comandos con salvaguardas integradas para evitar que golpee sus datos y cometa errores irreparables, como cambiar accidentalmente el nombre de un directorio completo de archivos con el mismo nombre, cada uno sobrescribiendo al otro .

Para para avanzados temas de bucle, sigue leyendo.

No todos los shells son Bash

El para La palabra clave está integrada en el shell de Bash. Muchos shells similares usan la misma palabra clave y sintaxis, pero algunos shells, como tcsh, usan una palabra clave diferente, como foreach , en su lugar.

En tcsh, la sintaxis es similar en espíritu pero más estricta que en Bash. En el siguiente ejemplo de código, no escriba la cadena foreach? en las líneas 2 y 3. Es un aviso secundario que le advierte que todavía está en el proceso de creación de su bucle.

$ foreach f (*)
foreach? file $f
foreach? end
cat.jpg: JPEG image data, EXIF standard 2.2
design_maori.png: PNG image data, 4608 x 2592, 8-bit/color RGB, non-interlaced
otago.jpg: JPEG image data, EXIF standard 2.2
waterfall.png: PNG image data, 4608 x 2592, 8-bit/color RGB, non-interlaced

En tcsh, ambos foreach y fin debe aparecer solo en líneas separadas, por lo que no puede crear un para bucle en una línea como puedas con Bash y shells similares.

Para bucles con el comando find

En teoría, podría encontrar un shell que no proporcione un para función de bucle, o puede que prefiera usar un comando diferente con funciones adicionales.

El encontrar El comando es otra forma de implementar la funcionalidad de un for bucle, ya que ofrece varias formas de definir el alcance de los archivos que se incluirán en su bucle, así como opciones para el procesamiento en paralelo.

El encontrar El comando está destinado a ayudarlo a encontrar archivos en sus discos duros. Su sintaxis es simple:proporciona la ruta de la ubicación que desea buscar y busca encuentra todos los archivos y directorios:

$ find . 
.
./cat.jpg
./design_maori.png
./otago.jpg
./waterfall.png

Puede filtrar los resultados de la búsqueda agregando una parte del nombre:

$ find . -name "*jpg"
./cat.jpg
./otago.jpg

Lo bueno de buscar es que cada archivo que encuentra se puede introducir en un bucle usando -exec bandera. Por ejemplo, para reducir solo las fotos PNG en su directorio de ejemplo:

$ find . -name "*png" -exec convert {} -scale 33% tmp/{} \;
$ ls -m tmp
design_maori.png, waterfall.png

En el -exec cláusula, los caracteres de paréntesis {} reemplazar cualquier artículo encontrar está procesando (es decir, cualquier archivo que termine en PNG que haya sido localizado, uno a la vez). El -ejecutivo La cláusula debe terminar con un punto y coma, pero Bash generalmente intenta usar el punto y coma para sí mismo. Usted "escapa" del punto y coma con una barra invertida (\; ) para que busque sabe tratar ese punto y coma como su carácter de terminación.

El encontrar El comando es muy bueno en lo que hace y, a veces, puede ser demasiado bueno. Por ejemplo, si lo reutiliza para encontrar archivos PNG para otro proceso fotográfico, obtendrá algunos errores:

$ find . -name "*png" -exec convert {} -flip -flop tmp/{} \;    
convert: unable to open image `tmp/./tmp/design_maori.png':
No such file or directory @ error/blob.c/OpenBlob/2643.
...

Parece que encontrar ha localizado todos los archivos PNG, no solo los que están en su directorio actual (. ), sino también aquellos que procesó antes y colocó en su tmp subdirectorio. En algunos casos, es posible que desee buscar para buscar en el directorio actual más todos los demás directorios dentro de él (y todos los directorios en esos ). Puede ser una poderosa herramienta de procesamiento recursivo, especialmente en estructuras de archivos complejas (como directorios de artistas musicales que contienen directorios de álbumes llenos de archivos de música), pero puede limitar esto con -max depth opción.

Para encontrar solo archivos PNG en el directorio actual (excluyendo subdirectorios):

$ find . -maxdepth 1 -name "*png"

Para buscar y procesar archivos en el directorio actual más un nivel adicional de subdirectorios, incremente la profundidad máxima en 1:

$ find . -maxdepth 2 -name "*png"

Su valor predeterminado es descender a todos los subdirectorios.

Looping por diversión y beneficio

Cuanto más utilice los bucles, más tiempo y esfuerzo ahorrará, y mayores serán las tareas que podrá abordar. Eres solo un usuario, pero con un ciclo bien pensado, puedes hacer que tu computadora haga el trabajo duro.

Puede y debe tratar el bucle como cualquier otro comando, manteniéndolo a mano para cuando necesite repetir una sola acción o dos en varios archivos. Sin embargo, también es una puerta de entrada legítima a la programación seria, por lo que si tiene que realizar una tarea compleja en cualquier cantidad de archivos, tómese un momento de su día para planificar su flujo de trabajo. Si puede lograr su objetivo en un archivo, envuelva ese proceso repetible en un para loop es relativamente simple, y la única "programación" requerida es una comprensión de cómo funcionan las variables y la organización suficiente para separar los archivos no procesados ​​de los procesados. Con un poco de práctica, puede pasar de ser un usuario de Linux a un usuario de Linux que sabe cómo escribir un bucle, ¡así que salga y haga que su computadora trabaje para usted!


Linux
  1. Cómo usar los comandos del historial de Bash

  2. ¿Cómo depurar un script Bash?

  3. ¿Cómo detener el script Loop Bash en la terminal?

  4. ¿Cómo escribir un entero en un archivo binario usando Bash?

  5. Cómo obtener el estado de salida de un bucle en bash

Golpear mientras se repite

Golpe para bucle

Golpear hasta bucle

Bash scripting:cómo escribir datos en archivos de texto

Shell Scripting para principiantes:cómo escribir Bash Scripts en Linux

Cómo ejecutar un script Bash