Saltar a contenido

Fish - Shell Interactivo Amigable

Fish (Friendly Interactive Shell) es un shell de línea de comandos inteligente y amigable diseñado para uso interactivo, usabilidad y descubrimiento. Creado por Axel Liljencrantz en 2005, Fish toma un enfoque diferente de los shells tradicionales al priorizar la experiencia de usuario y proporcionar configuraciones predeterminadas sensatas de inmediato. A diferencia de los shells compatibles con POSIX, Fish cuenta con resaltado de sintaxis, autosugerencias, completaciones de pestaña que funcionan sin configuración, y una sintaxis limpia y moderna que busca ser más intuitiva y menos propensa a errores que los lenguajes de shell tradicionales.

Instalación y Configuración

Instalando Fish Shell

# Ubuntu/Debian
sudo apt update && sudo apt install fish

# CentOS/RHEL/Fedora
sudo dnf install fish

# macOS (using Homebrew)
brew install fish

# Arch Linux
sudo pacman -S fish

# FreeBSD
pkg install fish

# From source (latest version)
git clone https://github.com/fish-shell/fish-shell.git
cd fish-shell
cmake .
make
sudo make install

Configurando Fish como Shell Predeterminado

# Check Fish installation
which fish
/usr/bin/fish

# Add Fish to available shells
echo /usr/bin/fish|sudo tee -a /etc/shells

# Set Fish as default shell
chsh -s /usr/bin/fish

# Verify change (restart terminal)
echo $SHELL

Configuración Inicial

# Start Fish shell
fish

# Fish will create configuration directory automatically
# ~/.config/fish/

# Run Fish configuration wizard
fish_config

# This opens a web-based configuration interface
# Accessible at http://localhost:8000

Estructura de Configuración Básica

# Fish configuration files
~/.config/fish/config.fish       # Main configuration file
~/.config/fish/functions/         # Custom functions directory
~/.config/fish/completions/       # Custom completions directory
~/.config/fish/conf.d/            # Additional configuration files

# Create basic config.fish
mkdir -p ~/.config/fish
cat > ~/.config/fish/config.fish << 'EOF'
# Fish configuration

# Set environment variables
set -gx EDITOR vim
set -gx BROWSER firefox

# Add to PATH
set -gx PATH $HOME/bin $PATH
set -gx PATH $HOME/.local/bin $PATH

# Aliases
alias ll 'ls -alF'
alias la 'ls -A'
alias l 'ls -CF'

# Custom greeting
set fish_greeting "Welcome to Fish Shell!"
EOF

Sintaxis y Características del Lenguaje Fish

Variables y Ámbito

# Variable assignment (no $ for assignment)
set name "John Doe"
set age 30
set path "/home/user"

# Using variables ($ required for expansion)
echo $name
echo "Hello, $name"
echo "Age: $age"

# Variable scopes
set -l local_var "local"          # Local to current scope
set -g global_var "global"        # Global to current session
set -U universal_var "universal"  # Universal across all sessions
set -x exported_var "exported"    # Exported to child processes

# Multiple assignment
set fruits apple banana orange
echo $fruits[1]                   # apple (1-indexed)
echo $fruits[2]                   # banana
echo $fruits[-1]                  # orange (last element)

# Array operations
set fruits $fruits grape          # Append
set fruits[2] kiwi               # Replace element
set -e fruits[1]                 # Erase element

Sustitución de Comandos

# Command substitution using parentheses
set current_date (date)
set file_count (ls|wc -l)
set user_home (eval echo ~$USER)

# Nested command substitution
echo "Today is "(date +%A)", "(date +%B)" "(date +%d)

# Store command output in variable
set git_branch (git branch --show-current 2>/dev/null)
if test -n "$git_branch"
    echo "Current branch: $git_branch"
end

Manipulación de Cadenas

# String operations
set string "Hello, World!"
echo (string length "$string")    # String length
echo (string sub -s 1 -l 5 "$string")  # Substring (Hello)
echo (string replace "Hello" "Hi" "$string")  # Replace
echo (string upper "$string")     # Uppercase
echo (string lower "$string")     # Lowercase

