Guía básica del intérprete de comandos Bash

Escrito por el .
gnu-linux planeta-codigo software-libre
Enlace permanente Comentarios

La línea de comandos sigue siendo una poderosa herramienta que aunque menos intuitiva que una interfaz gráfica permite hacer las tareas de forma más sencilla, directa y que se puede automatizar. Conocer las opciones del intérprete de comandos es básico para aprovechar su máximo potencial. Desde las combinaciones de teclas hasta los scripts o archivos de lotes. Tuberías y redirecciones, comandos con ejecución condicional, variables, interpolación de cadenas, scrtips, argumentos, funciones, for, switch, if, comparaciones, …

GNU

Linux

Automatizar las tareas que realizamos permite ahorrarnos el tiempo de tener que hacerlo manualmente y evita los errores que se puede producir. En GNU/Linux el uso de la terminal no es algo extraño y muchas tareas son realizadas más fácil y rápido con un comando que con un programa con interfaz gráfica, además tiene la ventaja de que puede automatizarse creando un script Bash.

El intérprete de comandos Bash junto con la combinación de otros programas proporcionados por la parte GNU de los sistemas Linux presentes en la mayoría de las distribuciones por defecto es suficiente para automatizar la mayor parte de tareas que necesitemos conociendo que hacen 50 comandos útiles de línea de comandos. Para aumentar la productividad es necesario aprender las combinaciones de teclas del intérprete Bash y del emulador de la terminal.

Tuberías y redirecciones

Al ejecutar un comando podemos querer encadenar la salida de un comando con la entrada de otro, mediante una tubería. Uno de los puntos de la filosofía de los programas de los sistemas Unix es que realicen una o pocas tareas pero que lo hagan muy bien. Usando varios programas especializados en una tarea podemos juntarlos como si fuese piezas de Lego para realizarla tarea compleja que necesitamos, encadenando la salida de un comando como la entrada del siguiente.

Una de las cosas buenas de Bash es que está presente por defecto en la mayoría de las distribuciones Linux y si no es este intérprete de comandos será otro similar por lo que no necesitamos instalar nada más adicional para usarlo. Aún así si necesitaremos algo más potente que Bash como lenguaje de programación podemos optar por un lenguaje de programación como Python para realizar los scripts aunque necesitaremos instalar su paquete y las dependencias que los scripts usen.

Por ejemplo, dada una lista de concursantes habilitados en un sorteo podemos obtener 3 ganadores de forma aleatoria con la combinación de los siguientes comandos. El comando grep permite aplicar una expresión regular a cada línea de un fichero que si la cumple es enviada a la salida, shuf reordena las líneas de forma aleatoria y con la opción -n 3 emite las 3 primeras. Los comandos proporcionados por GNU en los sistemas Linux proporcionan multitud de comandos como estos muy útiles, combinándolos conseguimos tareas más capaces que lo que son los comandos individualmente.

1
2
$ grep "^[^#]" sorteo.txt | shuf -n 3

sorteo-1.sh

Sorteo implementado con dos comandos de GNU/Linux

Sorteo implementado con dos comandos de GNU/Linux

Por defecto la salida estándar de un comando es la terminal pero podemos redirigirla a un fichero con la opción >.

1
2
$ grep "^[^#]" sorteo.txt | shuf -n 3 > ganadores.txt

sorteo-2.sh

Además de la salida estándar los programas tienen la salida de errores que podemos redirigir con 2>, si queremos redirigir la salida estándar y la de error podemos usar la redirección &>. Tanto la opción > y 2> crean un fichero con la salida redirigida, si en vez de sobrescribir el contenido del archivo queremos añadirlo al final podemos hacer la redirección con >>.

1
2
$ grep "^[^#]" sorteo.txt | shuf -n 3 >> ganadores.txt

sorteo-3.sh

Múltiples comandos

Si necesitamos ejecutar dos comandos seguidos podemos introducirlos en la misma línea en vez de individualmente, ejecutar un comando si el anterior se ha ejecutado correctamente con && o al contrario ejecutar un comando si el anterior ha fallado con ||. Si en la ubicación de trabajo que estamos existe un directorio no se podrá crear otro con el mismo nombre, dependiendo de las opciones de encadenamiento según el resultado del comando anterior se ejecutará o no el siguiente comando.

