Skip to main content

Command Palette

Search for a command to run...

Complete Guide: Fish Shell Adding Custom Functions

Published
6 min read
Complete Guide: Fish Shell Adding Custom Functions

WARNING Some of the commands used in this tutorial may not work on your machine, especially if you're using macOS instead of Linux. Tools like free, top, or certain awk filters behave differently across systems. If you run into issues, try using macOS alternatives.

Fish (Friendly Interactive Shell) is a modern, user-friendly command-line shell that offers powerful features like syntax highlighting, autosuggestions, and easy customization. This guide will walk you through downloading Fish and creating custom functions to enhance your command-line experience.

Getting Started with Fish

Launch Fish by typing fish in your terminal, or start a new terminal session if you've set it as your default shell.

Basic Fish Configuration

Fish stores its configuration in ~/.config/fish/. The main configuration file is config.fish.

# Create configuration directory if it doesn't exist
mkdir -p ~/.config/fish

# Edit main configuration file
nano ~/.config/fish/config.fish

Understanding Fish Functions

Fish functions are similar to aliases or shell functions in other shells, but more powerful. They can:

  • Accept arguments

  • Include complex logic

  • Be saved persistently

  • Have descriptions and help text

Function Storage Locations

  • User functions: ~/.config/fish/functions/

  • System-wide functions: /usr/share/fish/functions/

  • Session functions: Defined in memory for current session only

Creating Your First Fish Function

Method 1: Interactive Function Creation

# Start Fish and use the function editor
function hello
    echo "Hello, $argv!"
end

# Save the function permanently
funcsave hello

Method 2: Creating Function Files

Create a file in ~/.config/fish/functions/ with the function name:

# Create the functions directory
mkdir -p ~/.config/fish/functions

# Create a function file
nano ~/.config/fish/functions/hello.fish

Add the function content:

function hello --description "Say hello to someone"
    if test (count $argv) -eq 0
        echo "Hello, World!"
    else
        echo "Hello, $argv!"
    end
end

Practical Fish Function Examples

1. Enhanced Directory Navigation

# ~/.config/fish/functions/mkcd.fish
function mkcd --description "Create directory and cd into it"
    mkdir -p $argv[1] && cd $argv[1]
end

2. Git Shortcuts

# ~/.config/fish/functions/gst.fish
function gst --description "Git status with short format"
    git status --short --branch
end

# ~/.config/fish/functions/glog.fish
function glog --description "Pretty git log"
    git log --oneline --decorate --graph --all
end

# ~/.config/fish/functions/gcm.fish
function gcm --description "Git commit with message"
    if test (count $argv) -eq 0
        echo "Usage: gcm 'commit message'"
        return 1
    end
    git commit -m "$argv"
end

3. System Information Functions

# ~/.config/fish/functions/sysinfo.fish
function sysinfo --description "Display system information"
    echo "System Information:"
    echo "=================="
    echo "Hostname: "(hostname)
    echo "User: "$USER
    echo "OS: "(uname -s)
    echo "Kernel: "(uname -r)
    echo "Uptime: "(uptime | cut -d',' -f1 | cut -d' ' -f4-)
    echo "Memory: "(free -h | grep '^Mem:' | awk '{print $3"/"$2}')
    echo "Disk Usage: "(df -h / | tail -1 | awk '{print $5" used"}')
end

4. Development Environment Functions

# ~/.config/fish/functions/serve.fish
function serve --description "Start a simple HTTP server"
    set port 8000
    if test (count $argv) -gt 0
        set port $argv[1]
    end

    if command -v python3 >/dev/null
        python3 -m http.server $port
    else if command -v python >/dev/null
        python -m SimpleHTTPServer $port
    else
        echo "Python not found"
        return 1
    end
end

# ~/.config/fish/functions/venv.fish
function venv --description "Python virtual environment helper"
    switch $argv[1]
        case create
            python3 -m venv $argv[2]
        case activate
            source $argv[2]/bin/activate.fish
        case deactivate
            deactivate
        case '*'
            echo "Usage: venv [create|activate|deactivate] [name]"
    end
end

5. File and Text Manipulation

