Algoritmos y Estructuras de Datos Compiladores e Intérpretes Herramientas Lenguaje de programación
!Prog C/C++
Linux Matemáticas
Mates Discretas
Programación Orientada a Objetos Redes y Computación Distribuida Sistemas Operativos

Shell y Bash

[date: 09-02-2024] [last modification: 10-01-2025]
[words: 2799] [reading time: 14min] [size: 39321 bytes]

En este artículo se hará un overview del uso de la shell, más concretamente Bash. Algunos temas a tratar serán comandos, expansiones, redirecciones, tratamiento de caracteres especiales…

Shell

El shell es un programa que provee una interfaz de usuario para acceder a los servicios del Sistema Operativo o ejecutar los diferentes programas. Este puede ser de varios tipos:

En este artículo se hablará de los shells CLI, dado que los otros se han diseñado para que sean intuitivos y sencillos de usar.

Shells CLI principales
shBourne Shell, el primer Shell en las primeras versiones de Unix.
cshC Shell, desarrollado para Unix BSD. Su principal diferencia es que su sintaxis se parecía a C, pero aún así era fácil y rápido de usar de forma interactiva.
tcshTenet C Shell, versión mejorada de csh y retrocompatible con esta.
kshKorn Shell, basada en sh y características de csh.
bashBourne-Again Shell
zshZ Shell, versión extendida de sh, con muchas características de bash, ksh y tcsh. Además, permite añadir temas y customizar el prompt.
PowerShellPowerShell, es el shell por defecto de Windows.
fishFriendly-Interactive Shell, es una shell exótica, lo que quiere decir que no sigue el estándar POSIX con el fin de ser más sencilla y rápida de usar.

Puedes ver una comparativa en Wikipedia. Nótese que en Unix, el shell no está integrado en el kernel, por tanto el usuario puede utilizar otros o escribir el suyo propio.

En Linux, el archivo /etc/shells contiene las rutas a las shells conocidas por el sistema y el archivo /etc/passwd especifica la shell por defecto de cada usuario (también se puede ver en la variable $SHELL). Se puede cambiar con el el comando chsh.

Línea de comandos

Nos centraremos en Bash, que cumple con la especificación POSIX y es la shell por defecto en muchos sistemas (no solo Linux). Actualmente, algunos prefieren zsh, pero todo lo que vamos a ver también se le puede aplicar.

bash se ejecuta como si fuese un comando más:

bash

Y para salir puedes ejecutar exit o Ctrl-D.

Funcionamiento de Bash

El shell es un proceso interactivo que ejecuta comandos, de los que se distinguen dos tipos:

Nótese que los comandos externos son ajenos al shell, almacenados como archivos ejecutables en algún lugar del sistema. Para encontrar estos comandos externos, se busca en las rutas que contenga la variable PATH. Esta es una lista de rutas separadas normalmente por :.

PATH=/usr/local/bin:/usr/bin:/bin:/usr/local/sbin:/usr/sbin:/sbin:/opt/bin

Tenga en cuenta que se busca de forma lineal, por lo que conviene que las rutas más usadas se coloquen al inicio.

Se puede comprobar rápidamente si un comando es interno o externo de la siguiente forma:

type comando

Componentes de un comando y orden de evaluación

Cada comando tiene 3 componentes:

Nótese que en programas más complejos se puede distinguir otro componente, el subcomando, por ejemplo git clone.

Desde que introducimos un comando hasta que se ejecuta, el shell realiza los siguientes pasos en orden:

  1. Redirección E/S
  2. Sustitución de variables
  3. Sustitución de nombres de ficheros

Pero este comportamiento se modifica al usar eval:

  1. Primero se realizan todas las sustituciones
  2. Luego se ejecuta el comando

Ejecución en segundo plano

Varias formas de ejecutar un comando:

sleep 10     # Espera 10 segundos
sleep 10 &   # Lanza el mismo comando pero en segundo plano
             # Se puede lanzar otro comando
jobsMostrar los procesos en segundo plano
fg nTraer el proceso n al primer plano
bg nReanudar un proceso parado en segundo plano

A mayores, para manejar un proceso en primer plano se puede usar Ctrl-C para matarlo y Ctrl-Z para detener su ejecución.

Tabulador y edición de comandos

Uso de tabulador para completar comandos y rutas a archivos. Dando dos veces al tabulador se pueden listar todas las posibilidades.

Durante la edición de comandos en Bash, permite algunos atajos de teclado de Emacs por defecto. Puede usar set -o vim para usar los atajos de Vi.