# String splitting and joining
set words (string split " " "$string")
echo $words[1]                    # Hello,
set rejoined (string join "-" $words)
echo $rejoined                    # Hello,-World!

# Pattern matching
if string match -q "Hello*" "$string"
    echo "String starts with Hello"
end

# Regular expressions
if string match -qr "W\w+d" "$string"
    echo "String contains word starting with W and ending with d"
end

Declaraciones Condicionales

# if-then-else
if test $age -gt 18
    echo "Adult"
else if test $age -eq 18
    echo "Just turned adult"
else
    echo "Minor"
end

# Test conditions
if test -f "file.txt"             # File exists
    echo "File exists"
end

if test -d "directory"            # Directory exists
    echo "Directory exists"
end

if test "$var" = "value"          # String equality
    echo "Variable equals value"
end

if test $num -eq 10               # Numeric equality
    echo "Number is 10"
end

# Logical operators
if test $age -gt 18; and test $age -lt 65
    echo "Working age"
end

if test $status -eq 0; or test $force = "true"
    echo "Success or forced"
end

if not test -f "file.txt"
    echo "File does not exist"
end

# Switch statement
switch $file_extension
    case "txt"
        echo "Text file"
    case "jpg" "png" "gif"
        echo "Image file"
    case "*"
        echo "Unknown file type"
end

Bucles e Iteración

# for loop
for i in (seq 1 10)
    echo "Number: $i"
end

for file in *.txt
    echo "Processing: $file"
end

for item in $array
    echo "Item: $item"
end

# while loop
set counter 1
while test $counter -le 10
    echo "Counter: $counter"
    set counter (math $counter + 1)
end

# Loop control
for i in (seq 1 10)
    if test $i -eq 5
        continue    # Skip iteration
    end
    if test $i -eq 8
        break      # Exit loop
    end
    echo $i
end

Funciones y Scripting

Definición de Funciones

# Basic function
function greet
    echo "Hello, $argv[1]!"
end

# Function with description
function greet --description "Greet a user"
    echo "Hello, $argv[1]!"
end

# Function with argument validation
function calculate_sum --description "Calculate sum of two numbers"
    if test (count $argv) -ne 2
        echo "Usage: calculate_sum <num1> <num2>"
        return 1
    end

    math $argv[1] + $argv[2]
end

# Function with local variables
function process_file --description "Process a file"
    set -l filename $argv[1]
    set -l line_count (wc -l < "$filename")
    echo "File $filename has $line_count lines"
end

Características Avanzadas de Funciones

# Function with options
function my_ls --description "Enhanced ls with options"
    argparse 'l/long' 'a/all' 'h/help' -- $argv
    or return

    if set -q _flag_help
        echo "Usage: my_ls [-l|--long] [-a|--all] [directory]"
        return
    end

    set -l ls_args
    if set -q _flag_long
        set ls_args $ls_args -l
    end
    if set -q _flag_all
        set ls_args $ls_args -a
    end

    ls $ls_args $argv
end

# Function with completion
function mycommand --description "Custom command with completion"
    switch $argv[1]
        case "start"
            echo "Starting service"
        case "stop"
            echo "Stopping service"
        case "status"
            echo "Service status"
        case "*"
            echo "Usage: mycommand \\\\{start|stop|status\\\\}"
    end
end

# Save function permanently
funcsave greet
funcsave calculate_sum

Manejo de Errores

# Function with error handling
function safe_copy --description "Safe file copy with error handling"
    if test (count $argv) -ne 2
        echo "Error: Exactly two arguments required" >&2
        return 1
    end

    set -l source $argv[1]
    set -l dest $argv[2]

    if not test -f "$source"
        echo "Error: Source file '$source' does not exist" >&2
        return 1
    end

    if test -f "$dest"
        echo "Warning: Destination file '$dest' already exists"
        read -P "Overwrite? (y/N): " -l confirm
        if test "$confirm" != "y"
            echo "Copy cancelled"
            return 1
        end
    end

    if cp "$source" "$dest"
        echo "Successfully copied '$source' to '$dest'"
    else
        echo "Error: Failed to copy file" >&2
        return 1
    end
end

Características Interactivas

Autosugerencias

