Descargue como DOCX, PDF, TXT o lea en línea desde Scribd
Descargar como docx, pdf o txt
Está en la página 1de 19
Introduccin a la programacin de
scripts de shell con Bash
Guillermo Ontan Ledesma GrULLA guillermo.ontanon@hispalinux.es Copyright 2002 por Guillermo Ontan Historial de revisiones Revisin 0.1 26 de Mayo de 2002 Versin inicial, creada para el seminario del 22 de Mayo de 2002 en la EUPLA.
Tabla de contenidos 1. Sobre este documento 2. Introduccin 3. Los caracteres especiales ms comunes 4. Variables y parmetros 5. Uso de las comillas 6. Tests 7. Estructuras de control 8. Globbing 9. Redirecciones 10. Comandos internos de Bash 11. Comandos y filtros externos 12. Un ejemplo prctico: creacin de nuevos usuarios. 1. Sobre este documento Este documento es una introduccin a la programacin de scripts y es intencionadamente incompleto, no pretende, al menos de momento, ser una referencia completa. Este documento est fuertemente basado en la Advanced Bash Scripting Guide y, en mucha menor medida, en la pgina de manual de Bash. La ABSG es una referencia bastante completa, bien explicada y con montones de ejemplos, muy apropiado, tanto a modo de referencia como a modo de tutorial de introduccin.
2. Introduccin Una shell es un intrprete de comandos, es la aplicacin que permite al usuario comunicarse con el sistema operativo y darle rdenes. Existen montones de shells, algunos ejemplos: o Bourne Shell (sh) - La shell clsica que se encuentra en todos los sistemas UNIX. o Korn Shell (ksh) o C Shell (csh) o Bourne Again Shell (bash) - La shell de GNU que se encuentra en todos los sistemas Linux y en muchos otros UNIX. Es la que vamos a utilizar. La shell no solo es capaz de interpretar comandos, puede programarse usando ficheros de texto que sta interpretar, se llaman scripts y la shell ofrece construcciones y facilidades para facilitar su programacin. Los scripts de shell son muy tiles para ciertos tipos de tareas: o Tareas administrativas: algunas partes de los sistemas UNIX son scripts de shell, para poder entenderlos y modificarlos es necesario tener alguna nocin sobre la programacin de scripts. o Tareas tediosas que solo se van a ejecutar una o dos veces, no importa el rendimiento del programa resultante pero si conviene que su programacin sea rpida. o Hacer que varios programas funcionen como un conjunto de una forma sencilla. o Pueden ser un buen mtodo para desarrollar prototipos de aplicaciones ms complejas que posteriormente se implementarn en leguajes ms potentes. o Conocer a fondo la shell aumenta tremendamente la rapidez y productividad a la hora de usarla, incluso fuera de los scripts. Si un script de shell se queda pequeo para lo que queremos hacer, existen otros lenguajes interpretados mucho ms potentes como Perl, TCL o Python.
3. Los caracteres especiales ms comunes Como en cualquier lenguaje de programacin, en bash hay una serie de caracteres y palabras reservadas que tienen un significado especial: #!/bin/sh Todos los scripts de shell empiezan con esta linea, que sirve para decirle al sistema operativo que se trata de un fichero ejecutable y que sepa cual es el intrprete que lo tiene que interpretar. # Comentario: todo lo que haya tras l en una lnea es ignorado. ; Separa dos comandos: echo "la fecha de hoy es: " ; date . Seguido del nombre de un fichero, hace que el contenido de ese fichero sea interpretado por la shell como si fuese parte del script, es como un #include de C. ' " Distintas formas de entrecomillar cadenas que se explican con detalle ms adelante. ` Se ejecuta lo que hay entre las comillas como un comando y se sustituye su salida: echo `date` \ Escapa el siguiente caracter, haciendo que se interprete literalmente. $ Accede al valor de una variable: echo $PATH ~ Equivale al directorio 'home' del usuario, es equivalente a leer el valor de la variable de entorno HOME: echo ~ echo $HOME & Escrito despus de un comando, hace que ste se ejecute en segundo plano. Esto quiere decir que el script no esperar a que el comando retorne antes de ejecutar la siguiente instruccin. Los dems caracteres se irn introduciendo sobre la marcha.
4. Variables y parmetros Variables de entorno . Hay una serie de variables afectan al comportamiento de la shell, tanto a la hora de trabajar de forma interactiva como desde los scripts que sta interpreta. Estas variables pueden ser accedidas y modificadas en la linea de comandos y tambin en los scripts. Se puede ver el valor de todas las variables de entorno definidas en un momento dado invocando al comando set sin argumentos. Algunas variables especialmente tiles y su significado: $HOME Directorio 'home' del usuario. $PATH Rutas en las que la shell busca los ejecutables cuando se invoca un comando. $? Esta variable contiene el valor de salida del ltimo comando ejecutado, es til para saber si un comando ha finalizado con xito o ha tenido problemas. Un '0' indica que no ha habido errores, otro valor indica que s ha habido errores. $UID Identificador del usuario que ejecuta el script. $! Identificador de proceso del ltimo comando ejecutado en segundo plano. Declaracin y uso de variables . No es necesario declarar las variables, basta con asignar un valor a una variable para crearla. Para acceder al valor que contiene una variable se usa el caracter $, de la siguiente forma: variable = `date` echo $variable Parmetros recibidos por un script . Como cualquier programa, los scripts pueden recibir parametros en la linea de comandos, los parametros recibidos se guardan en una serie de variables que el script puede consultar. Estas variables tienen los siguiente nombres: $1 $2 $3 .... ${10} ${11} .... La variable $0 contiene el nombre con el que se ha invocado al script. El comando shift mueve todos los parametros una posicin a la izquierda, esto hace que el parametro que haya en $1 desaparezca, y sea reemplazado por el que haba en $2. La variable $# contiene el nmero de parametros que ha recibido el script. $* contiene todos los parametros juntos en una sola cadena.
5. Uso de las comillas En general las comillas se usan para prevenir que la shell interprete ciertos caracteres dentro de una cadena y para que tome una cadena con espacios como una sola palabra.. Comillas dobles . En general los caracteres especiales no son interpretados cuando estn entre comillas dobles. Sin embargo algunos de ellos s son interpretados: $ Esta permitido referenciar variables dentro de las comillas dobles. \ Se pueden escapar caracteres. ` Se puede realizar sustitucin de comandos, esto es, ejecutar un comando y sustituir la cadena por su salida. Comillas simples . Dentro de las comillas simples todos los caracteres son interpretados literalmente, ninguno de los caracteres especiales conserva sus significado dentro de ellas. Comillas invertidas . Poner una cadena entre comillas invertidas supone ejecutar su contenido como un comando y sustituir su salida.
Anterior Siguiente
6. Tests Un test es una expresin que permite evaluar si una expresin es verdadera o falsa. Los tests no slo operan sobre los valores de las variables, tambin permiten conocer, por ejemplo, las propiedades de un fichero. Los tests se usan, principalmente, en la estructura if then else fi para determinar qu parte del script se va a ejecutar. Un if puede evaluar, adems de un test, otras expresiones, como una lista de comandos (usando su valor de retorno), una variable o una expresin aritmtica. Este es un ejemplo del uso de if: if grep grulla fichero.txt > /dev/null then echo "fichero.txt contiene la cadena grulla" else echo "fichero.txt no contiene la cadena grulla" fi Hay dos formas distintas de escribir un test, [ ] y [[ ]]. No son equivalentes, (por ejemplo los operadores && || < y > solo funcionan en la ltima) pero de momento las diferencias son irrelevantes. if [[ test ]] then comando else comando fi A continuacin se listan los tests ms tiles. Tests de ficheros . Estos tests toman como argumento el nombre de un fichero y devuelven verdadero o falso: if [ -e fichero ] then echo "\"fichero\" existe" fi -e Verdadero si el fichero existe. -f Comprueba que el fichero es un fichero regular (que no es ni un directorio, ni un dispositivo). -d Devuelve verdadero si se trata de un directorio. -h Cierto si el fichero es un enlace simblico. -r Cierto si se tiene permiso para leer el fichero. -w Cierto si se tiene permiso para escribir el fichero. -x Cierto si se tiene permiso para ejecutar el fichero. Operadores de comparacin de enteros . Toman dos valores y devuelven verdadero o falso: [ "$a" -eq "$b" ] -eq igual a -ne no es igual a -gt es mayor que -ge es mayor o igual que -lt es menor que -le es menor o igual que Operadores de comparacin de cadenas . Comparan dos cadenas y devuelven verdadero o falso. Es importante saber que se puede usar el "Globbing" en las cadenas a comparar. = == Comparacin de igualdad != Comparacin de desigualdad. El operador ! se puede colocar delante de cualquier test para negar su resultado. < y > Menor que y mayor que.
Anterior Inicio Siguiente Uso de las comillas Estructuras de control
Anterior Siguiente
7. Estructuras de control Como en cualquier lenguaje de programacin, la shell ofrece estructuras que permiten controlar el flujo de ejecucin de los scripts. Bucle for . Su sintaxis bsica es la que sigue: for var in lista de valores do comandos done La variable $var toma el valor del siguiente valor de la lista en cada iteracin. Un ejemplo: for i in `ls *.sh` do if [ -x "$i" ] then echo "El fichero \"$i\" es ejecutable" fi done Bucle while . Sintaxis: while [ condicion ] do comandos done condicion puede ser, al igual que en un if, cualquier test, comando o expresin, el bucle se ejecutara mientras que la condicin devuelva verdadero, es decir, cero. En los bucles break y continue tienen el mismo funcionamiento que en otros lenguajes. break termina el bucle y continue salta a la siguiente iteracin. Case . Como en otros lenguales case sirve para ejecutar una zona de cdigo u otra, en funcin del valor de una expresin o variable: case $var in valor ) comandos ;; valor2 ) comandos ;; esac El funcionamiento de case puede verse en los scripts de inicio del sistema, lo usan para discernir si han sido llamados con los parametros start restart stop o algn otro.
Anterior Inicio Siguiente Tests Globbing
Anterior Siguiente
8. Globbing El globbing, tambin conocido por "filename expansion", es decir, expansin de nombres de ficheros, es el tratamiento que hace la shell cuando encuentra un nombre de fichero. Cuando se le indica a la shell el nombre de un fichero, algunos caracteres tienen un significado especial que la shell interpreta antes de hacer lo que tenga que hacer con ese nombre. Los caracteres son estos: * Corresponde con cualquier secuencia de cero o ms caracteres, con la excepcion de los ficheros cuyo nombre empieza con un punto. ? Corresponde con cualquier caracter, una sola vez. [] Corresponde con cualquiera de los caracteres o rangos de caracteres que contenga. ^ Niega la expresin que le sigue. {} Contiene varias expresiones separadadas por comas y corresponde a cualquiera de ellas.
Anterior Inicio Siguiente Estructuras de control Redirecciones
Anterior Siguiente
8. Globbing El globbing, tambin conocido por "filename expansion", es decir, expansin de nombres de ficheros, es el tratamiento que hace la shell cuando encuentra un nombre de fichero. Cuando se le indica a la shell el nombre de un fichero, algunos caracteres tienen un significado especial que la shell interpreta antes de hacer lo que tenga que hacer con ese nombre. Los caracteres son estos: * Corresponde con cualquier secuencia de cero o ms caracteres, con la excepcion de los ficheros cuyo nombre empieza con un punto. ? Corresponde con cualquier caracter, una sola vez. [] Corresponde con cualquiera de los caracteres o rangos de caracteres que contenga. ^ Niega la expresin que le sigue. {} Contiene varias expresiones separadadas por comas y corresponde a cualquiera de ellas.
Anterior Inicio Siguiente Estructuras de control Redirecciones
Anterior Siguiente
10. Comandos internos de Bash Un comando interno de bash es un comando que bash implementa y que ejecuta sin llamar a comandos externos. Por ejemplo, echo es un comando interno de bash y cuando se llama desde un script no se ejecuta el fichero /bin/echo. Esta es una lista de algunos de los comandos internos ms utilizados: echo Enva una cadena a la salida estndar, normalmente la consola o una tubera. read Lee una cadena de la entrada estndar y la asigna a una variable: echo -n "Introduzca un valor para var1: " read var1 echo "var1 = $var1" cd Cambia de directorio pwd Devuelve el nombre del directorio actual, equivale a leer el valor de la variable $PWD. pushd popd dirs pushd apila un directorio en la pila de directorios. popd lo desapila y cambia a ese directorio. dirs muestra el contenido de la pila. Estos comandos son muy tiles cuando un script tiene que navegar por un arbol de directorios. let Realiza operaciones aritmticas: let a=$b+7 export Hace que el valor de una variable est disponible para todos los procesos hijos de la shell. . source Estos dos comandos hacen que la shell cargue otro fichero. Es equivalente a #include en C/C++. exit Finaliza la ejecucin del script, recibe como argumento un entero que ser el valor de retorno del script. ps Ofrece un listado de los procesos que hay corriendo en la mquina, con diversa informacin sobre los mismos. fg Devuelve un proceso que estaba ejecutndose en segundo plano al primer plano. wait Detiene la ejecucin hasta que los procesos que hay en segundo plano terminan. kill Enva una seal a un proceso, normalmente para terminarlo.
Anterior Inicio Siguiente Redirecciones Comandos y filtros externos
Anterior Siguiente
11. Comandos y filtros externos En los scripts de shell es muy comm hacer un uso extensivo de un conjunto de filtros y comandos externos que realizan tareas especficas con una enorme potencia. Muchos de estos comandos son filtros de texto que reciben un flujo de texto (normalmente por la entrada estndar) y lo modifican de alguna forma, devolviendo el flujo modificado a la salida estndar. Comandos comunes ls Lista los contenidos de un directorio. cat Imprime los contenidos de un fichero en la salida estndar. Se suele combinar con redirecciones para filtrar los contenidos. tac (cat al revs) imprime los contenidos en orden inverso. cp Copia un fichero, grupo de ficheros o directorios. mv Mueve un fichero, ficheros o directorio a otra ruta. rm Elimina un fichero o ficheros. mkdir Crea un directorio. rmdir Elimina un directorio. chmod Cambia los permisos de un directorio. ln Crea un enlace a un fichero o directorio. find Busca ficheros segn su nombre dentro de un arbol de directorios. Filtros de texto sort Ordena el las lnas de texto por orden ascendente o descendente. uniq Elimina las lineas repetidas. expand Convierte los tabs en espacios. unexpand Convierte los espacios en tabs. cut Extrae campos de las lineas. colrm Elimina columnas de las lineas. paste Junta los ficheros por columnas. head Imprime slo las primeras lneas de la entrada. tail Imprime slo las ltimas lneas de la entrada. grep Imprime slo las lneas que coincidan con cierto patrn, el patrn puede ser una simple cadena o una expresin regular. Comandos que trabajan con ficheros tar Archiva grupos de ficheros en uno solo. Se suele combinar con gzip o bzip2 para crear paquetes comprimidos de varios ficheros. gzip gunzip Comprimen y descomprimen ficheros. bzip2 bunzip2 Comprimen y descomprimen ficheros. strings Busca cadenas dentro de ficheros binarios. basename Devuelve el nombre de un fichero por s slo, sin informacin sobre su ruta. dirname Devuelve la ruta de un fichero, quitando su nombre y dejando solamente el directorio. install Copia un fichero, permitiendo especificar permisos y dueo del mismo. til para instalar software.
Anterior Inicio Siguiente Comandos internos de Bash Un ejemplo prctico: creacin de nuevos usuarios.
Anterior
12. Un ejemplo prctico: creacin de nuevos usuarios. En este ejemplo se va a partir de un fichero de texto con los nombres y apellidos de una serie de futuros usuarios en lineas alternas: Guillermo Ontan Ledesma Otro Usuario Nuevo
No sabemos cuantos usuarios van a ser pero s sabemos que van a estar en este formato. Vamos a generar los nombres de usuario de forma que, por ejemplo, a Guillermo Ontan le corresponda el nombre de usuario gontanon. Leer los nombres y apellidos en un bucle . Lo primero que vamos a hacer es crear un bucle que lea el nombre y apellidos de un usuario en cada iteracin, para eso usamos un bucle while, una redireccin y el comando read: while read nombre do echo $nombre read apellido echo $apellido done < fichero.txt Generar los nombres de usuario . Para generar los nombres de usuario a partir de los datos que tenemos, se modifica el bucle que ya tenemos y usamos los comandos cut, tr y colrm combinados con las redirecciones, no es necesario conocer todos estos comandos, basta con mirar la pgina de manual cuando se necesite: while read nombre do nbe=`echo $nombre | tr [:upper:] [:lower:] | tr [] [aeioun] | colrm 2` read apellido apdo=`echo $apellido | tr [:upper:] [:lower:] | tr [] [aeioun] | cut -d ' ' -f1` user=$nbe$apdo echo $user done < fichero.txt Aadir el grupo y el usuario . Vamos a crear un grupo para el usuario y entonces crearemos el usuario. Hay que asignarle un identificador numrico a ambos, para eso vamos a aadir una variable contador, que inicializaremos en el valor que queramos que empiezen a aadirse, para todo esto se usarn los comandos groupadd, useradd, chpasswd y let: ID=3000
while read nombre # leemos el nombre de stdin do nbe=`echo $nombre | tr [:upper:] [:lower:] | tr [] [aeioun] | colrm 2` read apellido # lectura del apellido de stdin apdo=`echo $apellido | tr [:upper:] [:lower:] | tr [] [aeioun] | cut -d ' ' -f1` user=$nbe$apdo groupadd -g $ID $user echo "Creado el grupo $user, GID $ID" useradd -d /home/$user -g $user -m -k /etc/skel -c "$nombre $apellido" -u $ID $user echo "Creado el usuario $user, UID $ID" echo echo "$user:$user" | chpasswd let "ID=$ID+1" done < fichero.txt Recibir el fichero como parametro y comprobar su existencia . Por ltimo, podemos pulir un poco el script, recogiendo el nombre del fichero con los usuario como parametro y usando dos tests para comprobar que el parametro es correcto: #!/bin/sh
# Script de adicin de usuarios
ID=3000
# Comprobacin de que hemos recibido al menos un argumento if [ $# -ne 1 ] then echo "Debe introducir el nombre del fichero con los nombres de los usuarios." exit 1 fi
# Comprobacin de que el argumento recibido corresponde a un fichero if [ ! -f $1 ] then echo "El fichero $1 no existe o no es un fichero regular." exit 2 fi
while read nombre # leemos el nombre de stdin do # conversion a minusculas del nombre, eliminacion de las tildes y 's y # nos quedamos con la primera letra. nbe=`echo $nombre | tr [:upper:] [:lower:] | tr [] [aeioun] | colrm 2`
read apellido # lectura del apellido de stdin
# Conversion a minusculas del primer apellido y eliminacion de # tildes y 's apdo=`echo $apellido | tr [:upper:] [:lower:] | tr [] [aeioun] | cut -d ' ' -f1`
# Concatenacin de $nbe y $apdo user=$nbe$apdo
# Creacin del grupo del usuario groupadd -g $ID $user echo "Creado el grupo $user, GID $ID"