Movimientos en Bash
Ctrl-A / Ctrl-EIr al inicio (start) / final (end)
Alt-B / Alt-FMoverse una palabra hacia atrás (back) / delante (forward)
Ctrl-W / Alt-DBorrar palabra anterior / siguiente
Ctrl-U / Ctrl-KBorra hasta el principio / final
Ctrl-N / Ctrl-PComando siguiente / anterior. También sirven las flechas arriba y abajo.
Alt-.Escribir el último argumento (!$)
Ctrl-YDeshacer
Ctrl-LLimpia pantalla
Ctrl-DSalir

Expansiones

Más información en man 7 glob

Una expansión en Bash es una secuencia que este interpreta y expande antes de ejecutar el comando. También se les llaman comodines o globbing. Su uso principal es para sustituir nombres de archivos (wildcards):

ls -l *.html  # Lista todos los archivos html

Nótese que si la expansión falla (no hay archivos que coincidan), el argumento se dejará como está.

Comodines para archivos
*Expande a 0 o más caracteres. No cuentan los archivos ocultos
?Expande a 1 carácter
[ ]Expande solo a los caracteres que estén entre los corchetes
[! ] [^ ]Igual que antes, pero que no estén los caracteres

Bash tiene algunos conjuntos de caracteres predeterminados:

Expansión de comandos
$(comando)Ejecuta un comando y obtiene su resultado (stdout).
`comando`Equivalente al anterior.
Otras expansiones
Hola{1,2,3}Generación de strings. Genera Hola1, Hola2 y Hola3 (importante que no haya espacios entre las comas).
Hola{1..3}Equivalente al anterior. Funciona con letras (según códigos ASCII).
Hola{0..50..5}Va de 0 a 50 saltando de 5 en 5.
~Expande al directorio de usuario.
~rootExpande al directorio del usuario especificado.

Historial de comandos

Bash mantiene una lista de los comandos previamente usados. Esta tiene un tamaño definido por HISTSIZE, por defecto 1000, y se almacena por defecto en el archivo ~/.bash_history.

Los parámetros que denoto entre corchetes pueden ser:

Gestión del historial
historyMuestra todo el historial. Se suele combinar con grep.
history -cBorra todo el historial
fc [inicio] [fin]Permite ver, editar y reejecutar el rango de los comando inicio - fin.
fc -l [inicio] [fin]Igual que antes, pero solo se listan.
fc -s ANTES=DESPUES [cmd]Sustituye en un comando anterior y lo reejecuta.
Expansiones relativas al historial
Ctrl-RBúsqueda de un comando en el historial
!!Expande al comando anterior. Muy útil para sudo !!.
![cmd]Expande el comando especificado.
!?textoExpande el comando que contenga texto
^cadena1^cadena2Expande al comando que contiene la cadena1 y la cambiar por cadena2.

Variables

Bash permite la creación de variables. Se distinguen dos tipos:

Variables en Bash
variable=valorCrea una variable local.
export VARIABLE=valorCrea una variable global.
export VARIABLECrea una variable global a partir de una local.
VARIABLE=valor comandoCrea una variable global solamente para el comando dado.
readonly variableMarca una variable como solo lectura.
$variableExpande al valor de la variable.
variable=
variable=""
unset variable
Borra el contenido de la variable.

El comando declare permite declarar variables con determinadas características, además de mostrar información sobre las variables existentes.

Si se usa readonly sin parámetros, se mostrará una lista con todas las variables de solo lectura. Si se usa printenv o env se mostrarán todas las variables de entorno.

Importante

No poner espacios alrededor de =.
Fíjese que una palabra se interpreta como un comando:

una_variable = hola
  • Comando: una_variable
  • Parámetro 1: =
  • Parámetro 2: hola
Operaciones aritméticas
$(( (4+11)/3 ))Resuelve una expresión aritmética de enteros usando una sintaxis similar a C. El texto expande a 0.
$[ (4+11)/3 ]Equivalente al anterior.
bc -lRecibe una expresión de stdin y la procesa. Permite variables y variados operadores del estilo de C. Ver man bc.

Redirecciones

Recuerde que cada proceso tiene asociados 3 archivos especiales para su Entrada/Salida (toda la E/S se hace a través de archivos en Linux):

El comando recibe datos del stdin y luego escribe en stdout o stderr, dependiendo del caso. Pues el usuario puede redirigir estos datos a otro archivo.

Operadores de redirección
comando < archivoEl comando toma la entrada del archivo.
comando << etiquetaToma la entrada para el comando hasta que vuelva a aparecer la etiqueta.
comando <<< "string"Envía el string como entrada para el comando.
comando > archivoEnvía la salida del comando al archivo. Lo sobreescribe si contenía algo.
comando >> archivoEnvía la salida del comando al final del archivo.
comando | comandoPipe: la salida del primer comando es la entrada del segundo.
Redirección de los descriptores
comando 2>&1Envía stderr a stdout. Si no se pone el &, creará un archivo llamado 1.
comando &> archivoEnvía stderr y stdout al archivo. Equivalente a comando > archivo 2>&1