# Autosuggestions are enabled by default
# Type a command and Fish will suggest completions based on:
# - Command history
# - Valid file paths
# - Command completions

# Accept suggestion: Right arrow or Ctrl+F
# Accept single word: Alt+Right arrow or Alt+F
# Dismiss suggestion: Escape

# Configure autosuggestion color
set -g fish_color_autosuggestion 555

Completaciones de Pestaña

# Tab completions work automatically for:
# - Commands in PATH
# - File and directory names
# - Command-specific options and arguments

# Custom completion for your function
complete -c mycommand -a "start stop status restart" -d "Service commands"
complete -c mycommand -s h -l help -d "Show help"
complete -c mycommand -s v -l verbose -d "Verbose output"

# File-based completion
complete -c myapp -a "(__fish_complete_suffix .conf)" -d "Configuration files"

# Conditional completion
complete -c git -n "__fish_git_needs_command" -a "add commit push pull"
complete -c git -n "__fish_git_using_command add" -a "(__fish_git_modified_files)"

Resaltado de Sintaxis

# Syntax highlighting is automatic and includes:
# - Valid/invalid commands (green/red)
# - Strings and quotes
# - Variables and expansions
# - Comments

# Customize syntax highlighting colors
set -g fish_color_command blue
set -g fish_color_param cyan
set -g fish_color_redirection yellow
set -g fish_color_comment brblack
set -g fish_color_error red
set -g fish_color_escape bryellow
set -g fish_color_operator green
set -g fish_color_quote yellow
set -g fish_color_valid_path --underline

Historial y Búsqueda

# History search (automatic)
# Type partial command and use Up/Down arrows

# History search with specific text
# Type text and press Ctrl+R for reverse search

# History commands
history                           # Show all history
history search "git"              # Search history for "git"
history delete --prefix "rm"      # Delete commands starting with "rm"
history clear                     # Clear all history

# Configure history
set -g fish_history_max 10000     # Maximum history entries

Configuración y Personalización

Variables de Entorno

# Set environment variables
set -gx EDITOR vim
set -gx BROWSER firefox
set -gx PAGER less

# PATH manipulation
set -gx PATH $HOME/bin $PATH
set -gx PATH $HOME/.local/bin $PATH
set -gx PATH /usr/local/bin $PATH

# Remove from PATH
set -l index (contains -i /unwanted/path $PATH)
if test $index -gt 0
    set -e PATH[$index]
end

# Conditional environment variables
if test -d "$HOME/.cargo/bin"
    set -gx PATH $HOME/.cargo/bin $PATH
end

# Platform-specific variables
switch (uname)
    case Darwin
        set -gx HOMEBREW_PREFIX /opt/homebrew
    case Linux
        set -gx XDG_CONFIG_HOME $HOME/.config
end

Alias y Abreviaturas

# Aliases (expanded when defined)
alias ll 'ls -alF'
alias la 'ls -A'
alias l 'ls -CF'
alias grep 'grep --color=auto'

# Abbreviations (expanded when typed)
abbr -a g git
abbr -a gc 'git commit'
abbr -a gp 'git push'
abbr -a gl 'git log --oneline'
abbr -a gst 'git status'

# Conditional abbreviations
if command -v docker >/dev/null
    abbr -a d docker
    abbr -a dc 'docker-compose'
    abbr -a dps 'docker ps'
end

# List and manage abbreviations
abbr -l                           # List all abbreviations
abbr -e gc                        # Erase abbreviation

Personalización del Prompt

