Administración UNIX: Programación en bash Antonio LaTorre atorre@fi.upm.es Septiembre 2014 atorre@fi.upm.es Administración UNIX: Programación en bash 1/1 bash (Bourne-Again Shell) • Shell de texto basada en el Bourne Shell • Creada por Brian Fox en 1989 • POSIX shell con extensiones (Cumple con SUS) • Software libre (parte del proyecto GNU) • Estándar de facto en la mayorı́a de Linux • Presente en casi todos los UNIX modernos Sintaxis básica mandato [parámetros...] atorre@fi.upm.es Administración UNIX: Programación en bash 2/1 Mandatos mandato [parámetros...] • Los mandatos se invocan usando el nombre del fichero ejecutable • El ejecutable tiene que estar dentro del PATH • Los parámetros se separan por uno o más espacios • Se pueden redirigir la entrada y salida estándar del proceso que se arranca • Se puede invocar mas de un mandato en secuencia • Se puede recuperar y operar con el valor de retorno del mandato invocado atorre@fi.upm.es Administración UNIX: Programación en bash 3/1 Mandatos Valor de retorno • Cuando terminan, todos los procesos tienen un valor de retorno (número entero) • La shell captura ese valor y lo almacena por si es necesario su uso posterior • El valor de retorno 0 indica terminación satisfactoria (el programa ha terminado sin problemas) • Un valor de retorno distinto de 0 suele indicar que se ha producido algún error. Diferentes valores de retorno (1, 2, 3...) se usan como códigos de error • La mayorı́a de shells tratan además el valor de retorno 0 como valor lógico verdadero y cualquier otro como falso atorre@fi.upm.es Administración UNIX: Programación en bash 4/1 Variables Declaración y expansión básica • bash permite declarar variables que almacenan secuencias de caracteres • Se declaran asignándoles un valor: nombre=valor • Se pueden convertir en variables de entorno usando el mandato export VAR1=12 export VAR1 • Se accede a su valor usando el operador prefijo de expansión $ mandato $VAR1 atorre@fi.upm.es Administración UNIX: Programación en bash 5/1 Variables Tipo, expansión aritmética • Las variables no tienen tipo explı́cito, y normalmente se tratan como cadenas de texto VAR=1+2 la variable valdrá la cadena “1+2” • bash puede operar con el valor de una variable como si fuese un número entero. Para ello se usa el entorno $(( )). Lo que haya dentro se resuelve como una operación matemática VAR=$((1+2)) la variable valdrá la cadena “3” Los nombres de variables se expanden automáticamente en esta construcción atorre@fi.upm.es Administración UNIX: Programación en bash 6/1 Variables de entorno • Valores con nombre que se almacenan en el entorno del sistema • Usadas por los procesos y servicios • Muestran parte del estado y caracterı́sticas de configuración del sistema • De sistema o de usuario • Ejemplos: • PATH: Rutas donde buscar ejecutables • PWD: Directorio actual • UID: Uid del usuario • ?: Valor del retorno del último mandato invocado • RANDOM: Generador de números aleatorios (bash) • El mandato env muestra todas las variables de entorno definidas atorre@fi.upm.es Administración UNIX: Programación en bash 7/1 Redirecciones bash permite redirigir la entrada y salida estándar de los procesos que crea • El operador < se usa para redirigir la entrada de un mandato a un fichero mandato [params...] < fichero • El operador > se usa para redirigir la salida de un mandato a un fichero mandato [params...] > fichero Se puede especificar el descriptor que se desea redirigir: mandato > fichero redirige la salida estándar mandato 2> fichero redirige la salida estándar de error • El operador >> es similar a >, pero escribe al final del fichero (append) atorre@fi.upm.es Administración UNIX: Programación en bash 8/1 Redirecciones • El operador &número permite referirse a otro descriptor de fichero • Combinado con los operadores < y > permite agrupar redirecciones • Ejemplo: mandato > fichero 2>&1 La salida estándar de error (2) se redirige al mismo sitio que la salida estándar (1) mandato >& fichero Ambas salidas estándar se redirigen al mismo fichero. atorre@fi.upm.es Administración UNIX: Programación en bash 9/1 Expansiones Expasión de nombre de fichero Los caracteres *, ?, [, ] se usan para reemplazar un patrón por la lista ordenada de todos los ficheros en el directorio actual que encajan con el patrón: Todos los ficheros de extensión txt ls *.txt Todos los ficheros con cualquier extensión de 3 caracteres: ls *.??? Todos los ficheros que empiezan por a, b o c: ls [abc]* atorre@fi.upm.es Administración UNIX: Programación en bash 10/1 Expansiones Expansión de llaves Útil para escribir secuencias repetitivas de argumentos: {a,b,c}d → ad bd cd fichero{1..3} → fichero1 fichero2 fichero3 {a..b}{1..2} → a1 b1 a2 b2 Expansión con substitución Expansión de variable con sustitución con la construcción ${var/patron/sub}: VAR=fichero.png EXT=.jpeg ${VAR/.png/$EXT} → fichero.jpeg atorre@fi.upm.es Administración UNIX: Programación en bash 11/1 Expansiones Expansión de tilde bash permite expresar invocaciones a mandatos anidados • Usando la sitaxis `mandato [params...]` se puede invocar a un mandato como parámetro de otro • bash ejecuta primero el mandato entre tildes ` (tecla a la derecha de la P en el teclado ES, no con confundir con el apóstrofe ’) primero, y lo sustituye en la invocación del segundo por su salida estándar (NO su valor de retorno) mandato1 param1 `mandato2 param2 param3` param4 atorre@fi.upm.es Administración UNIX: Programación en bash 12/1 Escapado • El operador \ se utiliza para escapar caracteres especiales como &, ", |, ; o el propio \ \& \"\| \; \\ • Para indicar que una secuencia de caracteres debe interpretarse como una cadena única se pueden usar las comillas simples (’) o dobles (”): • La comilla doble permite algunas expansiones, tales como la de variables. Habitual para evitar que una variable con espacios sea interpretada como múltiples argumentos. "${NOMBRE}" • La comilla simple no permite ninguna expansión. atorre@fi.upm.es Administración UNIX: Programación en bash 13/1 Secuencias de mandatos bash permite crear secuencias de mandatos usando operadores de concatenación • El operador ; se usa para crear una lista de mandatos. Los mandatos se ejecutan secuencialmente mandato1 [args...] ; mandato2 [args...] ; ... • El operador && es similar a un AND lógico perezoso: El segundo mandato solo se ejecuta si el primero terminó correctamente (retorno 0) mandato1 [args...] && mandato2 [args...] && ... atorre@fi.upm.es Administración UNIX: Programación en bash 14/1 Secuencias de mandatos • El operador || es similar a un OR lógico perezoso: El segundo mandato solo se ejecuta si el primero no terminó correctamente (retorno 6= 0) mandato1 [args...] || mandato2 [args...] || ... • El operador | crea una tuberı́a o pipe que comunica la salida estándar (fd 1) del primer mandato con la entrada estándar (fd 0) del segundo mandato1 [args...] | mandato2 [args...] | ... atorre@fi.upm.es Administración UNIX: Programación en bash 15/1 Secuencias de control if Condición if tı́pica • Las condiciones son a if <condición> then mandato1 ... elif <condición> then ... else ... fi su vez secuencias de mandatos, que se interpretan en función de su valor de retorno • El sub-bloque else se puede omitir • El sub-bloque elif puede aparecer 0 ó más veces if <cond>; then mandato1; ...; else mandato2; ...; fi atorre@fi.upm.es Administración UNIX: Programación en bash 16/1 Secuencias de control Condiciones [ ] • Es muy habitual evaluar condiciones usando el mandato test if test $VAR -gt 10 then echo "Es mayor que 10" fi • bash permite remplazar este mandato por sus parámetros entre corchetes [ ] if [ $VAR -gt 10 ] then echo "Es mayor que 10" fi atorre@fi.upm.es Administración UNIX: Programación en bash 17/1 Secuencias de control case while case <expresión> in caso_1 ) mandato1 mandato2;; caso_2 ) mandato3 ...;; ... esac while <condición> do ... done Se evalúa el resultado de la expresión, no su retorno atorre@fi.upm.es until until <condición> do ... done Administración UNIX: Programación en bash 18/1 Secuencias de control for • La lista está formada por for variable in <lista> do ... done select una secuencia de una o más cadenas separadas por espacios • La sentencia select select variable in <lista> do ... [break] done atorre@fi.upm.es muestra un pequeño menú con las opciones de la lista. break se emplea para romper el bucle Administración UNIX: Programación en bash 19/1 Algunos mandatos útiles true Mandato que no hace nada. Termina con valor de retorno 0 false Mandato que no hace nada. Termina con valor de retorno 1 echo Imprime por su salida estándar un mensaje pasado como parámetro echo hola hola echo $PATH /usr/sbin:/usr/bin:/sbin:/bin atorre@fi.upm.es Administración UNIX: Programación en bash 20/1 Algunos mandatos útiles cat Muestra el contenido de un fichero cat fichero1 éste es el contenido del fichero1 head Muestra las primeras lı́neas de un fichero tail Muestra las últimas lı́neas de un fichero Si no se indica fichero operan con la entrada estándar seq Genera secuencias de números atorre@fi.upm.es Administración UNIX: Programación en bash 21/1 Algunos mandatos útiles wc Cuenta lı́neas, palabras y bytes de un fichero wc /var/log/auth.log 433 5266 41533 /var/log/auth.log cut Selecciona columnas especı́ficas en ficheros de texto ls -l | cut -d’ ’ -f1 -rw-r-----rw-r----drwxr-xr-x Si no se indica fichero operan con la entrada estándar atorre@fi.upm.es Administración UNIX: Programación en bash 22/1 Algunos mandatos útiles grep Muestra la lı́neas de un fichero que presentan un patrón grep [OPTIONS] PATTERN [FILE...] cat fichero1 ésta es la primera lı́nea ésta es la segunda ésta es la tercera lı́nea grep lı́nea fichero1 ésta es la primera lı́nea ésta es la tercera lı́nea grep nos permite usar expresiones regulares. Si no se indica fichero, opera con la entrada estándar atorre@fi.upm.es Administración UNIX: Programación en bash 23/1 Algunos mandatos útiles sed Realiza transformaciones sobre cadenas de texto • Añadir y eliminar fragmentos • Reemplazar sub-cadenas • ... echo "Hola Mundo" | sed s/"Mundo"/"a todos"/g Hola a todos Opera con expresiones regulares (al igual que grep). Si no se indica fichero, opera con la entrada estándar atorre@fi.upm.es Administración UNIX: Programación en bash 24/1 Algunos mandatos útiles test Realiza comprobaciones y evalúa condiciones lógicas • Comprueba si un fichero existe test -f fichero • Comprueba si dos cadenas son iguales test STRING1 = STRING2 • Comprueba si un número es mayor que otro test INTEGER1 -gt INTEGER2 • ... Ejemplos: test -f fichero1 && cat fichero1 test $I -gt $MAX || I=$(($I+1)) atorre@fi.upm.es Administración UNIX: Programación en bash 25/1 Combinando mandatos en bash Ejemplos • test $PWD = /tmp && echo "Estamos en $PWD" Imprime un mensaje indicando el directorio en que nos encontramos, si éste es /tmp • cat /var/log/messages | grep "^A.*m$" | head -n2 Muestra las dos primeras lı́neas del fichero /var/log/messages que empiezan por A y acaban por m • cd /tmp; echo "probando" > prueba.txt; cd - Cambia al directorio /tmp, escribe el mensaje "probando" en el fichero prueba.txt y regresa al directorio original • grep "`date + %D`" /tmp/prueba.txt > /dev/null || date + %D > /tmp/prueba.txt atorre@fi.upm.es Administración UNIX: Programación en bash 26/1 Scripts en bash • Un bash script es un fichero de texto plano que contiene una serie de mandatos y operadores que pueden ser interpretados y procesados por bash • Mecanismo básico: invocar a bash como un mandáto, pasándole el script como parámetro bash mi script.sh • Alternativamente se pueden dar permisos de ejecución al fichero y lanzarlo con un programa más. Para que ésto funcione es necesario incluir una cabecera al principio del fichero (primera lı́nea) #!/bin/bash atorre@fi.upm.es Administración UNIX: Programación en bash 27/1 Scripts en bash Estructura básica Un script de bash contiene lı́neas con declaraciones de variables, secuencias de mandatos, sentencias de control... Ejemplo: #!/bin/bash # Leemos los parámetros de entrada CADENA=$1 FICHERO=$2 # Contamos las lı́neas de FICHERO en las # que aparece CADENA grep $CADENA $FICHERO | wc -l # Terminamos satisfactoriamente exit 0 atorre@fi.upm.es Administración UNIX: Programación en bash 28/1 Scripts en bash Parámetros de entrada Los scripts se pueden invocar pasando parámetros de entrada. Para acceder a ellos se usan variables especiales dentro del script • $# almacena el número de parámetros que se han pasado • $0 almacena el nombre del propio script • $1, $2, $3, ... almacenan los parámetros, por orden • $* almacena todos los parámetros como una sola cadena atorre@fi.upm.es Administración UNIX: Programación en bash 29/1 Scripts en bash shift Descarta el primer parámetro y desplaza los demás una posición VAR1=$1 VAR2=$2 Es lo mismo que VAR1=$1 shift VAR2=$1 read Lee uno o mas parámetros por la entrada estándar y los almacena en variables read VAR1 VAR2 VAR3 ... atorre@fi.upm.es Administración UNIX: Programación en bash 30/1 Scripts en bash Opciones Las argumentos opcionales se pueden tratar por medio de bloques case y usanso shift pero resulta más sencillo usar getops: while getopts ab: opcion do case $opcion in a) activar_a=1;; b) activar_b=1 valor_b="$OPTARG";; ?) printf "Usage: %s: [-a] [-b valor] args\n" $0 exit 2;; esac done Este método no sirve para múltiples parámetros por opción. atorre@fi.upm.es Administración UNIX: Programación en bash 31/1 Scripts en bash Ejemplo #!/bin/bash if [ $# -ne 3 ] then echo "uso: $0 <palabra> <letra> <repeticiones>" exit 1 fi PALABRA=$1 LETRA=$2 REP=$3 POS=1 while [ $POS -le $REP ] do echo ‘echo $PALABRA | sed s/$LETRA/A/g‘ "(repetición $POS)" POS=$(($POS+1)) done atorre@fi.upm.es Administración UNIX: Programación en bash 32/1 Scripts en bash Otro ejemplo #!/bin/bash echo "Parametro 1: $1" echo "Parametro 2: $2" echo "Parametro 3: $3" select OP in concatenar reemplazar salir do case $OP in "concatenar" ) echo $1$2$3 ;; "reemplazar" ) echo $1 | sed s/$2/$3/g ;; "salir" ) break ;; esac done atorre@fi.upm.es Administración UNIX: Programación en bash 33/1 Scripts en bash Funciones bash permite declarar funciones dentro de un script • Funcionan como sub-scripts • Se usan igual que otros mandatos • Pueden recibir parámetros, que se gestionan con $#, $*, $1, $2, ... • Tienen valor de retorno function nombre { ... return <valor> } atorre@fi.upm.es nombre () { ... return <valor> } Administración UNIX: Programación en bash 34/1 Scripts en bash Ejemplo con funciones #!/bin/bash echo "Dime dos numeros" read NUM1 NUM2 function sum { echo $(($1+$2)) return 0 } echo "Suma: "‘sum $NUM1 $NUM2‘ div () { if [ $2 = 0 ] then echo "ERROR. Denominador = 0" return 1 fi echo $(($1/$2)) return 0 } atorre@fi.upm.es RES_DIV=‘div $NUM1 $NUM2‘ if [ $? = 1 ] then echo $RES_DIV echo "No se puede dividir" else echo "Division: "$RES_DIV fi Administración UNIX: Programación en bash 35/1