linux:programacionbash
Diferencias
Muestra las diferencias entre dos versiones de la página.
| Revisión previa | |||
| — | linux:programacionbash [2018/12/21 11:35] (actual) – [if] alberto | ||
|---|---|---|---|
| Línea 1: | Línea 1: | ||
| + | ====== Programación Bash ====== | ||
| + | Un programa o //script// escrito en bash, tiene por convenio extensión **.sh** y consiste en un archivo de texto en el que se incluyen los comandos que serán ejecutados uno tras otro hasta llegar a término.\\ | ||
| + | |||
| + | ===== Ejecución de scripts ===== | ||
| + | |||
| + | Un script puede ejecutarse de varias maneras: | ||
| + | * **Lanzar un nuevo Bash con el script como argumento**: | ||
| + | * **Ejecutar el script desde línea de comandos**: Con la sintaxis **[nombre del script].sh**. Si el usuario que ejecuta el script no utiliza el Bash como intérprete de comandos, pueden producirse errores. Para evitarlo, puede forzarse el shell con el que se ejecutarán los comandos indicándolo en un comentario " | ||
| + | * **Con un punto .**: Idéntico a usar el comando **source**. Indica al bash que interprete las órdenes del archivo pasado como argumento. Sintaxis: **.[nombre del script]**. | ||
| + | * **Con el comando exec**: Ejecuta los comandos del archivo pasado como argumento. Sintaxis: **exec [nombre del script].sh**. | ||
| + | |||
| + | En todos los casos el usuario debe tener permisos de ejecución, y la ruta del archivo con el código debe estar en la variable de entorno $PATH (a no ser que se especifique en la misma línea de comandos). | ||
| + | |||
| + | ===== Buenas prácticas ===== | ||
| + | Algunos consejos a la hora de realizar scripts en Bash, pueden ser: | ||
| + | * No poner a los scripts nombres de comandos ya existentes, ya que puede dar lugar a problemas (por ejemplo, existe un comando **script**). También es recomendable ponerles la expensión **.sh** para distinguirlos rápidamente. | ||
| + | * Se recomienda también usar varios terminales para el proceso de depuración, | ||
| + | * Se deben usar comentarios, | ||
| + | |||
| + | ===== Códigos de retorno ===== | ||
| + | Cuando un script finaliza sin mayor problema retorna 0. Si se ha producido un error o se ha dado algún tipo de situación especial, retorna un valor comprendido entre 1 y 255.\\ | ||
| + | Para conocer el valor de retorno del último comando ejecutado, podemos leerlo en la variable especial $?. Es recomendable guardar su valor en una [[Linux: | ||
| + | |||
| + | Si deseamos que nuestro script retorne un valor diferente de 0 cuando finalice, lo especificamos con el comando **exit [valor de retorno]**. \\ | ||
| + | El comando exit fuerza la finalización del script. | ||
| + | |||
| + | ===== Ejecución condicional ===== | ||
| + | Se puede especificar diferentes comandos en la misma línea separándolos con **;**. De esta manera se ejecutarán uno detrás de otro, sin que se tenga en cuenta sus valores de retorno.\\ | ||
| + | |||
| + | Si se separa con **&& | ||
| + | |||
| + | Si dos comandos se separan con **||**, el segundo comando se ejecutará sólo si el anterior ha devuelto un valor diferente de 0 (ejecución no correcta).\\ | ||
| + | |||
| + | Para depurar, pueden usarse los comandos **true** y **false**: true siempre devuelve 0, y false siempre devuelve 1. | ||
| + | |||
| + | ===== Variables especiales ===== | ||
| + | Variables definidas por el shell Bash: | ||
| + | * **$$**: contiene el PID del shell que está en ejecución. | ||
| + | * **$PPID**: contiene el PID del proceso padre del shell que está en ejecución. | ||
| + | * **$0**: contiene el nombre del script en ejecución. | ||
| + | * **$1, $2, $3, ...**: Argumentos pasados al script por línea de comandos. Para referenciar los parámetros de orden superior a 9, hay que poner llaves (ejemplo_ ${12}) con el fin de evitar ambigüedades. Se puede usar el comando **shift** para desplazar los parámetros n posiciones. | ||
| + | * **$#**: Número de parámetros de entrada del script. | ||
| + | * **$*** y **$@**: Contiene los parámetros pasados por la línea de comandos. | ||
| + | * **$LINENO**: | ||
| + | |||
| + | ===== Comando test ===== | ||
| + | El comando test efectúa una serie de comparaciones entre archivos, cadenas de caracteres, valores aritméticos y entorno del usuario, devolviendo los valores 0, si la comparación es correcta (expresión verdadera) y 1 si no es así. | ||
| + | Tiene dos posibles sintaxis: **test [expresión]** y **[ expresión ]** (los espacios entre los corchetes son obligatorios). | ||
| + | * Test de archivos: | ||
| + | * **-f [archivo]**: | ||
| + | * **-d [archivo]**: | ||
| + | * **-r [archivo]**: | ||
| + | * **-w [archivo]**: | ||
| + | * **-x [archivo]**: | ||
| + | * **-e [archivo]**: | ||
| + | * **-s [archivo]**: | ||
| + | * **[archivo1] -nt [archivo2]**: | ||
| + | * **[archivo1] -ot [archivo2]**: | ||
| + | * **[archivo1] -ef [archivo2]**: | ||
| + | |||
| + | * Test de cadenas de caracteres: | ||
| + | * **-n [cadena]**: verdadero si la cadena no es nula. | ||
| + | * **-z [cadena]**: verdadero si la cadena es nula. | ||
| + | * **[cadena1] = [cadena2]**: | ||
| + | * **[cadena1] != [cadena2]**: | ||
| + | |||
| + | * Test aritmético: | ||
| + | * **[valor1] -eq [valor2]**: verdadero si ambos valores aritméticos son iguales (// | ||
| + | * **[valor1] -ne [valor2]**: verdadero si ambos valores aritméticos son diferentes (//not equal//). | ||
| + | * **[valor1] -lt [valor2]**: verdadero si valor1 es inferior al valor2 (//lower than//). | ||
| + | * **[valor1] -le [valor2]**: verdadero si valor1 es inferior o igual al valor2 (//lower or equal//). | ||
| + | * **[valor1] -gt [valor2]**: verdadero si valor1 es superior al valor2 (//greather than//). | ||
| + | * **[valor1] -ge [valor2]**: verdadero si valor1 es superior o igual al valor2 (//greather or equal//). | ||
| + | |||
| + | * Test de entorno de usuario: | ||
| + | * **-o [opción]**: | ||
| + | |||
| + | * Combinación de expresiones (todas ls anteriores combinadas): | ||
| + | * **! [expresión]**: | ||
| + | * **[expresión1] -a [expresión2]**: | ||
| + | * **[expresión1] -o [expresión2]**: | ||
| + | |||
| + | ===== Operaciones aritméticas ===== | ||
| + | Bash ofrece las herramientas necesarias para realizar operaciones aritméticas. | ||
| + | |||
| + | ==== expr ==== | ||
| + | El comando **expr** es un comando externo del bash.\\ | ||
| + | Su sintaxis es **expr [expresión]**. | ||
| + | Algunos de sus operadores llevan **\** delante para no confundirlos con caracteres especiales del Bash.\\ | ||
| + | Es necesario insertar un espacio entre elementos para que sean reconocidos correctamente. | ||
| + | |||
| + | ^ Operadores aritméticos ^ Nombre ^ Operadores lógicos ^ Nombre ^ | ||
| + | | + | Suma | \< | ||
| + | | - | Resta | \& | ||
| + | | \* | Multiplicación | ||
| + | | / | División entera | ||
| + | | % | Módulo | ||
| + | | \( ... \) | Paréntesis | ||
| + | | | ||
| + | | | ||
| + | |||
| + | ==== let ==== | ||
| + | Comando interno del Bash, por lo que es más eficiente, ya que no tienen que crear un subproceso para ejecutarse.\\ | ||
| + | No es necesario separar los elementos por un espacio, es más fácil trabajar con variables, ya que se pueden definir en una expresión y no es necesario incluir el símbolo **$**. \\ | ||
| + | Tiene más opreadores que expr, son más comunes y no requieren del símbolo **\** delante.\\ | ||
| + | Tiene dos posibles sintaxis: **let [expresión]** o **< | ||
| + | |||
| + | ^ Operadores aritméticos ^ Nombre ^ Operadores lógicos ^ Nombre ^ Otros operadores ^ Nombre ^ | ||
| + | | + | Suma | < | ||
| + | | - | Resta | && | ||
| + | | * | Multiplicación | ||
| + | | / | División entera | ||
| + | | % | Módulo | ||
| + | | < | ||
| + | | = | Asignación | ||
| + | | | ||
| + | | | ||
| + | |||
| + | |||
| + | ===== Entrada de datos: read ===== | ||
| + | El comando **read** permite introducir datos, de forma que sea posible realizar programas interactivos.\\ | ||
| + | Se pasan a continuación de **read** las variables a las que se les asignarán los datos (números o cadenas de caracteres).\\ | ||
| + | Si hay más datos que variables, a la última variable asignada se le asigna una cadena con todos los datos restantes.\\ | ||
| + | Si hay menos datos que variables, las variables sin datos se considerarán nulas.\\ | ||
| + | Si se llama **read** sin argumentos, la entrada pasara completa como cadena a la variable de Bash **$REPLY**. | ||
| + | Es posible que la entrada se ponga en la misma linea que una frase, con la opción **-p**, ejemplo: | ||
| + | <code bash> read -p " | ||
| + | | ||
| + | echo $edad | ||
| + | | ||
| + | ===== Estructuras de control ===== | ||
| + | Permiten ejecutar comandos en función del resultado de una expresión.\\ | ||
| + | Para este cometido son muy usados los comandos **test** y **let**. | ||
| + | |||
| + | ==== if ==== | ||
| + | Ejecuta una serie de comandos si la condición evaluada es verdad.\\ | ||
| + | Sintaxis: | ||
| + | <code bash>if [condición] | ||
| + | then | ||
| + | | ||
| + | else | ||
| + | | ||
| + | fi</ | ||
| + | |||
| + | ==== for ==== | ||
| + | Ejecuta la misma serie de comandos tantas veces como valores haya en una lista dada.\\ | ||
| + | En cada iteración una variable toma el valor de la lista considerado en esa iteración.\\ | ||
| + | Sintaxis: | ||
| + | <code bash>for [variable] in [lista de valores] | ||
| + | do | ||
| + | | ||
| + | done</ | ||
| + | |||
| + | Es muy interesante el uso de caracteres genéricos en el uso de directorios y archivos, a la hora de definir una lista. | ||
| + | |||
| + | ==== while ==== | ||
| + | Se ejecutarán una serie de comandos mientras la condición sea válida.\\ | ||
| + | Sintaxis: | ||
| + | <code bash> | ||
| + | do | ||
| + | | ||
| + | done</ | ||
| + | |||
| + | |||