# ~/.config/fish/functions/extract.fish
function extract --description "Extract various archive formats"
    if test (count $argv) -eq 0
        echo "Usage: extract <archive_file>"
        return 1
    end

    switch $argv[1]
        case '*.tar.bz2'
            tar xjf $argv[1]
        case '*.tar.gz'
            tar xzf $argv[1]
        case '*.bz2'
            bunzip2 $argv[1]
        case '*.rar'
            unrar x $argv[1]
        case '*.gz'
            gunzip $argv[1]
        case '*.tar'
            tar xf $argv[1]
        case '*.tbz2'
            tar xjf $argv[1]
        case '*.tgz'
            tar xzf $argv[1]
        case '*.zip'
            unzip $argv[1]
        case '*.Z'
            uncompress $argv[1]
        case '*.7z'
            7z x $argv[1]
        case '*'
            echo "Don't know how to extract '$argv[1]'"
            return 1
    end
end

Advanced Function Features

Function Arguments and Options

function myfunction --description "Example function with options"
    argparse 'h/help' 'v/verbose' 'o/output=' -- $argv
    or return

    if set -q _flag_help
        echo "Usage: myfunction [options] <input>"
        echo "Options:"
        echo "  -h, --help     Show this help"
        echo "  -v, --verbose  Verbose output"
        echo "  -o, --output   Specify output file"
        return
    end

    if set -q _flag_verbose
        echo "Verbose mode enabled"
    end

    if set -q _flag_output
        echo "Output file: $_flag_output"
    end

    echo "Processing: $argv"
end

Using Variables and Conditionals

function backup --description "Backup files with timestamp"
    set timestamp (date +%Y%m%d_%H%M%S)

    if test (count $argv) -eq 0
        echo "Usage: backup <file1> [file2] ..."
        return 1
    end

    for file in $argv
        if test -f $file
            cp $file "$file.backup_$timestamp"
            echo "Backed up: $file -> $file.backup_$timestamp"
        else
            echo "File not found: $file"
        end
    end
end

Managing Fish Functions

Listing Functions

# List all functions
functions

# List functions matching a pattern
functions | grep git

# Show function definition
functions functionname

Editing Functions

# Edit a function interactively
funced functionname

# Save changes permanently
funcsave functionname

Removing Functions

# Remove from current session
functions -e functionname

# Remove permanently
rm ~/.config/fish/functions/functionname.fish

Fish Configuration Tips

Setting Environment Variables

# In ~/.config/fish/config.fish
set -gx EDITOR vim
set -gx PATH $HOME/bin $PATH
set -gx GOPATH $HOME/go

Creating Aliases

# In ~/.config/fish/config.fish
alias python    'python3'
alias l         'ls -a'
alias ll        'ls -la'
alias grep      'grep --color=auto'
alias ..        'cd ..'
alias ...       'cd ../..'
alisa c         'clear'

Custom Prompt

# ~/.config/fish/functions/fish_prompt.fish
function fish_prompt
    set_color $fish_color_cwd
    echo -n (basename (prompt_pwd))
    set_color normal
    echo -n ' $ '
end

Troubleshooting Common Issues

Function Not Loading

  1. Check function file location

  2. Verify syntax with fish -n ~/.config/fish/functions/functionname.fish

  3. Reload Fish configuration: source ~/.config/fish/config.fish

Best Practices

  1. Use descriptive function names - Make them easy to remember

  2. Add descriptions - Use the --description flag

  3. Handle arguments properly - Check for required arguments

  4. Provide help information - Include usage examples

  5. Test functions thoroughly - Especially error conditions

  6. Keep functions focused - One function, one purpose

  7. Use meaningful variable names - Improve readability

  8. Comment complex logic - Help future you understand the code

Conclusion

Fish shell offers a powerful and user-friendly environment for command-line work. With custom functions, you can automate repetitive tasks, create shortcuts for complex commands, and build a personalized toolkit that matches your workflow.

Start with simple functions and gradually build more complex ones as you become comfortable with Fish's syntax and capabilities. The investment in learning Fish and creating custom functions will pay dividends in improved productivity and a more enjoyable command-line experience.

Remember to back up your Fish configuration regularly, and consider using version control to track changes to your functions and configuration files.

More from this blog

W

Whats wrong with ...?

6 posts

A programming blog where I debug problems, share solutions, and learn in public. Join me as I explore what's wrong with code, concepts, and my own understanding—then fix it together.