miércoles, enero 30, 2019

fish shell: Notas

fish es un shell para sistemas operativos de tipo Unix: Un programa que se encarga de aceptar la entrada del usuario y ejecutar las órdenes que éste le da y que sirve de interfaz en modo texto con el sistema operativo. Al contrario que otros shell, este no deriva de la familia de Bourne Shell ni de la de C Shell, sino que implementa su propia sintaxis para hacer un intérprete de comando lo más sencillo y amigable que se pueda.

Este shell me lo descubrió un compi de trabajo. Me llamaba bastante la atención como usaba el resaltado de sintaxis para señalar cada parte de la línea de órdenes, como funciona el autocompletado de comandos y como recuerda éstos en función del contexto. Así que decidí probarlo unos días. Lo que no hice fue cambiar con chsh el shell por defecto de mi usaurio, sino decir al emulador de terminal que uso, iTerm2, que ejecutase fish en vez bash.

Al ser un programa de código abierto lo podemos compilar de las fuentes o usar uno de los paquetes precompilados para diferentes plataformas que existe: Diversas distribuciones de Linux, FreeBSD, macOS o Windows. En mi caso, puesto que uso macOS opté por la versión precompilada en formato pkg que se instalará en /usr/local/bin.

En estos meses que he usado fish, las ventajas que le veo son:

  • Un sistema de autocompletado de comandos y parámetros mucho más cómodo que el de bash.
  • El uso que realiza de la sintaxis de colores para distinguir los parámetros, el comando que se está ejecutando o el comando que ha fllado.
  • La posibilidad de ir completando por argumentos la línea de comandos.
  • En lo poco que lo he usado para hacer shell script, la ausencia de quotes o construcciones estrañas que nos encontramos en bash.

Por otra parte, su principal desventaja ees no ser parecido al Bourne Shell o al Csh, con lo cual entramos en el terreno de los shell exóticos: No lo usa tanta gente y hay menos recursos para poder aprender.

Mi idea es ir anotando en esta entrada las cosas que vaya usando de fish, así como poner traducciones de comandos que se utilizan en bash (derivado del Bourne Shell) a fish.

Algunos ejemplo de las capacidades coloreado de sintaxis en función de la parte del comando que se trate. Todo esto es configurable con temas que se pueden instalar y configurar a nuestro gusto.

> ~ ls -al /usr/local/bin/fish*
 ~/D/b/002 - icewinddale echo $PATH
~/D/b/002 - icewinddale echo (pwd)
> ~/D/b/002 - icewinddale open blog2.html
> ~/D/b/002 - icewinddale echo "Drizz

A partir de ahora, la entrada la voy a dividir en diferentes epígrafes donde voy a ir anotando lo que voy aprendiendo sobre este shell y como se compara con otros shells. Veréis esta entrada incompleta porque voy a ir escribiendo sus apartados conforme vaya leyendo y probando las cosas.

Ejecutando comandos

Lo primero que va a llamaros la atención cuando se ejecuta un comando es que el color de lo que estamos escribiendo va a cambiar. Si lo que escribimos no se corresponde con ningún comando que el sistema pueda ejecutar, veremos en rojo el comando. fish soporta tanto recomendaciones cuando empezamos a escribir comandos como autocompletado de los mismos cuando se pulsa la tecla TAB, como ocurre con otros shells. Podemos aceptar las sugerencias que nos ofrece fish pulsando → en nuestro teclado. En caso que queramos ir saltando de parámetro en parámetro usamos ALT + →

El autocompletado con la tecla TAB también funciona para las variables de entorno.

La redirección de entrada y salida se hace en fish así. La diferencia es que aquí se usa ^ para redirigir la salida estándar de error (en bashm, por ejemplo se usa 2>h;).

awk < file.in > file.out ^ file.err

Se puede concatenar comandos usando el punto y coma. El valor devuelto por los comandos se almacen a en la variable $status. En los shells compatibles con Bourne Shell la variable es $?.

