Las conchas de tu madre
Pues hoy vengo a hablar de conchas ─o shells, en inglés─ dentro del entorno de Emacs. No pude resistirme a la tentación de escribir el título así, ya me perdonará quien entienda otra cosa o piense que va leer algún tipo de artículo soez o socarrón, quizá campechano, sobre temas reproductivos humanos. Pero lamentablemente la cosa va de herramientas que vienen con nuestro editor favorito.
Esto parte de una conversación en el canal de Telegram del
blog. Patricio nos preguntó por qué no utilizábamos más eshell
o
por qué no hablábamos de él. Nos hizo una pequeña demostración con un
par de ejemplos para demostrarnos su potencia y la cosa quedó
ahí... bueno, no del todo, porque ahora os vengo a cansinar yo con
las conchas.
Efectivamente, son las conchas, porque hay más de una opción y cada una tiene su clít... cosa. Pero para resumir las enumero y luego hacemos hincapié más despacio en ellas, con algunos trucos y todo.
shell
: Ejecuta el shell predeterminado del sistema, en mi caso esbash
, dentro de un buffer de Emacs. Se llama a esta función con el comandoM-x shell
. Es una subshell y no podrá ejecutar todos los comandos que se le pasen, por ejemplo, no funcionan aquellos programas que funcionan sobrecurses
o cosas más visuales.term
: Ejecuta el shell que le digamos, pues pregunta antes de lanzar un terminal. Este comando abre un terminal completo en un buffer de Emacs. Es interactivo, como el anterior y además sí funcionarán las aplicaciones basadas encurses
. La forma de invocarlo puede serM-x term
desde el minibuffer oansi-term bash
desde código (sustitúyasebash
porzsh
o cualquier otroshell
de nuestra preferencia).eshell
: Este paquete es un emulador de terminal escrito enteramente enelisp
. Funciona sin recurrir a aplicaciones externas para emular una consola y viene con varios programas que sustituyen comandos externos. La ventaja de este emulador es que evalúa cualquier comandoelisp
en la línea de comandos y nos proporciona una manera sencilla de hacer nuestros scripts enelisp
en lugar de hacerlo enbash
ozsh
o...
Así pues, tenemos tres conchas que toquetear ¿cuál elegir? Pues
depende fundamentalmente de lo que queramos hacer. La forma más rápida
de ejecutar un comando de shell desde Emacs es utilizar el
minibuffer
con M-!
, esto llama al comando shell-command
y nos
pregunta por un comando. La salida del mismo nos la muestra en un
buffer llamado *Shell Command Output*
. También es posible que la
salida se vuelque al buffer actual si le damos un argumento
numérico... por ejemplo si queremos que nos añada al buffer una
lista de los ficheros en el directorio, podemos teclear M-1 M-! ls
-lh *.txt
y nos añadirá una lista de todos los ficheros con extensión
.txt
que encuentre en el directorio de trabajo.
También en ocasiones lo que queremos es que se ejecute el comando pero
en segundo plano. Lo mismo que hacemos en el terminal cuando
ejecutamos cualquier comando finalizándolo con el carácter &
. En
este caso Emacs nos proporciona el comando async-shell-command
y
lo podemos invocar con la combinación M-&
en lugar de M-!
. Si ese
comando produce cualquier salida, la mostrará en un buffer con el
nombre *Async Shell Command*
.
Pero bueno, en realidad todo esto no es una concha, sólo nos permite acceder a los comandos del sistema sin necesidad de cerrar el entorno de edición. Lo que queremos hacer es tener una terminal interactiva.
Shell
El terminal más a mano que tenemos en Emacs es el comando shell
.
Como he dicho antes ejecuta la mayoría de los comandos pero tiene
limitaciones puesto que no constituye un terminal completo. Además
Emacs tiene la costumbre de abrir la concha en un buffer con
nombre *shell*
, si ya tenemos uno abierto, lo que hace es llevarnos
a él, pero no abre uno nuevo. ¿Se pueden tener varios buffers con
distintas sesiones de shell abiertas? Pues sí. Además, para hacerlo,
tenemos varias alternativas. La primera consiste en renombrar el
buffer donde tenemos abierta la sesión con M-x rename-uniquely
y
veremos que nos pondrá el nombre a algo como *shell<2>*
, ahora
podemos llamar de nuevo a M-x shell
y tendremos dos buffers
independientes, uno con nombre *shell*
y otro con nombre
*shell<2>*
. La otra opción es utilizar el comando C-u M-x
shell
. Este comando nos pregunta por un nombre para el buffer, si
le proporcionamos uno distinto de shell
nos lo abrirá en un buffer
con ese nombre.
No voy a entrar en más profundidades. Podría poner una lista de combinaciones de teclas que funcionan en este modo, pero no quiero alargar innecesariamente el artículo, porque el objetivo son las dos conchas más potentes. Pero siempre tenéis a mano la ayuda para conocer los atajos.
Term
Básicamente term
funciona como el anterior shell
sin embargo,
tiene características que lo hacen más potente. Pero antes de seguir
tienes que recordar que la tecla que le sirve como escape es C-c
.
¿Qué es capaz de hacer éste terminal? Pues cualquier cosa que pueda
hacer un terminal... el resumen es que un buffer de nuestro Emacs
se ha convertido en un terminal completo, como puede ser xterm
o
KiTTY
o Terminator
o cualquier otro al uso.
Podemos ver en la imagen anterior, cómo incluso podemos ejecutar una
sesión de Emacs dentro de un terminal dentro de Emacs, sólo
tenemos que recordarle que funcione en modo texto con el comando
emacs -nw
y funciona sin que se produzca una anomalía dentro del
espacio-tiempo, ni nada. Eso sí, para enviarle combinaciones de teclas
tenemos que escaparlas y el comando para salir, será por tanto C-c
C-x C-c C-c
. O por poner otro ejemplo, que no necesitará escapar los
comandos, podemos ejecutar vim
dentro de Emacs:
En este caso, como digo, puesto que los comandos de vim
no coinciden
con las combinaciones de Emacs no nos hará falta escaparlos para
que se ejecuten.
Hablando de estas cosas de escapar comandos, en el terminal tenemos
que tener en cuenta el modo de trabajo que tengamos establecido.
Podemos estar en line mode o en char mode. Si queréis apreciar la
diferencia sólo tenéis que hacer pruebas en el mismo terminal. Con
C-c C-j
se entra en term-line-mode
y con C-c C-k
entramos en
term-char-mode
. Algunos de los comandos sólo funcionan cuando
estamos en modo char
, como C-c C-c
que envía al programa que esté
ejecutando el terminal un C-c
, o C-c CHAR
que sería el equivalente
de enviar en el Emacs normal un comando C-x CHAR
.
Además, el terminal también nos permite realizar conexiones remotas a
través de ssh
o telnet
. Y ya para rematar, también podemos
utilizar el terminal a través de un puerto serie con M-x serial-term
y comunicarnos con cualquier dispositivo que tengamos conectado a un
puerto serie. Nos preguntará por el nombre del puerto y por la
velocidad. Además podemos configurar el puerto serie pinchando en
8N1
en la línea de modo, lo que significa que cada byte
consiste
en 8 bits, sin paridad (No parity) y un stopbit
. Si la velocidad
no está bien configurada, seguramente sólo obtendrás basura del
puerto, así que primero mirad bien el manual de instrucciones de lo
que quiera que conectéis... en mi caso probé en su día con un par de
lectoras de marcas y me permitió cargar configuración e incluso leer
formularios. Un lujo al alcance de todos.
Eshell
Pues aquí viene la joya de la corona de los terminales para Emacs.
eshell
está escrito enteramente en elisp
. ¿Qué nos proporciona?
pues toda la potencia de Emacs en el terminal. En el caso
anterior, debíamos ejecutar term
indicando qué concha llamar
(bash
, zsh
, fish
...), el buffer se convertía en
un intermediario entre ese comando y nosotros, por lo que estamos
limitados a hacer las cosas que hagamos en un terminal normal. O dicho
de otro modo, hemos cambiado una ventana de xterm
por un buffer de
Emacs ─que ya está bien para muchas cosas─.
Pero para apreciar la diferencia, abre eshell
con el comando M-x
eshell
y teclea cualquier comando elisp
o de Emacs y mira a ver
qué hace... por ejemplo: prueba a escribir (+ 2 3)
y te devolverá
5
. Pero mucho más interesante que eso: estás navegando por los
directorios y te gustaría abrir un fichero... tecleas find-file
nombre-fichero.ext
y ¡eh! lo abre en un buffer... dired
, magit
,
cualquier comando responderá como se espera.
Funciona con todos los comandos que se invocan desde M-x
. Incluso
puede llamar, si lo necesitas a un terminal ansi
con el comando
ansi-term bash
si fuera el caso. Con los comandos más gráficos
ocurre como con shell
no funcionan algunos comandos más visuales, no
podemos tener vim
corriendo en él, por ejemplo, pero tampoco es tan
grave, dado que ampliamos el terminal con la potencia de los comandos
de Emacs, y si bien git log
no terminará de verse bien y funcionar
correctamente, puedes utilizar magit-log
para abrir un buffer de
magit
.
También, por supuesto, podemos ejecutar varios comandos separándolos
con ;
o en segundo plano terminándolos con &
, como en otros
terminales.
Comandos internos
Eshell
define algunos comandos internos. En algunos casos para
sustituir a comandos externos del sistema operativo. Por ejemplo, si
estás ejecutando eshell
, prueba el siguiente comando:
~ $ which ls eshell/ls is a compiled Lisp function.
y sin embargo, podemos seguir accediendo al comando del sistema:
~ $ which *ls /usr/bin/ls
Es decir, si queremos utilizar el comando correspondiente del sistema,
debemos ponerle un *
delante. No voy a hacer una lista exhaustiva de
todos los comando, pero por nombrar algunos tenemos: alias
, clear
,
date
, diff
, grep
, info
, kill
, make
...
Para nuestros scripts también cuenta con algunas variables internas que podemos utilizar:
$+
- Directorio de trabajo actual.
$-
- Directorio de trabajo anterior.
$_
- El último argumento del último comando.
$$
- El resultado del último comando interno, si el comando es
externo contendrá
t
onil
. $?
- Código de salida del último comando que puede ser
0
o1
.
Además de las habituales variables $*
para pasar todos los
argumentos o $1
, $2
... para pasar el argumento correspondiente.
Aliases
Eshell
nos permite tener también alias para nuestros comandos. Es
un poco distinto de cómo funcionan los alias en bash
, pero no
demasiado. Para eshell
, los argumentos se deben definir
explícitamente, es decir, en bash
nos podemos encontrar algún alias
definido del estilo de:
alias ls = "ls --color" alias ll = "ls -l"
En eshell
las definiciones serían más del estilo: alias ls 'ls
--color $*'
, o alias ll 'ls -l $*'
. Como se puede apreciar, hay que
especificar el uso de argumentos.
Manejar explícitamente los argumentos nos permite crear alias más
complejos como por ejemplo alias mcd 'mkdir $1 && cd $1'
, que lo que
hará si escribimos mcd lo-que-sea
es crear un directorio con nombre
lo-que-sea
y movernos a él.
Cuando utilizamos un alias
en la línea de comandos, eshell
lo
guarda para siguientes sesiones en un fichero y, por supuesto, también
podemos modificar nuestro fichero de aliases
directamente. Dicho
fichero de alias
será aquél que apunte la variable
eshell-aliases-file
, que por defecto es ~/.emacs.d/eshell/alias
,
pero que, como todo en Emacs podemos configurarlo y cambiarlo.
Redirección
Los operadores de redirección son los habituales de un shell
, es
decir, funcionan los habituales >
o >>
. Esos operadores sirven
para guardar la salida de un comando en un fichero (>
) o para añadir
la salida de un comando a un fichero (>>
). ¿Y si queremos llevar la
salida de un comando a un buffer? Pues para eso, eshell
nos
proporciona el operador >>>
.
Por ejemplo: echo "Hola Mundo!" >>> #<buffer *scratch*>
insertará la
cadena «Hola Mundo!» en el buffer *scratch*
. También servirá la
forma más corta del nombre del buffer #<*scratch*>
. Y también,
atentos a las comillas, porque si no, es posible que la salida que nos
encontremos sea ("Hola" "Mundo!")
, que no era lo deseado ─o a lo
mejor sí, que nunca se sabe lo que quiere un usuario de /Emacs/─.
Conclusión
Tienes a tu alcance toda la potencia del shell sin salir de Emacs. En ningún momento necesitas abandonar el editor para ejecutar lo que quiera que necesites hacer en el Sistema Operativo. Lo tienes a un golpe de tecla... y además con varias opciones para elegir la que mejor se adapte a eso que quieres, o necesitas, hacer.
El eshell
es un lujo cuando te acostumbras a él, pero cuidado: luego
intentarás abrir ficheros con find-file
en tu terminal favorito,
fuera de Emacs y tendrás que obligarte a repensar lo que quieres
hacer sin los comandos de Emacs a mano. No puedes teclear dired
en
un xterm
y navegar por los directorios y los ficheros... no, no hace
falta que abras Emacs ─si no lo tienes abierto─ para lo que sea,
basta recordar que ahí fuera las cosas son distintas...
Cuando me preguntan por qué me gusta tanto Emacs es fácil: por cosas
como ésta. Flexibilidad, potencia, el poder adaptar la herramienta a
mí en lugar de adaptarme yo a la herramienta. Porque puedo ejecutar,
por ejemplo vim
, en un buffer y trabajar como lo haría desde un
terminal normal. Y además hacerlo tanto en modo gráfico como en modo
texto, de la misma manera y con la misma efectividad.
Comentarios