El maravilloso poder de las exclamaciones en bash

Nacho - - Tiempo de lectura 3 mins

Bash tiene un montón de features que muchos de sus usuarios no conocemos. Podés usar bash durante años y quedarte en la orillita de lo que es posible. Por ejemplo, durante varios años no conocía el poder de las expresiones con símbolos de exclamación. El otro día pensaba en eso, y me di cuenta que en los años desde que aprendí sobre ellas, las uso un montón. E incluso así, me re quedo en la orilla de lo posible.

Para qué sirven

En general, las exclamaciones sirven para repetir comandos anteriores. Por ejemplo, lo más básico, quiero repetir el comando anterior.

Repetir el comando anterior

1
2
3
4
5
$ echo "hola"
hola
$ !!
echo "hola"
hola

Eso no parece muy útil, después de todo podrías hacer arriba+enter y pasa lo mismo. Pero imaginate que ejecutaste un comando y te diste cuenta de que necesitabas permisos de administrador para hacerlo. Sí, podés ir para arriba, ir al principio de la línea, agregar sudo antes, y enter. Pero eso ya empieza a ser medio molesto. La doble exclamación al rescate, nuevamente:

1
2
3
4
5
$ ls secreto
ls: cannot open directory 'secreto': Permission denied
$ sudo !!
sudo ls secreto
no-veas-esto

Podés también hacer lo mismo para repetir el comando anterior al anterior, usando !-2 en lugar de !!. Y si vas cambiando el número obviamente podés ir más para atrás.

Repetir un pedazo de un comando anterior

No siempre te interesa el comando anterior entero, a veces querés usar un pedazo del comando anterior. Lo más común: querés repetir el último argumento. Por ejemplo, imaginate que querés borrar un directorio, y te dice que el directorio no está vacío. Vos no esperabas eso, así que obviamente querés saber qué hay adentro.

1
2
3
4
5
$ rmdir vacio
rmdir: failed to remove 'vacio': Directory not empty
$ ls !$
ls vacio
mentira

De la misma manera que podés usar !-2 para ir a otro comando anterior, también podés combinarlo con $: !-2$ es el último argumento del comando anterior al último.

Pero no sólo eso, podés también elegir otras partes de los comandos anteriores. Algunos ejemplos:

  • !-2:1 El primer argumento del comando anterior al anterior
  • !!:0 El argumento cero (o sea, el comando) del comando anterior
  • !-3:2-4 Los argumentos del dos al cuatro del comando tres antes que este.

También podés combinar con otras capacidades de bash, como por ejemplo $() que te permite usar la salida de un comando como argumento a otro.

Por ejemplo:

1
2
3
$ find -name 'archivo.txt'
./un/directorio/largo/con/muchos/subdirectorios/archivo.txt
$ cd $(dirname $(!!))

Encontrás un archivo, y en lugar de copiar y pegar, usás bash para ir al directorio en el que está. Más rápido de hacer sin soltar el teclado.

Y muchas más opciones

Incluso después de años de conocer esta funcionalidad, sigo usando sólo !! y !$. Alguna vez, !-2. La posibilidad de referirme a otras porciones del comando aparte del último argumento las tengo presentes, aunque las uso re pocas veces. Pero hay muchas más cosas.

Algunos ejemplos rápidos:

  • !sudo El último comando ejecutado que empieza por sudo
  • !?ls? El último comando ejecutado que contiene ls
  • !!:* Todos los argumentos del último comando, excepto el 0 (el comando en sí mismo).
  • !$:h La parte inicial (antes del último /) del último argumento del último comando. t (tail) en lugar de h (head) es lo opuesto.

La documentación de Bash tiene mucho más para aprender. No, no las vas a usar todas todos los días, pero está bueno saber que las posibilidades existen.