Ya vimos que con touch y cat podemos crear un archivo con extensión .sh (shell) y escribir código para poder ejecutarlo desde consola. Dado que en Linux las extensiones no importan tanto como el contenido en sí, incluso podríamos dejarlo sin la extensión .sh o hasta podríamos ponerle .jpeg y aún así se podría ejecutar sin problemas. Sin embargo, lo correcto es agregarle siempre la extensión correspondiente.
Para ejecutar un script utilizamos el comando ./arch o bien bash arch, pero dado que por defecto ningún script recién creado tiene permisos de ejecución, antes necesitamos otorgarle permisos de ejecución al archivo con chmod +x o bien con chmod 755 arch (¿recuerdas a qué permisos corresponde?)
Todo código debe comenzar con el encabezado #!/bin/bash. La combinación #! se conoce como shebang y /bin/bash es la ruta que le indica al sistema cuál es el intérprete que debe utilizar (en nuestro caso es Bash, pero puede usarse el shebang para otros intérpretes). Es importante que se escriba siempre en la primera línea y sin espacios de por medio.
El código se escribe una sentencia por línea, tal como se haría en la consola. Los comentarios se indican con el signo numeral (#) y abarcan sólo una línea. Hay que remarcar además la importancia de los espacios y las indentaciones.
#!/bin/bash # código a ejecutar
NOTA: Cualquier cosa que se pueda ejecutar desde la terminal se puede incluir en un script y viceversa.
Teniendo en cuenta esto, una manera de probar que el código funciona es ir ejecutándolo parte por parte desde consola, verificando que cada paso es realizado correctamente.
| Comando | Descripción |
|---|---|
var=valor |
Se declara una variable y se le asigna un valor. Si la variable ya está declarada se le asigna un valor nuevo. ATENCIÓN: Recordar que no debe haber espacios que si el valor tiene más de una palabra debe escribirse entre comillas |
var= |
Se declara una variable pero no se le asigna ningún valor |
$var |
Invoca a una variable |
var=$(com) |
Almacena el resultado de un comando en una variable. Por ejemplo, fecha=$(date) guarda la fecha actual |
readonly VAR=valor |
Crea una variable cuyo valor no se podrá modificar (constante) [1] |
read var1 var2... |
Lee los datos introducidos por el usuario y los almacena en variables |
read -p |
(-prompt) Muestra el prompt en la misma línea |
read -s |
(-silent) Oculta los caracteres ingresados (como en una contraseña) |
compgen -v |
(-variables) Muestra un listado de todas las variables de entorno |
${var,} |
(con una sola coma) Muestra la primera letra del valor de la variable en minúscula [2] |
${var,,} |
(con dos comas) Muestra el valor de la variable en minúsculas [2] |
${var^^} |
Muestra el valor de la variable en mayúsculas [2] |
${#var} |
Muestra la longitud de la variable (cantidad de caracteres) |
[1] En la mayoría de los lenguajes de programación, las constantes se suelen escribir en mayúsculas.
[2] Estas acciones NO alteran los caracteres almacenados en la variable. Solamente los presentan de esa manera.
Ya vimos que con el comando basename se puede extraer el nombre del archivo con o sin su extensión. Ahora bien, basename es un programa en sí y es externo a Bash, pero de todas maneras podemos integrarlo fácilmente en nuestro código:
# Primero definimos una variable con la ruta del archivo ruta="/home/usuario/documento.pdf" # Extraer el nombre del archivo con su extensión nom_ext=$(basename $ruta) echo $nom_ext # documento.pdf # Extraer únicamente el nombre nom=$(basename $ruta .pdf) echo $nom # documento
El método con basename tiene un par de desventajas, porque no solamente es más lento debido a que requiere ejecutar otro proceso, sino que también debemos conocer de antemano cuál la extensión del archivo.
Por suerte existen otros métodos llamados expansión de parámetros con los que podemos obtener los mismos resultados:
| Comando | Descripción |
|---|---|
${ruta##*/} |
Extrae el nombre y la extensión del archivo |
${ruta##*.} |
Extrae únicamente la extensión del archivo |
${arch%.*} |
Extrae únicamente el nombre del archivo (arch debe tener tanto el nombre como la extensión) |
El primero le indica a Bash que busque el patrón más largo (##) que termine en una barra (*/) y que lo elimine. Con el segundo es lo mismo, pero terminando en punto en lugar de una barra.
ruta="/home/usuario/documento.pdf"
# Nombre y extensión
nom_ext=${ruta##*/}
echo $nom_ext # documento.pdf
# Sólo extensión
ext=${ruta##*.}
echo $ext # pdf
Con el tercero necesitamos un paso extra, ya que no podemos aislar directamente el nombre del archivo sin su extensión. Además debemos tener especial cuidado porque existen algunos archivos con extensión doble, como por ejemplo los archivos .tar.gz; en estos casos debemos repetir el último paso.
ruta1="/home/usuario/documento.pdf"
# Primero quitamos la ruta...
nom_ext=${ruta1##*/}
# ...y luego extraemos sólo el nombre
nom=${nom_ext%.*}
echo $nom # documento
# Con archivos con extensión doble, debemos repetir el último paso
ruta2="/home/usuario/comp.tar.gz"
arch=${ruta2%.*} # comp.tar
nom=${arch%.*} # comp
echo $nom # comp
La desventaja de estos métodos es que requieren más pasos, pero la gran ventaja es que no es necesario saber cuál es la extensión.
Podemos exportar una variable para que pueda ser utilizada por otro script. Esto se realiza primero con la palabra reservada export:
#!/bin/bash nom1="Diego" nom2="Ernesto" nom3="Fernando" echo "Script 1 => nom1 = $nom1, nom2 = $nom2, nom3 = $nom3" export nom1 nom2 # Exporta únicamente nom1 y nom2
Y después la importamos en otro archivo con source o el operador de punto (.) más la ruta del archivo:
#!/bin/bash . ./script1.sh # Es lo mismo que source ./script1.sh nom1="Alfredo" # Aquí definimos otras variables pero con los mismos nombres nom2="Benicio" echo "Script 2 => nom1 = $nom1, nom1 = $nom2, nom3 = $nom3"
Luego, al ejecutar script1.sh:
Script 1 => nom1 = Diego, nom2 = Ernesto, nom3 = Fernando
Pero al ejecutar script2.sh:
Script 1 => nom1 = Diego, nom2 = Ernesto, nom3 = Fernando Script 2 => nom1 = Alfredo, nom2 = Benicio, nom3 = Fernando
Como verás, script2.sh ha usado nuevamente el comando echo de script1.sh. Esto ocurre porque Bash no simplemente "lee" las variables, sino que copia todo el contenido y lo ejecuta línea por línea en el otro proceso.
Otra cosa muy importante a tener en cuenta es que tanto export como source funcionarán únicamente en la sesión actual.
¡Hola, [nombre]! Hoy es [fecha]” mostrando respectivamente esos datos.¡Hola, [nombre]! Ingresa tu contraseña: ".imagen.jpg y luego utilizar ambos basename y la expansión de parámetros para mostrar por consola la ruta completa, el nombre del archivo con su extensión, sólo el nombre y sólo la extensión.Los archivos también pueden aceptar argumentos almacenados en variables cuyos nombres son $1, $2... $n. Estas variables almacenan los valores que se introducen en orden cuando se ejecuta el programa en la terminal. Por ejemplo, si un programa llamado saludo.sh tiene el siguiente código:
#!/bin/bash echo Hola, $1 $2, ¿cómo estás?
Al ejecutarlo desde la consola con el comando ./saludo.sh Juan Pérez, siendo Juan el primer argumento que se almacena en $1 y Pérez en $2, el programa retornará:
Hola, Juan Pérez, ¿cómo estás?
Existen otras variables especiales que nos brindan información especial:
| Variable especial | Representa |
|---|---|
$0 |
El nombre del archivo que se está ejecutando [3] |
$n |
Accede al parámetro número n (del 1 al 9) |
$# |
El número total de argumentos que se pasan al programa |
$@ |
Todos los argumentos que se pasan al programa |
$? |
La salida del último comando ejecutado |
$$ |
El id del proceso que se está ejecutando (PID) |
$! |
El PID del último comando ejecutado |
$USER |
El usuario que está ejecutando el script |
$HOSTNAME |
El nombre del equipo |
$SECONDS |
La cantidad de segundos desde que comenzó la ejecución |
$RANDOM |
Devuelve un número aleatorio |
$LINENO |
El número de línea actual |
[3] Por ejemplo, si se abre una terminal y se escribe
echo $0, retornabash.
El nombre de este archivo es [nombre_archivo], admite [n] argumentos y sus valores actuales son [argumentos]."Tu nombre de usuario es [usuario] y tu ID es [número_al_azar]".