=====Tutorial de Programación en Bash===== [[Bash]] es una [[interpretes de comandos|shell]], que además cuenta con un //lenguaje de comandos interpretado// incorporado. Esto te permite escribir [[script|guiones]] y correrlos directamente en tu entorno. Si ya has completado [[lenguaje_del_interprete_de_comandos|el primer Tutorial del lenguaje de intérprete de comandos]] y sabes cómo hacer [[script|guiones simples de programación]], sin dudas este tutorial te enseñará algunas de sus características más avanzadas de Bash. ====Variables==== Las variables de bash son las mismas que en otros lenguajes de programación. No necesita especificarlas. #!/usr/local/bin/bash NAME="Tutoriales texto-plano.xyz" echo $NAME launchdate="Feb 28, 2023" echo $launchdate ===Varibles Globales y Locales=== Las Variables Globales son accesibles desde cualquier lugar del guión. Las variables locales sólo son accesibles dentro del mismo. Por ejemplo, una variable local utilizada unicamente en dentro de una función: #!/usr/local/bin/bash #Define una variable global de bash GLOBAL_VAR="valor de variable global" function hola { #Define variable local de bash local LOCAL_VAR="valor de variable local" echo $LOCAL_VAR echo $GLOBAL_VAR ## Esto será accesible aquí } echo $LOCAL_VAR ## Esto no será accesible aquí echo $GLOBAL_VAR ===Variable de Sistema=== Las variables de sistema son responsables de definir aspectos del intérprete de comando Bash. Estas variables son mantenidas por Bash en sí. Podremos modificar tales variables para cambiar aspectos del Shell. Utiliza el comando ''env'' para presentar todas las variables disponibles de Bash. env Generalmente se suele definir estas variables en mayúsculas, por ejemplo: ''PATH'', ''SHELL'', ''HOME'', ''LANG'', ''PWD'' y muchas mas. ==== Citas ==== En muchos lenguajes de programación una práctica estándar citar la cadena. Las citas se utilizan para referenciar texto, ficheros con caracteres de espacio. ===Cita con cadena=== No existe diferencia al utilizar apóstrofo '''...''' o comillas ''"..."'' mientras operas con textos simples y cadenas. El siguiente guion correrá sin errores y presentará el mensaje indicado y creará ambos directorios: #!/usr/local/bin/bash echo 'Cadena apostrofada' echo "Cadena entrecomillada" mkdir 'Directorio 1' mkdir "Directorio 2" ===Citas con Variables=== Recuerda que las expansión de variables de Bash __únicamente operará con las comillas__. Si defines cualquier variable en comillas simples, ¡no funcionarán! Ejecuta el siguiente guion. La primer echo presentará el valor de la variable (ej. ''Bienvenid@ ~fulana''). Pero la segunda variable solo presentará ''$NOMBRE'' porque está entre comillas simples: #!/usr/local/bin/bash NOMBRE="Bienvenid@ ~$USER" echo "$NOMBRE" echo '$NOMBRE' ====Depuración en Bash ==== El guionado de Bash provee una funcionalidad de depuración durante el tiempo de ejecución. Emplea el comando ''set -xv'' dentro del guion o en la línea de comando cuando ejecutes el guion para depurarlo. ===Depurado durante la ejecución=== Utiliza Bash con el argumento ''-xv'' para depurar al tiempo de ejecución de un guión de bash: $ bash -xv guion.sh ===Depurado de un guión=== Si deseas activar la depuración __dentro del mismo guion__, podrás depurar cierta parte del guion. #!/usr/local/bin/bash set -xv # Esta línea activa el depurado cd /var/log/ for i in "*.log"; do du -sh $i done Ahora corre el guion... $ ./guion.sh ...y obtendrás resultados como: cd /var/log/ + cd /var/log/ for i in "*.log"; do du -sh $i done + for i in '"*.log"' + du -sh boot.log mysqld.log post111.log post1121.log yum.log 0 boot.log 32K mysqld.log 0 post111.log 0 post1121.log 4.0K yum.log ====Código de Salida==== Un //código de salida// en Bash es un valor en código que representa el resultado de la ejecución apropiada de un programa, representado por un valor entre 0 y 255. Tal número denota el status de salida del último comando introducido, en otras palabras, es la indicación que da - al cese de su ejecución - el proceso hijo, al retornar al su proceso padre. | ''0'' - Success | Un //valor cero// (0) representa éxito. | | ''1-255'' Failure | Un //valor no cero// representa un fracaso. | ===Ejemplo=== Escribe un programa para escribir una cadena de texto en ''/etc/fichero_prueba.txt'' y ejecútalo para ver si funciona correctamente: #!/usr/local/bin/bash echo "Viva Bash, más rápido que un flash!" > /tmp/fichero_prueba.txt if [ $? -eq 0 ]; then echo "Funciona! Viva el Software Libre!" else echo "Lo siento, no puedo escribir en /tmp/fichero_prueba.txt" fi Este fichero buscará la cadena ''fulana'' en el fichero ''/etc/passwd''. #!/usr/local/bin/bash STRING="fulana" if grep ${STRING} /etc/passwd then echo "Si! Encontré la cadena" else echo "Buu!, no encontré la cadena" fi ====Entrada de Usuario==== El comando **read** se utiliza realizar entrada de datos interactiva. Para que el sistema aguarde tu entrada y la almacene en una variable al presionar la **tecla Intro** es la siguiente: $ read mivariable También podrás indicar algún texto que se presentará a modo de información, a la hora de solicitar la entrada: read -p "Dime tu nombre de usuari@: " miusuario Podrás utilizar el argumento **-sp** para no mostrar lo que tecleas (útil para guardar secreto en pantalla). $ read -sp "Dime de que equipo eres fanátic@: " miequipo Utiliza en un guion de Bash la funcionalidad del comando //read// para solicitar el ingreso de datos al usuario: #!/usr/local/bin/bash read -p "Ingresa tu nombre de usuari@: " miusuario read -sp "Dime de qué equipo eres fanátic@: " miequipo echo -e "\nTu nombre de usuari@ es $miusuario y tu equipo favorito es $miequipo" ==== Operadores ==== Los [[operadores en unix]] permiten realizar distinto tipo de operaciones en la shell. Bash cuenta con los mismos operadores, y extiende su utilización, A continuación encontrarás ejemplos de su uso en Bash. ===Operadores aritméticos ==== En Bash podrás encerrar entre paréntesis dobles ''(())'' para realizar las operaciones aritméticas sobre variables constituidas por valores numéricos, según esta sintaxis: (expresion)) (variable1+variable2)) (variable1-variable2)) (variable1*variable2)) (variable1/variable2)) ==Ejemplo de operadores aritméticos== Este guion permite ingresar dos valores numéricos para realizar las cinco operaciones básicas: #!/usr/local/bin/bash read -p "Ingresa un valor numérico: " n1 read -p "Ingresa otro valor numérico: " n2 echo "La Suma de $n1 + $n2 es = " $((n1+n2)) echo "La Resta de $n1 - $n2 es = " $((n1-n2)) echo "La División de $n1 / $n2 es = " $((n1/n2)) echo "La Multiplicación de $n1 * $n2 es = " $((n1*n2)) echo "El módulo entre $n1 % $n2 es = " $((n1%n2)) ===Operadores de comparación de cadena=== Utiliza doble igual (''=='') para comparar cadenas. if [ "$cadena" == "$cadena2" ] # True si es igual if [ "$cadena1" != "$cadena2" ] # True si es no igual ===Operadores de comparación numérica=== Como en todos los shells de tipo Unix, en Bash podrás utilizar operadores de comparación numérica. ((n1 == n2)) ## n1 es igual a n2 ((n1 != n2)) ## n1 es no igual a n2 ((n1 > n2)) ## n1 es mayor a n2 ((n1 >= n2)) ## n1 es mayor o igual a n2 ((n1 < n2)) ## n1 es menor a n2 ((n1 <= n2)) ## n1 es menor o igual a n2 ===Operadores de incremento y decremento=== Bash también cuenta con operadores de //incremento// (''++'') y //decremento// (''-- ## Ejemplo de Post-incremento $ variable=10 $ echo $((variable++)) ## Primero imprime 10 luego incrementa valor en 1 ## Ejemplo de Pre-incremento $ variable=10 $ echo $((++variable)) ## Primero incrementa valor en 1 luego imprime 11 En forma similar, puedes utilizar //operadores de pre-decremento// y //operadores de post-decremento//. ## Ejemplo de Post-decremento $ variable=10 $ echo $((variable--)) ## Primero imprime 10 y luego decrementa el valor en 1 ## Ejemplo de Pre-decremento $ variable=10 $ echo $((--variable)) ## Primero decrementa el valor en 1 luego imprime 9 ===== Condicionales ===== En un lenguaje de programación se utilizan bucles para repetir la ejecución de un bloque de código hasta que se satisfaga una condición definida. Esto es sumamente útil para realizar tareas repetitivas. Existen tres tipos de bucles principales: ''for'' (en caso), ''do'' ("hacer"), y ''do-while'' ("hacer-en tanto"). Las condiciones cuentan con introducción, nudo y desenlace. Introducen con su //identificador//, y desenlazan con un //identificador inverso//. ==== If-Else ==== Al igual que cualquier otro lenguaje de programación, ''if-else'' es la declaración de toma de decisiones de Bash. Decidirá la ejecución de un bloque de código en base al resultado del condicional ''if''. Si se evalúa verdadera la condición, ejecutará el código. Si la evalúa falsa, se ejecutará el bloque ''else'', cuya existencia es opcional. Se abre con ''if'' e incorpora la llamada ''then'' y se cierra con ''fi''. Opcionalmente, en el nudo puede incorporar una función condicional ''else'', con la sintaxis general: if [ condicion ] then hacer-algo else hacer-otra-cosa fi ===Ejemplo if-then=== Este programa solicita que ingreses una cifra, y te informa si es mayor a ''10''. #!/usr/local/bin/bash read -p "Ingrese un valor numérico: " myvar if [ $myvar -gt 10 ] then echo "El valor es mayor que 10" fi ===Ejemplos If-else=== Usando la declaración if-else ("//si-además//"), es posible ejecutar una declaración condicional si esta resulta falsa. Para ello se define un bloque de texto con ''else''. Este ejemplo implica un condicional por comparación numérica. Dará //Verdadero// si el valor ingresado por el usuario es mayor a ''10'', y si cumple tal prerrogativa ("then", "//luego//") presentará ''Correcto''; luego //si además// resulta //Falso// (de aquí el "if-else"), presentará ''No es correcto''. #!/usr/local/bin/bash read -p "Ingresa una cifra: " myvar if [ $myvar -gt 10 ] then echo "Correcto" else echo "No es correcto" fi Este ejemplo realiza una comparación de cadenas y las compara: #!/bin/bash read -p "Ingresa la primer cadena: " cadena1 read -p "Ingresa la segunda cadena: " cadena2 if [ "$cadena1" == "$cadena2" ] then echo "Ambas cadenas son iguales" else echo "Ambas cadenas son diferentes" fi ===Ejemplo if-elif-else=== La condición **elif** (else-if, "si además") se usa para incorporar múltiples condicionales ''if''. En este ejemplo de condicioniales //else-if//, debes indicar tus calificaciones. Si son mayores o iguales a ''80'', presentará ''Muy satisfactorio''. Si son inferiores a ''80'' o igual a ''50'' presentará ''Satisfactorio'', etcétera. #!/usr/local/bin/bash read -p "Ingresa tus calificaciones: " calificacion if [ $calificacion -ge 80 ] then echo "Muy satisfactorio" elif [ $calificacion -ge 50 ] then echo "Satisfactorio" elif [ $calificacion -ge 33 ] then echo "Aún no satisfactorio" else echo "Insatisfactorio" ===Ejemplo de condicionales if anidados === Con los **if anidados**, sólo se comprobará la veracidad de una condición anidada, si otra condición nido resulta verdadera. Por ejemplo, este programa solicita ingresar 3 valores numéricos como entrada y realiza una comparación numérica para analizar cuál es el valor mayor. #!/usr/local/bin/bash read -p "Cuantas copas tiene Boca :" boca read -p "Cuantas copas tiene River :" river read -p "Cuantas copas tiene Independiente :" independiente if [ $boca -gt $river ] then if [ $boca -gt $independiente ] then echo "Boca es el más grande" else echo "Independiente es el Rey de Copas" fi else if [ $river -gt $independiente ] then echo "River es el más grande" else echo "Independiente es el Rey de Copas" fi fi ==== While ==== **While** es una estructura de control de bucle iterativo, que continúa ciclando ("iterando") hasta que el condicional suministrado dé falso. Se abre con ''while'' ("mientras") e incorpora la llamada ''do'' ("hacer") y se cierra con ''done'' ("realizado"). Opcionalmente, en el nudo puede incorporar una función condicional ''until'' ("hasta"), que continúará iterando hasta que se valide el condicional. También puede incorporar la acción ''break'' ("interrumpir"), con la sintaxis general: while condición do paso1 paso2 ... done ===Ejemplo de bucle While=== El siguiente bucle se ejecutará 5 veces y se detendrá cuando el valor de la variable ''num'' sea mayor que 5. #!/bin/bash num=1 while [ $num -le 5 ] do echo "$num" let num++ done ===Ejemplo de bucle While infinito=== Los bucles infinitos se ejecutan continuamente hasta que se detienen forzadamente por el usuario, presionando **Ctrl+c**. #!/usr/local/bin/bash while true do echo "Presione Ctrl+c para Salir" done Los bucles infinitos también pueden detenerse agregando alguna salida condicional al guion: #!/usr/local/bin/bash while true do if [condicion];then exit fi done En el caso anterior, cuando la ''condicion'' se convierta en verdadera, se saldrá del bucle. En este ejemplo, se utiliza un condicional para ingresar a través de //read// cualquier cadena y valor, resenta un mensaje con //echo// y utiliza la orden ''read'' para solicitar interacción del usuario a través del teclado). Sólo interrumpirá el bucle de solicitud condicional si se se introduce ''s'' o bien (indicado con **-o** ''S''), con lo cual interrumpirá el bucle: while true do echo "Introduce algo para procesar (ingresa S para salir)" read entradausuario if [ $entradausuario == "s" -o $entradausuario == "S" ] then break fi //Procesar lo ingresado... done ===Ejemplo de Bucle While de estilo C=== Bash también acepta nomenclatura similar a C para escribir un bucle while: #!/usr/local/bin/bash num=1 while((num <= 5)) do echo $num let num++ done ===Ejemplo de bucle While leyendo fichero=== Esta funcionalidad útil de bash permite que el bucle While lea el contenido de un fichero línea por línea. De esta forma se puede leer líneas y desarrollar alguna tarea: #!/bin/bash while read mivariable do echo $mivariable done < /tmp/mi_fichero.txt En este ejemplo el se leerá en bucle línea a línea de ''nombre_fichero.txt'' y asignará el valor a la variable ''mivariable''. ==== case ==== **case** ("En caso") permite delimitar **casos de condicionales**. La introducción es ''case'', el nudo incorpora el caso, que deben definirse en una línea aislada delimitados por un '')''. Si indicas los casos separados por un ''|'' significa "o también". Un caso nomenclado con ''*)'' indica se interpreta como "todos los demás". Cada caso debe contar con un separador de línea '';;''. El desenlace es ''esac''. ===Ejemplo de múltiples cadenas en case === Se pueden definir más de una cadena para el patrón de coincidencias en una declaración case. user=`whoami` # pone el nombre de usuari@ en # la variable $user. case $user in fulana) echo "Hola fulana. Sé que te gusta saber la hora, de modo que te la presento abajo." date ;; sultano) echo "Hola Sultano, recuerda tu lista de tareas pendientes." cat /home/sultano/sultano_to_do.txt ;; sosa|molina) echo "Hola. No olvides vigilar la carga en el sistema. El tiempo de encendido del mismo es:" uptime ;; *) echo "Hola, quien quiera que seas. ¡Ponte a obrar por la Liberación, y recuerda!" fortune doctrina ;; esac >La declaración **case** es más útil y rápida para procesar que un condicional else-if. En lugar de revizar todas las condiciones if-else, la declaración case selecciona directamente el bloque a ejecutar basada en una entrada condicional. ===Ejemplo de coincidencia de patrones en case=== En las declaraciones //case// puedes utilizar caracteres comodines como ''*'', ''?'' y ''[]''. Aún así, algunas de las expansiones no funcionarán. >Ahora puedes utilizar ''shopt -s extglob'' para emplear coincidencia de patrones avanzada. #!/usr/local/bin/bash read -p "Ingresa una cadena:" choice shopt -s extglob case $choice in a*) ### coincide todo lo que comience con "a" #Aquí va un guion ;; b?) ### coincide cualquier cadena de dos caracteres que comience con "b" #Aquí va otro guion ;; s[td]) ### coincide "st" o "sd" #Aquí va otro guion ;; r[ao]m) ### coincide "ram" o "rom" #Aquí va otro guion ;; me?(e)t) ### coincide "met" or "meet" #Aquí va otro guion ;; @(a|e|i|o|u)) ### coincide una vocal #Aquí va otro guion ;; *) ### Coincide todo lo que no coincidió anteriormente #Aquí va un guion ;; esac ==== Bucle for ==== El bucle for se utiliza para realizar tareas repetitivas. La sintaxis básica de un bucle for, es la siguiente: for VARIABLE in PARAMETRO1 PARAMETRO2 PARAMETRO3 do //declaraciones del bucle for-loop done El bucle for ejecutará todos los parámetros definidos una vez. El nudo del bucle se comienza con la palabra reservada ''do'' ("hacer") y se termina con la palabra reservada ''done'' ("finalizado"). Todas las declaraciones deben escribir dentro del nudo del bucle. En esta sintaxis, ''VARIABLE'' se inicializa con los valores del ''PARAMETRO'' que puede ser accedido dentro del nudo del bucle. Estos parámetros pueden ser cualquier número, cadena, etcétera. ===Ejemplo Bucle For=== Este bucle básico itera 5 veces. #!/usr/local/bin/bash for i in 1 2 3 4 5 do echo "$i" done También puedes definir un //rango// para el bucle for, utilizando valores numéricos entre paréntesis ''()'' dentro del guión de Bash. #!/usr/local/bin/bash for i in {1..5} do echo "$i" done Los argumentos pueden estar formados por cadenas, como en: #!/usr/local/bin/bash for dia in DOM LUN MAR MIE JUE VIE SAB DOM do echo "$dia" done ===Ejemplo de Bucle For en estilo C=== En Bash es posible también puedes escribir un bucle for siguiendo nomenclatura de estilo C. Por ejemplo, para presentar números del ''1'' al ''10''. #!/usr/bin/bash for ((i=1; i<=10; i++)) do echo "$i" done ===Ejemplo de bucle For con ficheros=== Puedes acceder nombres de ficheros de uno en uno en un bucle for en el directorio especificado. Por ejemplo, podremos leer todos los ficheros del directorio de trabajo actual. En el siguiente bucle iterará la cantidad de veces coincidente con el número de ficheros disponibles en el directorio de trabajo. Seleccionará un fichero por cada iteración numérica. #!/usr/local/bin/bash for nombrefichero in * do ls -l $nombrefichero done ====Funciones==== Una función (también llamadas subrutinas o procedimientos) es una sección de código utilizada para realizar una tarea específica. Estas pueden ser reutilizadas. Sintaxis: nombreFuncion(){ // procedimiento de la función } nombreFuncion //llamada a la función ===Creación de una función === Crea tu primer función de un guion de bash para que presente la cadena "Hola Texto-plano.xyz!". Elabora el guion de Shell "saludo.sh" con el siguiente código fuente: #!/usr/local/bin/bash funSaludazo(){ echo "¡Hola texto-plano.xyz!"; } # llama a la función saludazo desde cualquier lugar del guion, por ejemplo, ahora mismo: funSaludazo Ejecuta el guion creado: $ ./saludo.sh ¡Hola texto-plano.xyz! ===Función con argumento=== Para indicarle un argumento a la función es necesario hacerlo de la misma manera que argumentarías cualquier comando desde el intérprete de comandos: agregándolos a continuación con un espacio en blanco. Las funciones reciben argumentos ''$1'', ''$2'', etcétera. En consecuencia, para crear un guion de shell con argumento podrías incluir un código semejante a este: #!/usr/local/bin/bash funArgumentos(){ echo "Primer Argumento: " $1 echo "Segundo Argumento: " $2 echo "Tercer Argumento: " $3 echo "Cuarto Argumento: " $4 } # Llama a funArgumentos desde cualquier lugar en el guion, utilizando parámetros como los indicados a continuación funArgumentos 1 Bienvenido a Texto-plano.xyz Ejecuta el guion desde la shell de Bash: $ ./saludo.sh Primer Argumetno : 1 Segundo Argumento : Bienvenido Tercer Argumento : a Cuarto Argumento : Texto-plano.xyz