Un lugar muy común para redirigir la salida de un comando es /dev/null, la basura, lo que evita que se muestre nada en la consola.

Es importante que al combinar varias redirecciones de distintos descriptores, 2>&1 o análogos vaya siempre al final del comando a redirigir. Es decir, si quieres redirigir stderr a stdout para pasarselo a grep, debes hacer esto:

params2stderr prueba test prueba 2>&1 | grep "p"

En lugar de:

params2stderr prueba test prueba | grep "p" 2>&1

En este último intentas redirigir la salida de grep, en lugar de la salida del primer comando.

Caracteres especiales

La siguiente lista de caracteres reciben un tratamiento especial por parte de bash:

    Globbing:               * ? [ ] [! ]
    Variables:              $
    Redirección:            < > << >> ` |
    Terminador de comando:  & ;

Por tanto, si quieren utilizar como caracteres literales (no con el significado que les da Bash), será necesario escaparlos.

Tratamiento de caracteres especiales
'Ignora todos los caracteres especiales. El texto no puede contener '.
"Ignora todos los caracteres especiales excepto $ \ y `
\Ignora el caracter especial que viene a continuación. También se puede usar para ignorar el salto de línea.

Algunos comandos

Documentación

El número potencial de comandos es muy grande, y cada uno tiene sus propios subcomandos, con opciones y diferentes parámetros; por lo que resulta muy difícil aprenderlos todos.

Normalmente, los programas disponen de una opción que muestran alguna ayuda básica, comúnmente --help o -h. Para comandos internos se puede usar help <comando>.

$ fdisk --help
Usage:
 fdisk [options] <disk>         change partition table
 fdisk [options] -l [<disk>...] list partition table(s)

Display or manipulate a disk partition table.

Options:
 -b, --sector-size <size>      physical and logical sector size
 [...]
 -h, --help                    display this help
 -V, --version                 display version

For more details see fdisk(8).

Pero el mejor lugar para buscar información concreta es el manual (man).

Manual

Muestra información detallada sobre un comando, aplicación, función C, etc.

man fdisk
  • Desplazamiento: flechas, barra espaciadora, enter o h j k l.
  • u d: mayor desplazamiento
  • q: salir
  • /texto: búsqueda
  • n: siguiente de la búsqueda

Pulsa h para ver el resto de opciones disponibles.

Formato de una página

  • Cabecera: nombre del comando y sección.
  • NAME: nombre y descripción corta del comando.
  • SYPNOSYS: sintaxis del comando.
  • DESCRIPTION: descripción detallada del comando y sus opciones.
  • Otras secciones con más información: AUTHOR, SEE ALSO, EXAMPLES

Organización de las páginas

Se busca según la variable de entorno MANPATH. Ver el comando manpath para más información.

Las secciones se buscan en el siguiente orden: 1 8 2 3 4 5 6 7 9.

SecciónContenido
1Comandos de usuario y aplicaciones
2Llamadas del sistema
3Llamadas de biblioteca
4Ficheros especiales (/dev)
5Formato de ficheros y convenciones (/etc/passwd)
6Juegos
7Ficheros varios, macros e información adicional
8Comandos de administración (root)
9Rutinas del kernel

Opciones de CLI

  • man <section>: especificar la sección
  • man -w: muestra dónde está el archivo de ayuda
  • man -wa: muestra dónde están todos los archivos que coincidan
  • man -f: da una descripción breve. También con whatis
  • man -k: busca por nombre y descripción. También con apropos

El comando whatis mantiene una base de datos para rápidamente realizar búsquedas. Se construye con diferentes comandos, dependiendo de la distribución:

makewhatis
catman
mandb

Otro comando interesante puede ser info, que es el sistema de manuales de GNU. Por lo general es más flexible y completo que man.

Útiles con pipes y redirecciones

tee

Copia la entrada que recibe de stdin y la copia a stdout y otros archivos.

ls -l /bin | tee archivos.txt | less

El comando anterior lista el contenido de /bin, lo guarda en el archivo archivos.txt y luego muestra el resultado con less.

Con el parámetro -a añade al final del archivo en lugar de sobreescribir.

xargs

Lee el stdin y pasa esos datos como parámetros a otro comando.

locate README | xargs cat

El comando anterior encuentra todos los archivos que se llamen README y luego los imprime por pantalla. Nótese que locate solo devuelve las rutas.

locate README | xargs -I % 'cat %; cp % /tmp'

En este otro ejemplo, se hace lo mismo, pero también se hace una copia del archivo a /tmp. xargs sustituye cada línea que lee de stdin por % en el comando especificado.

Anterior: Estructura de directorios Volver a Linux Siguiente: Módulos del Kernel y Servicios