Tutorial de Fish
Este es un tutorial del interprete de comandos de avanzada por antonomasia, la Fish shell.
Este tutorial asume que ya tienes un entendimiento basico de los lenguaje del interprete de comandos y los comandos de Unix.
Activar el interprete de comandos Fish
En nuestro sistema BSD podras cambiar el interprete de comandos con chsh.
chsh -s /usr/local/bin/fish
Deberas reiniciar la sesion para que surta efecto.
Ejecutar Comandos
fish ejecuta comandos como cualquier otra shell: para hacerlo ingresa un comando, seguido por sus argumentos. Los espacios funcionan como separadores.
echo ¡Hola texto-plano.xyz!
¡Hola texto-plano.xyz!
Esto ejecuta el comando echo con los argumentos
¡Hola
y texto-plano.xyz!
. En este caso, es lo
mismo que un solo argumento ¡Hola texto-plano.xyz!
,pero en
muchos casos no lo sera. Si necesitas pasar un argumento que incluya un
espacio, puedes indicarlo con una \
, o utiliza comillas
simples \'\
' o dobles ""
.:
mkdir Mis\ Documentos
# Crea un directorio llamado "Mis Documentos", con un espacio en el nombre
cp ~/Algun\ Fichero 'Mis Documentos'
# Copia un fichero llamado "Algun Fichero" en el directorio "Mis Documentos" del directorio home/
ls "Mis Documentos"
Algun Fichero
Obtener Ayuda
Ejecuta help para abrir la ayuda de fish en un navegador web, y man con la pagina para que abra la pagina de man. Puedes tambien solicitar ayuda con el comando especifico, por ejemplo help set para abrirlo en el navegador web, o man set para presentarlo en la terminal.
man set
set - handle shell variables
Synopsis...
Resaltado de sintaxis
Notaras rapidamente que fish resaltara la sintaxis al vuelo en la medida que la escribas. Los comandos invalidos resultaran por defecto coloreados en rojo:
> /bin/mkd
Un comando peude ser invalido porque no existe o porque se refiere a un fichero que no se puede ejecutar. Cuando el comando sea valido, se presentara en un color diferente:
/bin/mkdir
Las rutas de fichero validas son subrayadas en la medida que las tipeas:
> cat __~/algunfi__
Esto te dira que existe un fichero que comienza con
algunfi
, lo cual es una retroalimentacion util de tener
mientras vas escribiendo.
Pueden cambiarse estos y muchos otros colores ejecutando el comando fish_config, o modificando directamente las variables de color.
Por ejemplo, si deseas desactivar (casi) todo el coloreado, ingresa:
fish_config theme choose none
Esto escoge el tema none
("ninguno"). Para ver todos los
temas de color ingresa:
fish_config theme show
El solo ejecutar fish_config te abrira una interfaz de navegador que te permitira escoger entre los temas disponibles.
Comodines
Fish soporta los comodines familiares *
que significa
"todos". Para listar "todos los ficheros JPEG":
ls *.jpg
lena.jpg
meena.jpg
santa maria.jpg
Puedes incluir multiples comodines:
ls l*.p*
lena.png
lesson.pdf
El comodin recursivo doble asterisco es especialmente poderoso, ya que busca en directorios de forma recursiva:
ls /var/**.log
/var/log/system.log
/var/run/sntp.log
Si la busqueda transversal en tales directorios lleva mucho tiempo, puedes usar Ctrl+c para interrumpirla.
Canos y Redirecciones
Puedes usar canos entre comandos con el |
:
echo hola texto-plano.xyz | wc
1 2 12
Puedes redirigir los stdin y stdout con <
y
>
. stderr se redirecciona con2>
.
grep fish < /etc/shells > ~/output.txt 2> ~/errors.txt
Para redirigir stdout y stderr en un fichero, necesitaras primero redirigir stdout, y posteriormente colocar stderr en stdout:
make > salida_make.txt 2>&1
Autosugerencias
En la medida que tipeas, fish te sugerira comandos a la derecha del cursor actual, el color gris:
> /bin/hostname
Conocera las rutas y las opciones:
> grep --ignore-case
Y la historia tambien. Ingresa una vez un comando, y podras volver a invocarlo simplemente tipeando unos pocos caracteres:
> rsync -avze ssh . usuario@algunhuespedlargo.com:/alguna/ruta/larga/hasta/lograr/llegar/a/la/verdad/
Para aceptar la sugerencia presiona flecha derecha del cursor o Ctrl+f. Para aceptar una palabra unica de la autosugerencia, usa Alt+Flecha derecha del cursor. Si la autosugerencia no es lo que quieres, simplemente ignorala.
Si no gustas de recibir autosugerencias, desactivalas configurando
$fish_autosuggestion_enabled
en 0 de la siguiente
manera:
set -g fish_autosuggestion_enabled 0
Autocompletado con Tab
En fish funcionaran un rico conjunto de autocompletados con Tab.
Presiona la tecla tab y fish intentara completar el comando o ruta:
> /pri[Tab] => /privado/
Si hay mas de una posibilidad, te las listara:
> ~/cosas/s[Tab]
~/cosas/sueno.txt (txt, 2.8kB) ~/cosas/script.sh (Executable, 1.3K)
Presiona la tecla tab nuevamente para ciclar entre las posibilidades.
fish tambien es capaz de completar muchos comandos, como ramas de git:
> git merge pr[Tab] => git merge prompt_designer
> git checkout b[Tab]
builtin_list_io_merge (Branch) builtin_set_color (Branch) busted_events (Tag)
¡Intenta presionar la tecla tab para ver que puede hacer fish!
Variables
Como otras shells, en fish el $
seguido por un nombre de
variable resultara reemplazado con el valor de dal variable:
echo Mi directorio de la tilde tilde es $HOME
Mi directorio en la tilde es /home/fulana
Esto se conoce como sustitucion de variables, y tambien sucede su se
utilizan "
, pero no con ''''':
echo "Mi directorio de trabajo es $PWD"
Mi directorio de trabajo es /home/fulana/docs
echo 'Mi directorio de trabajo es $PWD'
Mi directorio de trabajo es $PWD
A diferencia de otras shells, fish no tiene una sintaxis
VARIABLE=VALOR
dedicada para configurar las variables. En
lugar de ello, utiliza un comando ordinario: set, el
cual toma el nombre de la variable, y luego su valor.
set nombre 'Fulana Mengana'
echo $nombre
Fulana Mengana
Te en cuenta el uso de las ""
: sin ellas,
Fulana
y Mengana
habrian sido argumentos
separados, y $nombre
se hubiese convertido en una lista de
dos elementos).
A diferencia de otras shells, las variables no resultan divididas luego de este paso de sustitucion de variables. Entonces:
mkdir $nombre
ls
Fulana Mengana
En Bash, esto hubiese creado dos directorios:
Fulana/
y Mengana/
. En fish, crea solo uno, ya
que la variable cuenta con el valor Fulana Mengana
, de modo
que este es el argumento enviado al comando mkdir, con
espacios y todo.
Puedes eliminar (o "borrar") una variable utilizando el argumento -e or --erase en set. Por ejemplo:
set -e MiVariable
env | grep MiVariable
(sin salida)
Exportar (Variables de Interprete)
A veces necesitaras tener disponible una variable para utilizar en un
comando externo, a menudo como una configuracion de
set. Por ejemplo, muchos programas como git o man leen la variable $PAGER
para
descubrir tu paginador (programa para reveer texto) preferido. Otras
variables utilizas asi incluyen $BROWSER
,
$LANG
(para configurar tu idioma) y $PATH
.
Notaras que estas estas escritas en MAYUSCULAS
, pero esto
es solo por convencion.
Para otorgar una variable a un comando externo, debes "exportarla". A diferencia de otras shells, fish no usa el comando export para ello. En su lugar, podras exportar la variable con set -x o set --export.
set -x MiVariable AlgunValor
env | grep MiVariable
MiVariable=AlgunValor
Tambien puedes des-exportarlas con --unexport o -u.
¡Esto tambien opera a la inveersa! Si fish comienza con algo mas,
heredara las variables exportadas por su proceso progenitor. De modo que
si tu emulador de terminar ejecuta fish, y exporta $LANG
con el valor es_ES
, fish recibira tal configuracion. Y
cualquier emulador que inicies al cual le otorgues variables tambien las
pasaran, a no ser que especificamente decidas no hacerlo. Esta es la
manera en la cual fish recibe usualmente los valores de
$LANG
, $PATH
y $TERM
, sin que se
los debas especificar obligatoriamente.
Las variables exportadas pueden ser locales, globales o universales; "exportar" no es limitado! Usualmente las querrias globalizar con set -gx MiVariable AlgunValor.
Listas
El comando set indicado arriba emplea comillas para asegurar que Fulana Mengana fuese un solo argumento. Si hubiesen sido dos argumentos, entonces el nombre hubiese consitnuido una lista de dos elementos. De hecho, todas las variables de fish son en realidad listas, que pueden contener cualquier cantidad de valores, o de hecho ninguno.
Algunas variables como $PWD
, cuentas unicamente con un
valor. Por convencion, hablamos de valor de la variable, pero
realmente significan su primer (y unico) valor.
Otras variables como $PATH
, cuentan realmente con
multiples valores. Durante la expansion de variables, esta se expandira
para convertirse en multiples argumentos, de la siguiente manera:
echo $PATH
/usr/bin /bin /usr/sbin /sbin /usr/local/bin
Las variables cuyo nombre finaliza con PATH
seran
divididas automaticamente con comas para convertirse en listas. Se unen
utilizando ,
y luego se exportan a subcomandos
individuales. Esto se realiza para retener compatibilidad con otras
herramientas, que esperan que $PATH
use ,
como
divisor. Puedes agregar este hack a una variable con
set --path, o removerlo con set
--unpath.
Las listas no pueden contener sublistas; no existe recursividad. Una variable consiste en una lista de cadenas, sin otra consideracion alguna.
Para obtener un conteo de una lista, utiliza:
count $PATH
5
Puedes agregar (o preceder) a una lista configurando la lista a si
misma, con algunos argumentos adicionales. Aqui agregamos
/usr/local/bin
a la variable $PATH
:
set PATH $PATH /usr/local/bin
Puedes acceder a elementos individuales entrecorchetando con
[]
. En indizado comienza en 1
desde el
comienzo, y desde -1
desde el final:
echo $PATH
/usr/bin /bin /usr/sbin /sbin /usr/local/bin
echo $PATH[1]
/usr/bin
echo $PATH[-1]
/usr/local/bin
Tambien podras acceder a rangos de elementos, conocidos como "cortes":
echo $PATH[1..2]
/usr/bin /bin
echo $PATH[-1..2]
/usr/local/bin /sbin /usr/sbin /bin
Podras reiterar sobre una lista (o corte) con un bucle for:
for val in $PATH
echo "entrada: $val"
end
# Presentara:
# entrada: /usr/bin/
# entrada: /bin
# entrada: /usr/sbin
# entrada: /sbin
# entrada: /usr/local/bin
Las listas adyacentes a otras listas o cadenas resultaran expandidas
como productos cartesianos, a no ser que se encuentren entrecomilladas
con ""
.
set a 1 2 3
set 1 a b c
echo $a$1
1a 2a 3a 1b 2b 3b 1c 2c 3c
echo $a" banana"
1 banana 2 banana 3 banana
echo "$a banana"
1 2 3 banana
Esto es similar a una expansion arbolada.
Sustitucion de Comandos
La sustitucion de comandos utiliza la salida de un comando como
argumento de otro. A diferencia de otras shells, Fish no utiliza
comillas francesas abiertas ``` para sustituir comandos. En
lugar de ellas utiliza
()con o sin el signo
$`:
echo En (pwd), usando $(uname)
En /home/fulana, usando OpenBSD
Un uso comun consiste en capturar la salida de un comando en una variable:
set os (uname)
echo $so
Linux
Las sustituciones de comandos que no usen el signo $
resultan expandidas dentro de las encomillado con ""
, de
modo que hacerlo con $
resulta mas sencillo:
touch "testing_$(date +%s).txt"
ls *.txt
testing_1360099791.txt
A diferencia de otras shells, fish no divide la sustitucion de comandos o ningun espacio en blanco (tales como espacios o tabulaciones), sino nuevas lineas. Esto podria implicar dificultades con algunos comandos tales como pkg-config, el cual presenta lo que deben ser multiples argumentos, como una unica linea. Para dividirlo a lo largo de los espacios en blanco tambien, emplea division de cadenas.
printf '%s\n' (pkg-config --libs gio-2.0)
-lgio-2.0 -lgobject-2.0 -lglib-2.0
printf '%s\n' (pkg-config --libs gio-2.0 | string split -n " ")
-lgio-2.0
-lgobject-2.0
-lglib-2.0
Si requieres una salida de sustitucion de comandos como un argumento
(sin division alguna) utiliza una sustitucion de comandos entrecomillada
con ""
:
echo "primera linea
segunda linea" > mifichero
set mifichero "$(cat mifichero)"
printf '|%s|' $mifichero
|primera linea
segunda linea|
Separar comandos (;)
Como otras shells, fish permite secuenciar multiples comandos tanto en ordenes separadas como en una sola orden por linea.
Para escribirlas en una sola linea, usa el punto y coma
;
. Esto significa que los ejemplos siguientes son
equivalentes.
echo ¡fish; echo es un pescado
# o
echo fish
echo es un pescado!
Status de salida
Cuando un comando sale a la shell, retornara un codigo de status de salida, como un numero entero positivo.
A diferencia de otras shells, fish almacena la ultima status de
salida recibida en $status
en lugar de hacerlo en
$?
.
false
echo $status
1
Esto indica como resulto la ejecucion del comando. 0
significa realmente exito, mientras que los otros significan
determinados casos de fracasos. Por ejemplo, set
--query retornara el numero de variables que solicito que no
estuvieron configuradas con set, mientras que set --query
PATH usualmente devuelve 0
, set --query
arglbargl boogaboo usualmente devuelve 2
.
Tambien existe una lista $pipestatus
variable para cada
status de salidas 1
de los procesos en un
cano.
Combinadores (And, Or, Not)
fish utiliza los combinadores &&
y
||
usuales para combinar comandos, y !
para
negar la combinacion:
./configure && make && sudo make install
Aqui, make se ejecuta solo si ./configure
tiene
exito (devuelve 0), y sudo make install se ejecutara si y solo si
tanbto ./configure
y make
tienen exito.
fish tambien soporta condicionales and, or, y not. Los primeros dos son modificadores de trabajos y tienen precedencia menor. Ejemplo:
cp fichero1 fichero1_bak && cp fichero2 fichero2_bak; and echo "Respaldo exitoso"; or echo "El respaldo fallo"
El respaldo fallo
Como se menciono en la seccion sobre el uso de ;
, esto
tambien podria ordenarse en multiples ordenes, tal como:
cp fichero1 fichero1_bak && cp fichero2 fichero2_bak
and echo "Respaldo exitoso"
or echo "El respaldo fallo"
Condicionales (If, Else, Switch)
Usa if y else para ejecutar codigo condicionalmente, de acuerdo al status de salida de un comando dado.
if grep fish /etc/shells
echo "¡Pesque un fish!"
else if grep bash /etc/shells
echo "¡Pesque un bash!"
else if grep ksh /etc/shells
echo "¡Me pesque un korn-alito!"
else
echo "No pesque shells interesantes."
end
Para comparar cadenas o numeros o consultar las propiedades de un fichero (si existe o si es se lo puede escribir, etc), usamos test, por ejemplo:
if test "$fish" = "cornalito"
echo CORNALITO
end
# o
if test "$numero" -gt 5
echo $cantidad es mayor que cinco
else
echo $cantidad es cinco o menor
end
# o
# Este test es verdadero si existe la ruta /etc/hosts
# - Podria ser un fichero, directorio, o symlink (o posiblemente algo mas).
if test -e /etc/hosts
echo Muy probablemente tengamos un fichero host
else
echo No tenemos un fichero host
end
Tambien pueden utilizarse combinadores para lograr condicionales mas complejas, tales como:
if grep fish /etc/shells; and command -sq fish
echo fish esta instalado y configurado
end
Para condicionales aun mas complejos, utiliza begin y end para agrupar partes de estas condicionales.
Tambien contaras con un comando switch:
switch (uname)
case Linux
echo ¡Hola, Pinguino de Tux!
case Darwin
echo ¡Hola, ¿Como esta Hexley?
case FreeBSD NetBSD DragonFly OpenBSD
echo ¡Hola, monstruo de Beastie!
case '*'
echo "¿Quien eres tu, forastero?"
end
Como ves, case no falla, y puede aceptar argumentos
multiples o comodines entrecomillados con "
.
Funciones incorporadas
En fish, una funcion consiste en una lista de comandos, que podrian
recibir opcionalmente argumentos. A diferencia de otros shells, estos
argumentos no resultaran enviados en forma de "variables numeradas" tal
como $1
, sino que en vez de ellos lo seran en forma de una
lista unica tal como $argv
. Para crear una funcion de este
tipo, utiliza la funcion incorporada function:
function di_hola
echo Hola $argv
end
say_hola
# presenta: Hola
di_hola texto-plano.xyz!
# Presenta: Hola texto-plano.xyz!
A diferencia de otras shells, fish no tiene una sintaxis de prompt especial. Las funciones toman su lugar.
Podras listar el nombre de todas las funciones del interprete con el comando functions incorporado (¡en plural!). fish cuenta con una buena cantidad de funciones incorporadas:
funciones incorporadas
N_, abbr, alias, bg, cd, cdh, contains_seq, dirh, dirs, disown, down-or-search, edit_command_buffer, export, fg, fish_add_path, fish_breakpoint_prompt, fish_clipboard_copy, fish_clipboard_paste, fish_config, fish_default_key_bindings, fish_default_mode_prompt, fish_git_prompt, fish_hg_prompt, fish_hybrid_key_bindings, fish_indent, fish_is_root_user, fish_job_summary, fish_key_reader, fish_md5, fish_mode_prompt, fish_npm_helper, fish_opt, fish_print_git_action, fish_print_hg_root, fish_prompt, fish_sigtrap_handler, fish_svn_prompt, fish_title, fish_update_completions, fish_vcs_prompt, fish_vi_cursor, fish_vi_key_bindings, funced, funcsave, grep, help, history, hostname, isatty, kill, la, ll, ls, man, nextd, open, popd, prevd, prompt_hostname, prompt_pwd, psub, pushd, realpath, seq, setenv, suspend, trap, type, umask, up-or-search, vared, wait.
Podras ver el origen de cualquiera de las funciones pasando su nombre a funcions:
functions ls
function ls --description 'Lista el contenido de un directorio'
command ls -G $argv
end
Existe una funcion llamada alias, pero solo es un atajo para hacer funciones.
Bucles
Bucles While:
while true
echo "Buclear por siempre"
end
# Presenta:
# Buclear por siempre
# Buclear por siempre
# Buclear por siempre
# Si, esto bucleara por siempre. A no ser que abortes con Ctrl+c.
Bucles For
Los bucles For pueden utilizarse paera iterar sobre una lista. Por ejemplo, un listado de ficheros:
for fichero in *.txt
cp $fichero $fichero.bak
end
Podras iterar sobre una lista de numeros utilizando seq:
for x in (seq 5)
touch fichero_$x.txt
end
Prompt
A diferencia de otras shells, mno existe una variable para
prompt tal como PS1
. Para presentar tu
prompt, fish ejecuta la funcion fish_prompt
y
emplea su salida como prompt. Fish tambien ejecuta la funcion
fish_right_prompt
en caso de existir, y usa su salida a la
derecha del prompt.
Podras definir tu propio prompt directamente desde la linea de comandos:
function fish_prompt; echo "Prompt nuevo % "; end
New Prompt % _
En tal caso, si estas satisfecho con este prompt, podras guardarlo en
el disco tipeando funcsave fish_prompt. Esto salvara el
prompt en ~/.config/fish/functions/fish_prompt.fish
. (O, si
lo deseas, puedes crear el fichero manualmente desde el comienzo).
Estan permitidas utilizar prompts de multiples lineas. Podras
configurarle colores a traves de set_color
, pasandole
nombres ANSI de colores, o valores RGB en hexadecimal:
function fish_prompt
set_color purple
date "+%m/%d/%y"
set_color F00
echo (pwd) '>' (set_color normal)
end
Este prompt resultara en:
02/06/13
/home/fulana > _
Puedes escoger entre varios prompts de ejemplo ejecutando fish_config prompt o bien fish_config desde una interfaz web local.
$PATH
$PATH
es una variable de ambiente que contiene los
directorios en los cuales Fish buscara los comandos que introduzcas. A
diferencia de otras shells, $PATH
es una lista, no una
cadena delimitadas por comas ,
.
Fish se encargara de definir $PATH
por defecto, pero
tipicamente solo heredara el $PATH
del proceso padre y lo
configurara como valor que cobre sentido para el sistema (ver exportar).
Para prefijar /usr/local/bin
y /usr/sbin
al
$PATH
, puedes introducir:
set PATH /usr/local/bin /usr/sbin $PATH
Para remover /usr/local/bin
del $PATH
,
ypuedes introducir:
set PATH (string match -v /usr/local/bin $PATH)
Por razones de compatibilidad con otras shell y comandos externos, el
$PATH
es una variable de ruta, y de tal modo resultara
unida con comas (no espacios) cuando lo cites entrecomillado con
""
echo "$PATH"
/usr/local/sbin:/usr/local/bin:/usr/bin
...de este sera exportado de dicha manera, y cuando Fish comience
dividira el $PATH
que recibe en forma de lista dividida por
,
.
Puedes hacerlo directamente en config.fish
, como harias
con otras shells con fichero .profile
.
Una manera mas rapida es usar la funcion fish_add_path
,
que agrega un directorio dato al $PATH
si no estuviese
incluida ya. Esto lo logra modificando la variable universal
$fish_user_paths
, la cual sera prefijada automaticamente
al $PATH
. Por ejemplo, para agregar de forma permanente
/usr/local/bin
a tu $PATH
, introduce:
fish_add_path /usr/local/bin
La ventaja reside en que no tendras que ir editando ficheros de
confuracion. Simplemente escribe esto una vez en la linea de comandos, y
afectara tanto la sesion actual como todas las instancias futuras.
Tambien puedes agregar esta linea al config.fish
, ya que
solo agregara el componente si es necesario hacerlo.
O puedes modicar $fish_user_paths
por ti mismo, pero
debes ser cuidadoso de no agregarlo incondicionalmente
alconfig.fish
, o crecera mas y mas grande.
Inicio (¿donde esta .bashrc?)
Fish inicia ejecutando los comandos dispuestos en
~/.config/fish/config.fish
. Puedes crear este fichero si no
existe.
Es posible crear firectamente funciones y variables para el
config.fish
utilizando los comandos mostrados arriba. Por
ejemplo:
cat ~/.config/fish/config.fish
set -x PATH $PATH /sbin/
function ll
ls -lh $argv
end
Sin embargo, lo mas eficiente y comun es usar funciones de autocargado y variables univeresales.
Si deseas organizar tus configuraciones, fish tambien lee los comandos en los ficheros de extension
.fish
situados en~/.config/fish/conf.d/
.
Funciones de Autocarga
Cuando fish encuentra un comando, intenta autocargar una funcion con
dicho nombre de comando, buscando un fichero con tal nombre o un comando
situado en ~/.config/fish/functions/
.
Por ejemplo, si deseas tener una funcion llamada ll
,
agregarias un fichero de texto llamado ll.fish
a
~/.config/fish/functions
:
cat ~/.config/fish/functions/ll.fish
function ll
ls -lh $argv
end
Esta es tambien la manera preferida de definir tu prompt en Fish:
cat ~/.config/fish/functions/fish_prompt.fish
function fish_prompt
echo (pwd) "> "
end
Variables Universales
Una variable universal es una variable cuyo valor es compartido por todas las instancias de fish, ahora y en el futuro (incluso ante un reinicio). Si administras el sistema, podrias hacer universal una variable con set -U:
set -U EDITOR nano
Ahora, en otra shell:
echo $EDITOR
nano
Conclusion
Has aprendido las grandes diferencias puntuales del shell Fish. ¡Felicitaciones!
No temas anunciarlo a la comunidad con gab:
gab -m "¡No vendo pescado, pues me han ensenado fish!"