Would you like me to continue with the remaining sections?```fish

Simple prompt function

function fish_prompt set_color green echo -n (whoami) set_color normal echo -n "@" set_color blue echo -n (hostname) set_color normal echo -n ":" set_color yellow echo -n (prompt_pwd) set_color normal echo -n "$ " end

Advanced prompt with Git integration

function fish_prompt set -l last_status $status

# User and host
set_color green
echo -n (whoami)
set_color normal
echo -n "@"
set_color blue
echo -n (hostname)
set_color normal

# Current directory
echo -n ":"
set_color yellow
echo -n (prompt_pwd)
set_color normal

# Git information
if git rev-parse --git-dir >/dev/null 2>&1
    set -l branch (git branch --show-current 2>/dev/null)
    if test -n "$branch"
        echo -n " ("
        set_color cyan
        echo -n "$branch"
        set_color normal

        # Check for changes
        if not git diff --quiet 2>/dev/null
            set_color red
            echo -n "*"
            set_color normal
        end
        echo -n ")"
    end
end

# Prompt symbol based on last command status
if test $last_status -eq 0
    set_color green
    echo -n " ❯ "
else
    set_color red
    echo -n " ❯ "
end
set_color normal

end

Right prompt

function fish_right_prompt set_color brblack echo -n (date "+%H:%M:%S") set_color normal end ### Configuración de Tema y Colorfish

Use fish_config for GUI configuration

fish_config

Or set colors manually

set -g fish_color_normal normal set -g fish_color_command blue set -g fish_color_quote yellow set -g fish_color_redirection cyan set -g fish_color_end green set -g fish_color_error red set -g fish_color_param cyan set -g fish_color_comment brblack set -g fish_color_match --background=brblue set -g fish_color_selection white --bold --background=brblack set -g fish_color_search_match bryellow --background=brblack set -g fish_color_history_current --bold set -g fish_color_operator green set -g fish_color_escape bryellow set -g fish_color_cwd green set -g fish_color_cwd_root red set -g fish_color_valid_path --underline set -g fish_color_autosuggestion 555 set -g fish_color_user brgreen set -g fish_color_host normal set -g fish_color_cancel -r set -g fish_pager_color_completion normal set -g fish_pager_color_description B3A06D yellow set -g fish_pager_color_prefix white --bold --underline set -g fish_pager_color_progress brwhite --background=cyan ```## Gestión de Paquetes y Plugins

Administrador de Plugins Fisher

```fish

Install Fisher

curl -sL https://git.io/fisher|source && fisher install jorgebucaran/fisher

Install plugins

fisher install jorgebucaran/nvm.fish fisher install PatrickF1/fzf.fish fisher install franciscolourenco/done fisher install jethrokuan/z

List installed plugins

fisher list

Update plugins

fisher update

Remove plugin

fisher remove jorgebucaran/nvm.fish ### Plugins de Fish Popularesfish

z - Directory jumping

fisher install jethrokuan/z

Usage: z partial_directory_name

fzf integration

fisher install PatrickF1/fzf.fish

Provides Ctrl+R for history search, Ctrl+Alt+F for file search

done - Desktop notifications

fisher install franciscolourenco/done

Notifies when long-running commands complete

nvm for Node.js

fisher install jorgebucaran/nvm.fish nvm install node nvm use node

autopair - Automatic bracket pairing

fisher install jorgebucaran/autopair.fish

bass - Run Bash utilities in Fish

fisher install edc/bass bass source ~/.bashrc ### Instalación Manual de Pluginsfish

Create functions directory

mkdir -p ~/.config/fish/functions

Download and install plugin manually

curl -Lo ~/.config/fish/functions/fisher.fish --create-dirs https://git.io/fisher

Install from local directory

git clone https://github.com/user/plugin.git cp plugin/*.fish ~/.config/fish/functions/ ```## Características Avanzadas y Consejos

Operaciones Matemáticas