$ echo "Hi!";echo $status
Hi!
0

Aparte del clásico uso de * y ? para hacer globing para seleccionar nombres de ficheros, fish tiene otra interesante opción que es **. Cuando se usa este patrón, fish bajará por el árbol de directorio buscando aquellos ficheros y directorios que coincidan con el patrón. Por ejemplo, el siguiente comando recorre el árbol de directorios desde la ruta actual e imprime los ficheros y directorios que terminen en .deb:

ls **.deb

Para ejecutar comandos y quedarnos con el resultados la construcción que utiliza fish es (), frente a las backstick `` de bash. Por ejemplo:

# En fish imprimirá la ruta actual
$ echo (pwd)
/home/ubuntu
# El equivalente al comando anterior en bash
$ echo `pwd`
/home/ubuntu
Una diferencia importante es que esta sustitución no funciona dentro de cadenas de texto delimitadas por comillas, así mientras que en bash se puede hacer:
# En bash
$ echo "La ruta es `pwd`."
La ruta es /home/ubuntu.
# En fish
$ echo "La ruta es "(pwd)"."
La ruta es /home/ubuntu.

Variables de entorno

Las variables en fish son listas. Eso se puede ver fácilmente con la siguiente secuencia de comandos:

$ echo $PATH
/home/ubuntu/bin /home/ubuntu/.local/bin /usr/local/sbin /usr/local/bin /usr/sbin /usr/bin /sbin /bin /usr/games /usr/local/games /snap/bin
$ echo $PATH[2]
/home/ubuntu/.local/bin
$ echo $PATH[-2]
/usr/local/games
$ echo echo $PATH[1-2]
/home/ubuntu/bin /usr/local/games

Si el índice es negativo, se empieza a contar desde el final, mientras que también se permiten rangos

set es la orden del shell que se usa para manejar las variables. Por ejemplo, si se quiere crear una variable que tenga la ruta actual del sistema. Si se usa sin parámetros, nos imprimirá todas las variables que hay en el sistema ordenadas por orden alfabético:

$ set
MD_DURATION 121
COLORFGBG '15;0'
COLORTERM truecolor
COLUMNS 87
...

Las variables pueden tener tres posibles alcances, aparte de poder ser exportadas - es decir, estár disponible para los subprocesos que se lance desde el shell o no -. Los posibles alcances de la variables son:

  • locales, se crean pasando el parámetro -l. La variable sólo es válida en el bloque actual de código.
  • globales, se crean usando el parámetro -g. El alcance será global: La variable estará disponible durante la ejecución del shell una vez que se ha declarado.
  • universal, se crean con el parámetro -U. Estarán disponibles en todos los procesos fish que esté ejecutando el usuario en ese momento.
Ejemplos:
# Este es un ejemplo de local. Puede verse como el valor no se ve fuera del bloque
$ echo "Start";begin set -l VPATH (pwd);echo $VPATH; end;echo "VALUE:$VPATH"
Start
/Users/terron
VALUE:
# Este es global. Ahora si veremos el valor
$ echo "Start";begin set -g VPATH (pwd);echo $VPATH; end;echo "VALUE:$VPATH"
Start
/Users/terron
VALUE:/Users/terron
# Por último -U la crearía universal, estaría disponible en todos los shells
set -U VPATH (pwd)

Para exportar una variable y hacerla disponible a los subprocesos que se están ejecutando, se utiliza el parámetro -x. Para borrar una variable del entorno se utiliza -e:

# Este comandio ejecuta bash y hace que muestre las variables
# de entorno. Podemos ver la que hemos exportado, VPATH
$ set -gx VPATH (pwd) ;/bin/bash -c export|grep VPATH
declare -x VPATH="/home/drizzt"
# Para borrar
set -gx VPATH (pwd)
echo $PATH
/home/ubuntu
set -e VPATH
echo $VPATH

No hay comentarios: