Lo más básico
Al shell Bash, el intérprete de comandos estándar en Linux, le podemos pasar comandos desde una terminal o desde un script, que es un archivo de texto que contiene un pequeño programa.
‘Hola mundo’ en Bash
El script más sencillo es Hola mundo. Veamos cómo crearlo:
- crearemos el script con un editor de texto. En Linux disponemos de numerosos editores avanzados orientados a programación, con resaltado de sintaxis, como Gedit, Kwrite, Kate, Scite, etc.
- llamaremos a nuestro script hello.sh. A los scripts del shell se les suele poner la extensión .sh para identificarlos más fácilmente.
- en un script podemos incluir cualquier comando que se pueda ejecutar en el intérprete
de comandos. En nuestro caso, el contenido de hello.sh será el siguiente:
#!/bin/bash echo "Hola, mundo."
- la primera línea indica la aplicación que interpretará los comandos del script, en este caso Bash, cuyo ejecutable es /bin/bash.
- le daremos al script permisos de ejecución con el comando chmod:
$ chmod a+x hello.sh
- para ejecutar el script añadiremos al nombre del script la ruta del directorio
actual, "./", ya que el directorio donde se encuentra (nuestra carpeta
personal) no está en el PATH:
$ ./hello.sh
También podemos ejecutar el script llamando a bash:
$ bash hello.sh
En ambos casos obtendremos por la salida estándar (la pantalla) lo siguiente:
Comentarios
Las líneas que comienzan por el carácter "#" (excepto la primera), se consideran comentarios y son ignoradas por el intérprete de comandos.
Salir del script
El comando para terminar el script es exit. Este comando no es útil al final del script, pero sí para terminar el programa en algún punto intermedio, por ejemplo "si se da tal condición, entonces terminar". Además, el comando exit permite establecer el valor de retorno, el valor devuelto por el script.
Variables en los scripts
Para que una variable definida dentro de una función, bucle o estructura sea de ámbito local (sólo existe en esa estructura) debemos declararla como local con el comando local:
local j=8 |
Las variables que no se definan expresamente como locales, se definan donde se definan, serán de ámbito global, y por tanto, accesibles en cualquier lugar del programa.
Argumentos de los scripts
A un script se le pueden pasar argumentos.
- Dentro del script estos argumentos se almacenan en las variables de nombre $0, $1, $2, …, $9.
- La variable $0 almacena el nombre del script, mientras que $1, $2, …, $9 almacenan los argumentos propiamente dichos.
- Sólo hay nombre específico para los nueve primeros argumentos (más el propio nombre del comando), pero el comando shift hace posible utilizar y distinguir parámetros que están más a la derecha del noveno lugar en la llamada al script. Cuando se ejecuta el comando shift dentro del script, $2 se convierte en $1, $3 en $2, etc, y lo que hubiera sido $10 en $9, es decir, que se recorta la lista de argumentos una posición quitando el primero de ellos, con lo cual ya se puede referenciar. El comando shift deja inalterado $0 y puede utilizarse tantas veces como se desee.
- El número de argumentos que se le pasa al script está contenido en la variable $#.
- El conjunto de todos los argumentos está almacenado en la variable $*.
Veamos por ejemplo el siguiente script, llamado args.sh:
#!/bin/bash echo "$0 contiene $0" echo "$1 contiene $1" echo "$2 contiene $2" echo "En total hay $# parametros" |
Ejecutamos este script sin pasarle argumentos:
$ ./args.sh $0 contiene ./args.sh $1 contiene $2 contiene En total hay 0 parametros |
Ahora ejecutamos el script pasándole dos argumentos:
$ ./args.sh buenos dias $0 contiene ./args.sh $1 contiene buenos $2 contiene dias En total hay 2 parametros |
Veamos un ejemplo de script al que se le pasa sólo un parámetro. El comando de borrar de Linux rm no pide confirmar la operación de borrado si no se le pone la opción "-i". Esto es peligroso porque uno fácilmente puede olvidarse de teclear dicha opción y borrar lo que no quería borrar. Vamos a crear un script llamado del.sh que incluya dicha opción. Dicho archivo podría ser:
#!/bin/bash echo "Quiere borrar el archivo $1?" rm -i $1 |
Después de darle a este archivo el correspondiente permiso de ejecución con el comando chmod, podríamos borrar con confirmación el archivo file1 tecleando:
$ del.sh file1 |
Dentro del archivo de comandos, $0 valdría del y $1 valdría file.
Veamos ahora un script al que se le pasan dos parámetros. El programa cambio.sh intercambia el nombre de dos archivos:
#!/bin/bash mv $1 archivotemp mv $2 $1 mv archivotemp $2 |
Para ejecutar este programa haremos:
$ cambio.sh file1 file2 |
En este ejemplo $0 es cambio.sh, $1 es file1 y $2 es file2.
Veamos un ejemplo con mútiples argumentos. Si el programa del.sh que hemos hecho previamente lo hubiéramos utilizado en la forma:
$ del.sh *.f |
teóricamente debería borrar, con confirmación, todos los archivos Fortran del directorio (*.f). En la práctica no es así, porque $1 sólo almacena el primer archivo Fortran y es el único que borra. Para borrar todos el script del.sh podría ser:
#!/bin/bash echo "Hay # programas para borrar n" rm -i * |
Valor de retorno
Cuando se ejecuta un programa o comando devuelve un valor numérico, que será:
- cero (0) si el programa finalizó con éxito.
- distinto de cero si el programa no finalizó con éxito. Cada uno de los valores distintos de cero va asociado a una causa distinta: sabiendo este valor podemos saber por qué razón falló el programa.
El valor de retorno no se imprime por la pantalla, es decir, cuando un programa termina no saca por pantalla un cero u otro número, sino que el valor de retorno del último programa ejecutado queda almacenado en la variable especial $?.
Veamos un ejemplo:
#!/bin/bash echo "Listando archivo existente..." ls archivo_existente echo "El valor de retorno fue: $?" echo " " echo "Listando archivo inexistente..." ls archivo_inexistente echo "El valor de retorno fue: $?" |
Primero listamos un archivo existente: lo lista con éxito y por tanto el valor de retorno es 0. A continuación, listamos un archivo inexistente: como eso no es posible, el comando no termina con éxito y el valor de retorno es distinto de cero (en este caso 1).
Utilizaremos el valor de retorno para saber si los comandos del script han tenido éxito o no, pudiendo emplear esta información en sentencias condicionales.
El comando para terminar el script, exit, permite establecer el valor de retorno (el valor devuelto por el script), para así obtener información acerca de si el script ha tenido éxito o no y porqué. Por ejemplo:
#!/bin/bash if [ expresion1 ]; then Bloque 1 exit 0 else Bloque 2 exit 1 fi |
Evaluar expresiones
El comando que permite evaluar expresiones es test: el valor de retorno será cero (0) si la expresión es VERDADERO (TRUE), y uno (1) si la expresión es FALSO (FALSE). La sintaxis es:
test <expresion> |
Veamos un ejemplo:
#!/bin/bash a=7 b=8 test $a -eq $a echo $? test $a -eq $b echo $? |
Si ejecutamos el script obtendremos:
0 1 |
El primer comando quiere decir: ¿es $a igual a $a? Vemos que el valor de retorno es cero (0), lo cual indica que la expresión es VERDADERO: efectivamente $a es igual a $a. El segundo comando comprueba si $a igual a $b: el valor de retorno de test es uno (1), ya que la expresión es FALSO: $a no es igual a $b.
Existe otra sintaxis para evaluar una expresión, algo más clara:
[ expresion ] |
Veamos un ejemplo:
#!/bin/bash a=7 b=8 [ $a -eq $b ] echo $? |
Si ejecutamos el script obtendremos:
1 |
Algunos de los operadores que admite test son:
- para comparar enteros:
[ integer1 -eq integer2 ]
- -eq igual (equal).
- -ne distinto (not equal).
- -ge mayor o igual (greater than or equal).
- -gt mayor (greater than).
- -le menor o igual (less than or equal).
- -lt menor (less than).
- para comparar o aplicar a cadenas:
[ string1 = string2 ], [ -z string1 ]
- = igual.
- != distinto.
- -z la longitud de la cadena es cero.
- para comparar o aplicar a archivos:
[ file1 -nt file2] , [ -e file1 ]
- -nt fecha de modificación más reciente (newer than).
- -ot fecha de modificación más antigua (old than).
- -e el archivo existe.
- -s el archivo existe y tiene un tamaño mayor que cero.
- -d el archivo existe y es un directorio.
- -h el archivo existe y es un enlace simbólico.
- -x el archivo existe y es ejecutable.
Estructuras de control
Estructuras de control Bash: IF
- if
Las estructuras condicionales if permiten que nuestros scripts se comporten de una forma u otra según la condición que especifiquemos, siendo condición un comando test. La sintaxis es:
if condicion1; then Bloque1 elif condicion2; then Bloque2 else Bloque3 fi
En el siguiente ejemplo pedimos al usuario un número que se almacena en la variable $input. Dependiendo de si el número es menor, igual o mayor que 5, el script se comporta de una forma u otra. Si el usuario no introduce nada o introduce una cadena de texto, se ejecutará lo que hay tras else, pues ninguna de las condiciones anteriores se cumple.
#!/bin/bash echo "Introduzca un numero: " read input if [ $input -lt 5 ]; then echo "El numero era menor que 5" elif [ $input -eq 5 ]; then echo "El numero era 5" elif [ $input -gt 5 ]; then echo "El numero era mayor que 5" else echo "No introdujo un numero" fi
En el siguiente ejemplo, primero comprobamos que nos han pasado dos argumentos (el archivo donde buscar y la cadena de búsqueda): si no es así, le indicamos al usuario cómo debe ejecutar el script y salimos. A continuación comprobamos que el archivo existe: si no es así, advertimos y salimos. Una vez verificadas estas dos condiciones, mediante cat y el pipe, grep cuenta el número de veces que el valor de $BUSQUEDA está en el archivo, que queda guardado en $NUM_VECES.
#!/bin/bash if [ $# -ne 2 ]; then echo "Necesito dos argumentos, el primero" echo "es el archivo donde debo buscar y" echo "el segundo es lo que quieres que busque." echo " " echo "Uso: $0 <archivo> <patron_busqueda>" echo " " exit fi ARCHIVO=$1 BUSQUEDA=$2 if [ ! -e $ARCHIVO ]; then echo "El archivo no existe" exit fi NUM_VECES='cat "$ARCHIVO" | grep --count "$BUSQUEDA"' if [ $NUM_VECES -eq 0 ]; then echo "El patron de busqueda "$BUSQUEDA" no fue encontrado" echo "en el archivo $ARCHIVO " else echo "El patron de busqueda "$BUSQUEDA" fue encontrado" echo "en el archivo $ARCHIVO $NUM_VECES veces" fi
Estructuras de control Bash: FOR
- for
El bucle for viene a solucionar el problema de "Para cada uno de los elementos siguientes, quiero que mi script haga esto". El bucle for ejecuta las sentencias de Bloque tantas veces como elementos haya en LISTA: la primera vez VARIABLE valdrá el primer elemento de la lista, la segunda vez VARIABLE valdrá el segundo elemento de la lista, y así sucesivamente. El elemento LISTA del bucle for puede ser una variable que contenga una lista de elementos:
lista = "pedro pepe juan jose"
for i in $lista; do
… una lista de elementos:
for i in pedro pepe juan jose; do
… una lista de archivos dada utilizando comodines:
for i in $DIR/.*; do
… o un comando tal que su salida sea una lista de elementos:
for i in ‘ls’; do
La sintaxis del bucle for es:for VARIABLE in LISTA ; do Bloque done
Veamos un ejemplo. Si ejecutamos el siguiente script:
#!/bin/bash for i in pedro pepe juan jose; do echo "Hola $i" done
obtenemos:
Hola pedro Hola pepe Hola juan Hoja jose
El siguiente ejemplo lista los archivos y directorios ocultos. Una vez comprobado que la cadena que se le ha pasado como argumento no tiene longitud cero, que existe y que es un directorio, lista cada archivo que pertenezca a la lista, es decir, que verifique que su primer carácter es un punto (.):
#!/bin/bash DIR=$1 if [ -z $DIR ]; then echo "El primer argumento debe tener longitud mayor que 0" exit 1 fi if [ ! -d $DIR ]; then echo "El directorio debe existir y ser un directorio" exit 1 fi for i in $DIR/.*; do echo "Encontrado el elemento oculto $i" done echo "Finalizado"
En el bucle for podemos usar break para salir del bucle en cualquier momento.
Estructuras de control Bash: CASE
- case
La estructura case sirve para actuar de una u otra manera en función del valor de una variable: esto podríamos hacerlo con if, pero case es más eficiente y cómodo. La sintaxis es:
case $VARIABLE in valor1) Bloque 1 ;; valor2) Bloque 2 ;; ... *) Bloque default ;; esac
Si $VARIABLE no coincide con ninguno de los valores valor1, valor2… sí coindirá con el comodín *, ejecutándose el Bloque default. Veamos un ejemplo:
#!/bin/bash if [ $# -lt 1 ]; then echo "Error. Esperaba al menos un parametro" exit 1 fi case $1 in windows) echo "El logo de windows es una ventana" exit 0 ;; mac) echo "El logo de mac es una manzana" exit 0 ;; linux) echo "El logo de linux es un pinguino" exit 0 ;; *) echo "Logo sin definir" exit 1 ;; esac
Estructuras de control Bash: WHILE
- while
El otro tipo de bucle posible en los scripts de bash es el bucle while. Este bucle viene a solucionar el problema de "quiero que mi script haga esto mientras que se dé esta condición". Su sintaxis es:
while test CONDICION; do Bloque done
En el siguiente ejemplo la condición para que el bucle se siga ejecutando es "que $j valga menos de 10", y en cada ciclo sumamos 1 a la variable $j:
#!/bin/bash j=0 while [ $j -lt 10 ]; do echo "j vale $j" j=$[$j+1] done
En el bucle while también podemos usar break para salir del bucle en cualquier momento. En el siguiente ejemplo la condición se cumple siempre (test 1 siempre retornará TRUE), pero break hará que termine el bucle cuando el número introducido sea igual a $MINUM.
#!/bin/bash MINUM=8 while [ 1 ]; do echo "Introduzca un numero: " read USER_NUM if [ $USER_NUM -lt $MINUM ]; then echo "El numero introducido es menor que el mio" echo " " elif [ $USER_NUM -gt $MINUM ]; then echo "El numero introducido es mayor que el mio" echo " " elif [ $USER_NUM -eq $MINUM ]; then echo "Acertaste: Mi numero era $MINUM" break fi done echo "El script salio del bucle. Finalizado."
Introducir datos por el teclado
Para introducir datos por el teclado usaremos el comando read. Para ver cómo funciona, veamos el siguiente script:
#!/bin/bash frase="Introduzca lo que usted quiera:" echo $frase read entrada_del_usuario echo " " echo "Usted introdujo: $entrada_del_usuario" |
Cuando se ejecute el script, al llegar al comando read esperará a que el usuario escriba algo y presione la tecla <INTRO>. A continuación, almacenará la entrada del usuario en la variable $entrada_del_usuario.
Funciones
Una función es un conjunto de comandos a los que se da un nombre, de manera que puedan ser ejecutados desde cualquier punto del script llamando a la función mediante ese nombre.
- Antes de llamar una función debemos definirla. La sintaxis es:
function nombre_funcion () { Bloque }
- Una vez definida la función se convierte en un "comando posible" dentro del script, al que se le pueden pasar argumentos que se procesan de la misma forma: $1, $2, etc. se corresponden con el primer parámetro, segundo, etc.
- Al igual que un script devuelve un valor que podemos establecer con exit, podemos hacer que una función devuelva un valor con el comando return, que se usa igual que exit.
En el siguiente ejemplo definimos una función que se ejecuta si se le pasa un número de argumentos distinto de 2, o si el segundo argumento no es un archivo existente: si los argumentos no son adecuados llamamos a la función uso que explica al usuario cómo se debe llamar el script. Esta estrategia es muy útil y frecuente en scripts complejos con muchas opciones:
#!/bin/bash function uso () { echo "Este script recibe dos argumentos." echo "El primero debe ser windows o linux ," echo "y el segundo debe ser un archivo existente." echo " " } if [ $# -ne 2 ]; then uso exit 1 fi case $1 in windows) if [ -e $2 ]; then echo "El script windows termino con exito" exit 0 else uso exit 1 fi ;; linux) if [ -e $2 ]; then echo "El script linux termino con exito" exit 0 else uso exit 1 fi ;; *) uso exit 1 ;; esac |
En el siguiente ejemplo vamos a ver cómo utilizar el comando shift para trabajar con argumentos. La función lista_parametros recibe varios parámetros y usando shift recortamos la lista de argumentos una posición quitando el primero de ellos: $1 vale $2, $2 vale $3, etc. De esta manera, imprimimos el primer argumento, ejecutamos shift y volvemos a imprimir el primer argumento (que ahora es el segundo) y así hasta el final, habiendo conseguido imprimir todos los argumentos.
#!/bin/bash function lista_parametros () { echo "Se ha llamado a lista_parametros, con $#" echo "parametros. Mostrando los parametros:" echo " " b=7 numparms=$# local j=1 while [ $j -le $numparms ]; do echo "El parametro $j contiene $1" shift local j=$[$j+1] done } lista_parametros a b c d dsfafd d echo $b echo $j |
QUIERO RESOLUCION DE 2 SCRIPTS IMPORTANTES
1. Crear un script llamado uno.sh que busque dentro de un fichero las líneas que contienen una palabra, tanto el nombre de fichero, como la palabra que se quiere buscar se pasarán por la línea de comandos. Se debe comprobar:
• Que se pasen exactamente dos parámetros.
• Que el fichero debe existir.
Ejemplo:
Miserver @ usuario$ uno.sh /home/usuario/jfsfj.txt redes
2. Crear un script llamado dos.sh que pida por pantalla dos números y muestre por pantalla la secuencia de números que hay entre el menor y el mayor, al lado de cada número debe aparecer su cuadrado.
Ejemplo 1
Introduce el primer número: 5
Introduce el segundo número: 1
1 1
2 4
3 9
4 16
5 25
Ejemplo 2
Introduce el primer número: 2
Introduce el segundo número: 6
2 4
3 9
4 16
5 25
6 36
en la comparación con enteros tienes
“-t menor (less than)”
y lo correcto es
“-lt menor (less than)”
puede ser importante, a mi me ha llevado un rato darme cuenta, en todo caso gracias por contribuir publicando estas cosas.
Un saludo,
Iván.
A CUTI:
1.- uno.sh
—————————————————————————————–
#!/bin/bash
if [ $# -ne 2 ]; then
echo “No se han introducido dos parámetros”; exit 1
fi
# Esto comprueba el nº de parámetros
if [ -e $1 ];then
echo “”
else
echo “El fichero no existe”; exit 2
fi
# Esto comprueba la existencia del fichero
grep –file=”$1″ $2
—————————————————————————————–
El fichero dos.sh depende de la versión de BASH que tengas.