1
2
3
$ mkdir directorio ; mkdir directorio ; echo "Directorio creado"
$ mkdir directorio && mkdir directorio && echo "Directorio creado"
$ mkdir directorio &> /dev/null || echo "La creación de directorio ha fallado"
multiples-comandos.sh

Múltiples comandos en la misma línea

Múltiples comandos en la misma línea

Variables e interpolación de cadenas

Podemos definir variables locales en el script o exportarlas para que estén accesibles en otros procesos e incluso interpolarlas en cadenas de la siguiente forma:

1
2
3
4
5
name="picodotdev"
export name="picodotdev"

$ echo $name
$ echo "Hola $name!"
variables-1.sh

También podemos interpolar la salida de un comando dentro de una cadena:

1
2
$ echo "Hola $name! a las `date`"

variables-2.sh

Interpolación en cadenas de variables y comandos

Interpolación en cadenas de variables y comandos

Invocaciones de comandos anteriores

Con el comando history podemos ver el historial completo de comandos que hemos ejecutado con anterioridad. Al lado de cada comando vemos un identificador numérico que podemos usar para ejecutarlo de nuevo con ![identificador]. Con el siguiente historial podemos ejecutar el comando con identificador 512 indicando una exclamación y el identificador, !512. Si queremos ejecutar el último comando introducido podemos usar la doble exclamación !!. Si queremos ejecutar el último comando completo de cierto comando podemos usar ![comando] en vez de su identificador.

Historial de comandos

Historial de comandos

Hay más formas de ejecutar comandos del historial. Si quisieramos invocar un comando del historial cambiando algún argumento podemos hacer una búsqueda en orden inverso con Ctrl+r.

Scripts

Los scritps son archivos de texto con permisos de ejecución interpretados por Bash u otro intérprete que ejecuta los comandos del script, es la forma de automatizar varios comandos. Al inicio de los scripts se suele incluir el shebang donde se indica el programa encargado de interpretar el script, puede ser Bash o un programa escrito en un lenguaje de programación como Python. Se puede indicar de varias formas pero las preferidas son las siguientes:

1
2
#!/usr/bin/env bash
#!/usr/bin/env python
scripts-1.sh

Una vez escrito el script antes de ejecutarlo debemos darle permisos de ejecución con el comando chmod:

1
2
$ chmod +x script.sh

scripts-2.sh

Argumentos

Al igual que los comandos pueden recibir opciones y argumentos los scripts también, hacer uso de ellos son mediante las siguientes variables:

  • $0: contiene nombre del script.
  • $1: primer argumento, $2 segundo argumento, …
  • $#: número de argumentos al invocar el script.
  • $*: todos los argumentos al invocar el script.
  • $?: valor del estado de salida del último comando ejecutado. Normalmente se usa 0 para los comandos ejecutados correctamente y 1 para los que han terminado incorrectamente.

Funciones, for, switch, if, comparaciones

En los scripts Bash se pueden definir funciones para reutilizar parte del script. Pueden incluir argumentos.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
function() {
   echo "Hola $1!"
}

function("picodotdev")

Además los _scripts_ pueden incluir ciertas sentencias para controlar el flujo de ejecución del _script_ con expresiones condicionales, bucles y comparaciones.