```fish

Math command for calculations

math 5 + 3 # 8 math 10 * 2 # 20 (escape * in some contexts) math "10 * 2" # 20 math 20 / 4 # 5 math 17 % 5 # 2

Math with variables

set num1 10 set num2 5 math $num1 + $num2 # 15

Advanced math functions

math "sqrt(16)" # 4 math "sin(3.14159/2)" # 1 math "log(10)" # 2.30259 math "pow(2, 8)" # 256

Floating point precision

math -s2 10 / 3 # 3.33 (2 decimal places) ### Operaciones de Archivos y Globbingfish

Basic globbing

ls .txt # All .txt files ls **/.py # All .py files recursively ls file?.txt # file1.txt, file2.txt, etc.

Advanced globbing patterns

ls *.(txt|md|rst) # Files with specific extensions ls file[1-9].txt # file1.txt through file9.txt

File test operations

if test -f "file.txt" echo "File exists" end

if test -d "directory" echo "Directory exists" end

if test -x "script.sh" echo "File is executable" end

File manipulation

cp source.txt destination.txt mv old_name.txt new_name.txt rm unwanted_file.txt mkdir new_directory rmdir empty_directory ### Gestión de Procesosfish

Background jobs

command & # Run in background jobs # List active jobs fg %1 # Bring job 1 to foreground bg %1 # Send job 1 to background kill %1 # Kill job 1

Process information

ps aux # List all processes pgrep firefox # Find process by name pkill firefox # Kill process by name

Disown processes

command & disown # Detach from shell ### Redirección de Entrada/Salidafish

Output redirection

command > file.txt # Redirect stdout to file command >> file.txt # Append stdout to file command 2> error.log # Redirect stderr to file command &> output.log # Redirect both stdout and stderr

Input redirection

command < input.txt # Read input from file

Pipes

ls -l|grep "txt" # Pipe output to grep ps aux|grep "firefox"|wc -l # Count firefox processes

Tee command

command|tee file.txt # Write to file and stdout ```## Mejores Prácticas de Scripting

Estructura de Script

```fish

!/usr/bin/env fish

Script description

Author: Your Name

Date: YYYY-MM-DD

Function definitions

function usage echo "Usage: $argv[0]

function main # Parse arguments argparse 'h/help' 'v/verbose' -- $argv or return

if set -q _flag_help
    usage
    return 0
end

if set -q _flag_verbose
    set -g verbose true
end

# Main script logic here
echo "Script execution completed"

end

Call main function with all arguments

main $argv ### Manejo de Erroresfish

Check command success

if command_that_might_fail echo "Command succeeded" else echo "Command failed with status $status" exit 1 end

Validate arguments

function validate_file set -l file \(argv[1] if not test -f "\)file" echo "Error: File '$file' does not exist" >&2 return 1 end return 0 end

Use in script

if not validate_file "important.txt" exit 1 end ### Consideraciones de Rendimientofish

Use built-in string operations instead of external commands

set result (string replace "old" "new" $text) # Instead of sed set length (string length $text) # Instead of wc

Avoid unnecessary command substitutions

if test -f "file.txt" # Instead of if test (ls file.txt) echo "File exists" end

Use arrays efficiently

set files *.txt for file in $files # Instead of for file in (ls *.txt) process_file $file end ```## Depuración y Resolución de Problemas

Modo de Depuración

```fish

Run script with debug output

fish -d 3 script.fish

Enable debug in script

set fish_trace 1

Your commands here

set fish_trace 0

Function debugging

function debug_function echo "Function called with arguments: $argv" >&2 echo "Current directory: "(pwd) >&2 echo "Status: $status" >&2 end ### Problemas Comunes y Solucionesfish

Issue: Command not found

Solution: Check PATH and command existence

if not command -v mycommand >/dev/null echo "mycommand is not installed or not in PATH" exit 1 end

Issue: Variable not expanding

Solution: Use proper Fish syntax

set var "value" echo \(var # Correct echo "\)var" # Also correct echo '$var' # Wrong - literal string

Issue: Function not found

Solution: Check function definition and loading

functions myfunction # Check if function exists funcsave myfunction # Save function permanently ### Perfilado de Rendimientofish

Time command execution

time command

Profile function execution

function profile_function set -l start_time (date +%s%N) your_function \(argv set -l end_time (date +%s%N) set -l duration (math "(\)end_time - $start_time) / 1000000") echo "Function took $duration ms" end ```Fish Shell representa un cambio de paradigma en el diseño de shells, priorizando la experiencia de usuario y la capacidad de descubrimiento por encima del cumplimiento estricto de POSIX. Sus sugerencias inteligentes, resaltado de sintaxis y configuración basada en web lo hacen particularmente atractivo para principiantes en la línea de comandos, mientras que sus potentes capacidades de scripting y extenso ecosistema de plugins satisfacen las necesidades de usuarios avanzados. Aunque su sintaxis diferente requiere cierta adaptación para usuarios provenientes de shells tradicionales, el enfoque de Fish en ser útil e intuitivo lo convierte en una excelente opción para uso interactivo de shell y flujos de trabajo de desarrollo modernos.