Me estuve planteando que para hacer más ameno el curso deberíamos empezar ya a hacer scripts. (Ya sé que la palabra script no existe en castellano pero decir guiones o cualquiera de sus sinónimos no me parece adecuado, así que, y con la venia, seguiré diciendo script aun consciente de que no es correcto).
Primero pensé que como había que trabajar con los permisos de ejecución se hacía imprescindible explicar antes lo de los permisos en linux, y de hecho escribí un artículo sobre los permisos pero al terminar lo vi tan ‘infumable’ que no me atrevo a publicarlo. Ahora he retomado el asunto de explicar los scripts, y cuando haya que hablar de permisos daré unas breves nociones pero sin meterme a fondo. Quizá más adelante volvamos sobre el tema, para ver el tema de los permisos a fondo, pero de momento no lo considero imprescindible.
Hola mundo
Para los que nunca habéis hecho un curso de programación, decir que eso de ‘Hola Mundo’ es el primer ejemplo de programa que se suele poner para aprender a programa en cualquier lenguaje. Un programa tan simple que lo único que hace es imprimir una frase en la pantalla, la frase más manida es por supuesto ‘Hello World’ o su traducción ‘Hola Mundo’.
En bash no es necesario hacer un programa para sacar una frase por pantalla, si con un simple comandito de una línea ya está.
$ echo "Hola Mundo"
Hola Mundo
Pero claro con eso no aprenderíamos lo que es un script. Un script de bash no es más que una secuencia de comandos contenidos en un fichero de texto, cada uno en una línea, que la shell interpreta y ejecuta uno tras otro (salvo que haya instrucciones que indiquen una secuencia distinta claro).
Nuestro primer script solo tendrá una linea. Todavía tenemos la carpeta ‘ejercicios_curso_bash’ que creamos en el capítulo anterior, vamos a utilizarala, primero nos situamos y borramos todos los archivos que hay en ella. Asegurate con el comando ‘pwd’ de cual es tu directorio de trabajo antes de hacer el ‘rm -f *’. Esa órden borra todos los ficheros de la carpeta de trabajo, y no quiero sorpresas.
$ cd ~/ejercicios_curso_bash
$ pwd
/home/redy/ejercicios_curso_bash
$ rm -f *
Abre tu editor de textos favorito, crea un fichero nuevo con el siguiente texto:
echo "Hola Mundo"
Guardalo en la susodicha carpeta con el nombre ‘saluda’
En lo sucesivo todos los scripts que ponga irán en recuadros como el de arriba. El texto aparecerá en colorines, al estilo de como aparece en muchos editores que resaltan la sintaxis del lenguage. Que sepas que cuando veas un recuadro así, son las líneas que debes teclear (bueno también ‘se vale’ copiar y pegar venga…) en tu editor de textos, para que queden grabadas en el script (no te preocupes si los colores son distintos o si en tu editor no sale el texto coloreado, eso depende del editor.)
Ahora vamos a decirle a bash que ejecute ese script:
$ bash saluda
Hola Mundo
Si tu script saludo no dice ‘Hola Mundo’ tenemos un problema. ¿Has escrito exactamente lo que yo decía? ¿Lo has guradado con el nombre ‘saluda’ en la carpeta ‘~/ejercicios_curso_bash’? ¿Era esa carpeta tu directorio de trabajo cuando le mandaste ejecutarlo?.
Comentarios
Un comentario en un programa es un texto que no forma parte de las instrucciones, no será interpretado por el ordenador a la hora de ejecutar o de compilar el programa, simplemente se pone para que cuando un programador lea el programa, le sirva de aclaración de algun aspecto o detalle importante.
Dicen los grandes programadores que el buen código no los necesita, que si un programa está bien escrito se entiende tan bien que cualquier comentario sobra. Y ahora me viene a la mente una frase de Martin Fowler, un experto en desarrollo y metodología del software, que dice que: “Any fool can write code that a computer can understand. Good programmers write code that humans can understand” (Cualquier necio puede escribir código que un ordenador puede entender. Los buenos programadores escriben código que los seres humanos podemos entender). Como ni yo, ni posiblemente tu tampoco , somos de esa pequeña minoría que se pueden llamar buenos programadores, será mejor que pongamos en nuestro código algún comentario y quizá así nos sea más fácil entender luego el espagueti que hemos liado (Bueno vale, el hola mundo se entiende bien sin comentarios, pero tiempo al tiempo… Mejor irnos acostumbrando a ponerlos.).
En bash los comentarios se ponen mediante el signo ‘#’. Cuando bash encuentre en un comando una palabra que comience por el signo ‘#’ ignorará todo lo que haya desde ese signo hasta el final del comando (final de línea).
$ echo Hola Mundo # Esta órden saludara a todo el mundo
Hola Mundo
Aunque lo más usual es que en un script el # se ponga al principio de la línea y entonces toda la línea es un comentario, ya ves que no tiene porque ser así, y que justo a continuación de un comando y en la misma línea podemos poner un # para clarificar algo. Evidentemente el # no tendrá efecto entre comillas, ni en medio de una palabra:
$ echo "Hola Mundo # Esto también sale"
Hola Mundo # Esto también sale
$ echo Hola Mundo Es#to también sale
echo Hola Mundo Es#to también sale
Ahora que ya sabemos comentar vamos a poner bonito nuestro script: ábrelo con tu editor favorito y modifícalo para que quede tal que así:
# saluda versión 1.0 # Programa para aprender como confeccionar un primer script en bash # Autor: _pon tu nombre aquí_ # Se permite la reproducción bajo los términos de la licencia GPL y patatín patatán # echo "Hola Mundo" # Fin del programa
Guárdalo, y tendrás una nueva versión del script que hace exactamente lo mismo pero queda como más ‘pofesional‘ ¿no?
$ bash saluda
Hola Mundo
Hacer que sea un programa ejecutable
Si ahora miramos, con el comando file, qué es nuestro script ‘saluda’, veremos que el sistema lo reconoce como un simple archivo de texto ASCII.
$ file saluda
saluda: Non-ISO extended-ASCII text
Solo nosotros sabemos que es un script de bash. Y por tanto la única manera de ejecutarlo es diciéndole al bash que lo abra como un script, tal como hicimos arriba.
Vamos a mejorar un poco todo esto: podemos convertir nuestro script en un programa más del sistema que el kernel sepa ejecutar, y así solo tendremos que invocarlo por su nombre como un comando más. Para hacer esto solo es necesario un par de retoques:
En la primera línea del programa, añadiremos un comentario especial que comienza siempre por ‘#!’ y un espacio en blanco, luego ponemos el nombre de ruta del intérprete que va a ejecutar ese script, en nuestro caso ‘/bin/bash’.
Cuando al kernel le ordenamos ejecutar un fichero de texto cuya primera línea está formada siguiendo esa regla, en realidad ejecutará el intérprete pasándole como argumento el nombre del script (exactamente igual que hacíamos nosotros con el comando ‘bash saluda’). En este caso, como el script se llama ‘saluda’ y la primera línea es ‘#! /bin/bash’, ejecutará lo equivalente a teclear ‘/bin/bash saluda’. Editemos pues nuestro script para añadirle esa línea:
#! /bin/bash # saluda versión 1.0 # Programa para aprender como confeccionar un primer script en bash # Autor: _pon tu nombre aquí_ # Se permite la reproducción bajo los términos de la licencia GPL y patatín patatán # echo "Hola Mundo" # Fin del programa
Ahora ya es un script de bash para el sistema:
$ file saluda
saluda: Bourne-Again shell script text executable
Solo falta otro detalle hay que darle permiso de ejecución. El sistema de permisos en Linux se basa en un esquema de usuarios/grupos que lo convierte en la base principal de la seguridad en Linux, a estos usuarios y grupos se les asignan distintos derechos sobre los archivos y directorios. Cada archivo pertenece a un usuario y a un grupo. Un archivo puede tener permiso de lectura, de escritura y de ejecución, si no tiene el permiso de lectura no podremos leerlo, si no tiene el de escritura no podremos modificarlo y si no tiene el de ejecución no podrá ser ejecutado, que es lo que nos interesa. Veamos como funciona, si haces:
$ ls -l
Te saldrá algo como esto:
-rw-r--r-- 1 redy redy 264 oct 22 10:07 saluda
El tercer y cuarto campos (con los valores ‘redy’ y ‘redy’ en mi caso) son el usuario propietario del fichero y el grupo al que pertenece el fichero. Un fichero pertenece normalmente al usuario que lo crea y al grupo de ese usuario. Solo el root puede cambiar el propietario de un fichero. Pero el propietario puede cambiarle los permisos. Las letras y guiones que aparecen en el primer campo son los permisos. Bueno, la primera letra es el tipo de elemento dentro del sistema de archivos, una ‘d’ indicará que es un directorio y un ‘-’ que es un fichero (hay otras como ‘b’, o ‘c’ para dispositivos, ‘l’ para enlaces simbólicos…). Los 9 caracteres a continuación y en grupos de tres en tres son los permisos; por este orden: permisos para el propietario, permisos para el grupo y permisos para el resto. Cada grupo de permisos indica lo que puede hacer el individuo en cuestión con ese fichero. Y las tres letras que pueden aparecer en cada grupo de permisos por este órden son r (Read: lectura), w (Write: escritura) y x (eXecute: ejecución). Si aparece la letra es que el permiso está concedido y si aparece un ‘-’ en su lugar es que no. ¿Vaya lío? Veámoslo en el ejemplo de arriba: Tenemos -rw-r–r– si quitamos el primer ‘-’ que indica que es un fichero y lo dividimos de tres en tres nos queda rw- r– r– lo cual indicará que los permisos para el usuario redy (que es el propietario del fichero) son rw- (lectura y escritura). Los permisos para cualquier otro usuario que pertenezca al grupo redy serían los tres siguientes r– (lectura). Y para el resto de usuarios del sistema también serían r– (lectura). Es decir que a pesar de que es reconocido por el sistema como un script de bash ejecutable, nadie puede ejecutar el fichero porque nadie tiene permiso para ello. Para modificar los permisos se usa el comando chmod. Normalmente a chmod se le pasan dos argumentos el primero indica los permisos que queremos modificar, y el segundo el nombre del fichero. Para indicar los permisos que queremos modificar pondremos el signo ‘+’ para darlo o ‘-’ para quitarlo seguido de la letra del permiso (‘r’, ‘w’, o ‘x’). Opcionalmente podremos poner antes del signo las letras ‘u’ (usuario), ‘g’ (grupo) u ‘o’ (otros) para indicar a quien queremos conceder o denegar ese permiso, si no ponemos esa letra o ponemos la ‘a’ (de all) se asignará o quitará el permiso para todos.
Entonces, para darle permiso de ejecución a nuestro fichero, tenemos que hacer:
$ chmod +x saluda
ls -l
-rwxr-xr-x 1 redy redy 264 oct 22 10:07 saluda
Ahora que tiene permiso de ejecución y en su primera línea se le indica al kernel como debe manejarlo, ya es un programa, y para ejecutarlo solo hace falta escribir como un comando su nombre de ruta
$ ~/ejercicios_curso_bash/saluda
Hola Mundo
Como ~/ejercicios_curso_bash es nuestro directorio de trabajo, y si volvemos a lo explicado hace un par de entregas eso puede representarse con una ruta relativa con un simple punto (‘..’ era el directorio padre y ‘.’ el propio directorio, ¿recuerdas?), podemos teclear simplemente:
$ ./saluda
Hola Mundo
Y ya para darle el último toque. Hay una serie de directorios dónde suelen ponerse los programas. Al sistema se le indica dónde debe buscar los programas en caso de que nosotros no indiquemos la ruta completa, mediante una variable (pronto veremos esto de las variables, paciencia). Solo comentar que si pones el comando:
$ echo $PATH
/usr/local/bin:/bin:/usr/bin:/usr/X11R6/bin:/usr/games:/home/redy/bin
Obtendrás la lista (separados por ‘:’) de todos los directorios dónde se buscan programas para ejecutarlos. Si ponemos nuestro programa en uno de esos directorios ya no será necesario especificar su nombre de ruta completo para ejecutarlo, sólo el nombre, como si fuera uno de tantos programas o utilidades de nuestro sistema. Claro que en esa lista no tendremos permiso de escritutra en la mayoría de los directorios… Veamos (No intentes entender el siguiente comando de momento, que sepas simplemente que nos sirve para ver en que directorios de los dichos podemos escribir):
$ ls -ld $(echo $PATH |tr ":" " ")
drwxr-xr-x 2 root root 4096 nov 20 2006 /bin/
drwxr-xr-x 2 redy redy 4096 oct 18 08:17 /home/redy/bin/
drwxr-xr-x 3 root root 61440 sep 21 13:53 /usr/bin/
drwxr-xr-x 2 root root 4096 abr 25 12:48 /usr/games/
drwxr-xr-x 2 root root 4096 sep 13 08:19 /usr/local/bin/
drwxr-xr-x 3 root root 4096 sep 27 07:54 /usr/X11R6/bin/
En la lista de los que a mi me salen, resulta que todos pertenecen al root y solo tienen permiso de escritura para el propietario, excepto el /home/redy/bin que pertenece a redy y también tiene permiso de escritura solo para el propietario. Vaya ese soy yo, luego ahí puedo escribir, lo cual, dicho de un directorio significa que puedo meter cosas dentro de él. Apuesto a que tu tienes uno igual pero, obviamente, sustituyendo ‘redy’ por tu nombre de usuario. Puedes trasladar el script ‘saluda’ a ese directorio con el comando mv.
$ mv saluda /home/redy/bin
$ saluda
Hola Mundo
¡Funciona!
Recuerda que si quieres editarlo de nuevo, ahora ya no está en ~/ejercicios_curso_bash sino en ~/bin