for file in /etc/* do
    echo $file
done
{{% gist id="" file="" %}}

while getopts ":df" opt; do
  case $opt in
	d)
  	echo "Opción «d» indicada"
  	;;
	f)
  	echo "Opción «f» indicada"
  	;;
	\?)
  	echo "Opción inválida: -$OPTARG"
  	;;
  esac
done
funciones-1.sh

Opciones de un script

Opciones de un script
1
2
3
if [ -f $1 ]; then
	echo "El archivo existe."
fi
funciones-2.sh

Los scripts de Bash suelen manejar ficheros y disponemos de una buena cantidad de opciones para comparar:

  • [ -a FILE ]: verdadero si el fichero existe.
  • [ -d FILE ]: verdadero si el fichero existe y es un directorio.
  • [ -e FILE ]: verdadero si el fichero existe.
  • [ -f FILE ]: verdadero si el fichero existe y es un fichero regular.
  • [ -h FILE ]: verdadero si el fichero existe y es un enlace simbólico.
  • [ -r FILE ]: verdadero si el fichero existe y se puede leer.
  • [ -s FILE ]: verdadero si el fichero existe y su tamaño es mayor que cero.
  • [ -w FILE ]: verdadero si el fichero existe y se puede escribir.
  • [ -x FILE ]: verdadero si el fichero existe y se puede ejecutar.
  • [ -N FILE ]: verdadero si el fichero existe y ha sido modificado desde la última lectura.
  • [ FILE1 -nt FILE2 ]: verdadero si FILE1 ha sido modificado más recientemente que FILE2 o si FILE1 existe y FILE2 no.
  • [ FILE1 -ot FILE2 ]: verdadero si FILE2 ha sido modificado más recientemente que FILE1 o si FILE2 existe y FILE1 no.
  • [ FILE1 -ef FILE2 ]: verdadero si FILE1 y FILE2 se refieren al mismo dispositivo y número de inodo.

Y otros menos comunes:

  • [ -S FILE ]: verdadero si el fichero existe y es un socket.
  • [ -b FILE ]: verdadero si el fichero existe y es un fichero especial de bloques.
  • [ -c FILE ]: verdadero si el fichero existe y es un fichero especial de caracteres.
  • [ -g FILE ]: verdadero si el fichero existe y su bit SGID está establecido.
  • [ -k FILE ]: verdadero si el fichero existe y su bit sticky está establecido.
  • [ -p FILE ]: verdadero si el fichero existe y es una tubería con nombre (FIFO).
  • [ -t FD ]: verdadero si el descriptor de fichero está abierto y refiere a una terminal.
  • [ -u FILE ]: verdadero si el fichero existe y su bit SUID está establecido.
  • [ -O FILE ]: verdadero si el fichero existe y el ID del usuario efectivo es su propietario.
  • [ -G FILE ]: verdadero si el fichero existe y el ID del grupo efectivo es su propietario.
  • [ -L FILE ]: verdadero si el fichero existe y es un enlace simbólico.

Y algunos otros:

  • [ -o OPTIONNAME ]: verdadero si la copión OPTIONNAME está activa.
  • [ -z STRING ]: verdadero si la longitud de STRING es cero.
  • [ -n STRING ] o [ STRING ]: verdadero si la longitud de STRING no es cero.
  • [ STRING1 == STRING2 ]: verdadero si las cadenas son iguales.
  • [ STRING1 != STRING2 ]: verdadero si las cadenas no son iguales.
  • [ STRING1 < STRING2 ]: verdadero si léxicamente STRING1 se ordena antes que STRING2 en el locale actual.
  • [ STRING1 > STRING2 ]: verdadero si léxicamente STRING1 se ordena después que STRING2 en el locale actual.
  • [ ARG1 OP ARG2 ]: donde OP es un operador de entre -eq, -ne, -lt, -le, -gt o -ge. Estas operaciones aritméticas binarias retornan verdadero si ARG1 es igual a, no igual a, menor que, menor que o igual, mayor que o mayor que o igual que ARG2, respectivamente. ARG1 y ARG2 son valores enteros.

Las expresiones anteriores se pueden combinar:

  • [ ! EXPR ]: verdadero si EXPR es false.
  • [ ( EXPR ) ]: retorna el valor de EXPR, puede usarse para cambiar la precedencia de operadores.
  • [ EXPR1 -a EXPR2 ]: verdadero si ambas EXPR1 y EXPR2 son verdadero, operador and.
  • [ EXPR1 -o EXPR2 ]: verdadero si alguna de EXPR1 y EXPR2 son verdadero, operador or.

Control de trabajos

El comando jobs obtenemos una lista de trabajos que se está ejecutando junto con su identificador y estado, con la combinación de teclas Ctrl+z dejamos el proceso actual detenido y en segundo plano, con fg lo devolvemos a primer plano y si estaba detenido se continua su ejecución, con bg si estaba detenido continua su ejecución en segundo plano.

Trabajos en primer y segundo plano

Trabajos en primer y segundo plano

Esta guía es parte de un tema de los explicados en el completo libro sobre la administración sobre sistemas Unix, UNIX and Linux System Administration Handbook. Un libro con cantidad de temas para conocer más en detalle nuestros sistemas basados en la filosofía Unix. Casi 1300 páginas de documentación con información básica y detallada que deberíamos obligarnos a conocer. Redes, seguridad, virtualización, hospedaje web, copias de seguridad, procesos periódicos, instalación de software, control de procesos y muchos temas más. Otros buenos documentos son Advanced Bash-Scripting Guide y el siguiente manual de Bash.


Comparte el artículo: