xiaohongshu
xiaohongshu
fish-shell-config
Expert Fish shell configuration including config files, functions, abbreviations, prompts, environment variables, and scripting. Use when setting up Fish, creating aliases/functions, writing Fish scripts, configuring prompts, or migrating from bash. Keywords: fish shell, fish config, alias, abbr,...
Full skill instructions
Expert guidance for Fish shell setup, configuration, scripting, and interactive features based on official Fish documentation.
Fish philosophy differs fundamentally from bash:
"$var" and $var behave identically (already quoted)~/.config/fish/functions/-U flagset VAR value instead of VAR=valueFish reads configs in this order:
~/.config/fish/
├── config.fish # Main config (keep minimal)
├── conf.d/ # Auto-sourced configs (lexical order)
│ ├── 10-nix.fish # Early: PATH and environment
│ ├── 20-direnv.fish # Middle: tool hooks
│ ├── 30-starship.fish # Late: prompt setup
│ └── 40-aliases.fish # Last: shortcuts and abbrs
└── functions/ # Autoloaded function definitions
├── nix-try.fish
└── my-function.fish
Best practice: Keep config.fish minimal; use conf.d/*.fish for modular configs.
Where: ~/.config/fish/functions/name.fish for autoloading
# ~/.config/fish/functions/ll.fish
function ll --description 'list all files'
eza -la $argv
end
Benefits: Autoloaded on demand, persistent, scriptable, full control
Where: conf.d/40-aliases.fish
# Creates a function under the hood
alias g='git'
alias k='kubectl'
# Better: guard with type check
function __maybe_alias --argument-names name target
if type -q $target
alias $name="$target"
end
end
__maybe_alias g git
__maybe_alias ll eza
Note: In Fish, alias creates a function, so it's callable from scripts.
Where: conf.d/40-aliases.fish
# Expands on SPACE/ENTER in interactive shells
abbr -a gco 'git checkout'
abbr -a gst 'git status -sb'
abbr -a glg 'git log --oneline --graph --decorate --all'
abbr -a kctx 'kubectl config use-context'
# Conditional abbreviation
if type -q kubectl
abbr -a k 'kubectl'
end
Benefits: See expansion before execution, learn command syntax, purely interactive
-l local: Current block/function only-g global: Current session-U universal: Persists across all sessions (stored in ~/.config/fish/fish_variables)-x export: Visible to child processes (environment variable)# Session-only global export
set -gx EDITOR nvim
# Universal (survives restarts)
set -U fish_greeting "" # disable greeting
# Local function variable
function my_func
set -l temp_var "local value"
# temp_var dies when function exits
end
# PATH manipulation (Fish handles it as a list)
set -gx PATH $HOME/.local/bin $PATH
# Check if set before setting
set -q EDITOR; or set -gx EDITOR nvim
$argv - function/script arguments (replaces bash $@, $1, $2...)$status - last command exit code (replaces bash $?)$fish_pid - current shell PID (replaces bash $$)$PATH - automatically colon-delimited when exportedfunction name --description 'what it does'
# $argv contains all arguments
command $argv
end
--description 'text' - shown in completions--wraps command - inherit completions from command--argument-names var1 var2 - name positional argsfunction nix-try --description 'Try a package temporarily' \
--argument-names package
if test (count $argv) -eq 0
echo "Usage: nix-try <package>"
return 1
end
# Command substitution with $()
set -l store_path (nix build nixpkgs#$package --print-out-paths --no-link)
if test $status -ne 0
echo "Failed to build $package"
return 1
end
$store_path/bin/$package
end
funced function_name # Edit in $EDITOR
funcsave function_name # Save to ~/.config/fish/functions/
# Using 'test' command
if test -e /path/to/file
echo "exists"
else if test $count -gt 5
echo "greater than 5"
else
echo "other"
end
# Using command exit status
if command_that_might_fail
echo "succeeded"
end
# Using 'and'/'or'
command1; and command2 # command2 only if command1 succeeds
command1; or command2 # command2 only if command1 fails
# For loop over list
for file in *.txt
echo "Processing $file"
end
# While loop
set -l count 0
while test $count -lt 10
echo $count
set count (math $count + 1)
end
# Iterate over command output (splits on newlines)
for line in (cat file.txt)
echo "Line: $line"
end
switch $argv[1]
case start
echo "Starting..."
case stop
echo "Stopping..."
case '*'
echo "Unknown command"
end
# Two equivalent forms
set output $(command)
set output (command)
# Splits on newlines only (not spaces)
set lines (cat file.txt) # Each line = one list element
# Split on custom delimiter
set fields (echo "a:b:c" | string split ':') # ['a', 'b', 'c']
string builtin)# Split
echo "foo:bar:baz" | string split ':'
# Join
string join ',' a b c # "a,b,c"
# Replace
string replace 'old' 'new' $var
# Match/regex
string match -q '*pattern*' $var; and echo "matched"
# Length
string length "hello" # 5
# Case conversion
string upper "hello" # HELLO
string lower "WORLD" # world
# Single quotes - no expansion
echo 'literal $PATH' # outputs: literal $PATH
# Double quotes - variables/commands expand, but NO word splitting
set var "hello world"
echo "$var" # one argument: "hello world"
echo $var # STILL one argument: "hello world" (Fish doesn't split!)
# No quote needed for variables (Fish doesn't word-split)
set files (ls)
for f in $files # Safe! Each filename is one element
echo $f
end
# All variables are lists
set mylist one two three
# Access elements (1-indexed!)
echo $mylist[1] # "one"
echo $mylist[2] # "two"
echo $mylist[-1] # "three" (last element)
# Ranges
echo $mylist[1..2] # "one two"
echo $mylist[2..-1] # "two three"
# Append
set -a mylist four # now: one two three four
# Prepend
set -p mylist zero # now: zero one two three four
# Count
count $mylist # 5
# Iterate
for item in $mylist
echo $item
end
Fish prompts are functions, not variables:
# ~/.config/fish/functions/fish_prompt.fish
function fish_prompt
set -l last_status $status
# Color codes
set_color blue
echo -n (prompt_pwd)
if test $last_status -ne 0
set_color red
echo -n " [$last_status]"
end
set_color normal
echo -n ' > '
end
# ~/.config/fish/conf.d/30-starship.fish
if type -q starship
starship init fish | source
end
# Run when changing directory
function on_cd --on-variable PWD
if test -f .envrc
direnv allow .
end
end
# Run on Fish start
function on_start --on-event fish_startup
echo "Welcome to Fish!"
end
| Bash | Fish | Notes |
|---|---|---|
VAR=value | set VAR value | Use -gx for export |
export VAR=value | set -gx VAR value | Global + export |
$? | $status | Exit code |
$@ | $argv | All arguments |
$1, $2 | $argv[1], $argv[2] | Positional args |
${VAR} | $VAR or {$VAR} | Braces optional |
$((...)) | math ... | Arithmetic |
[[ ... ]] | test ... | Conditionals |
for i in {1..10} | for i in (seq 1 10) | Ranges |
<<EOF): Use echo or filesbegin; ...; end for groupinguntil: Use while not[[: Use test or [# ~/.config/fish/conf.d/20-direnv.fish
if type -q direnv
direnv hook fish | source
end
# ~/.config/fish/conf.d/10-nix.fish
if test -e /nix/var/nix/profiles/default/etc/profile.d/nix-daemon.fish
source /nix/var/nix/profiles/default/etc/profile.d/nix-daemon.fish
end
# Print variable
echo $PATH
# Check if command exists
type -q command; and echo "exists"
# Show function definition
type function_name
# Show all functions
functions
# Show all variables
set
# Debug mode
fish -d 3 -c 'your command'
# Temporary (session only)
set -gx PATH $HOME/.local/bin $PATH
# Persistent (universal)
set -U fish_user_paths $HOME/.local/bin $fish_user_paths
# ~/.config/fish/functions/gs.fish
function gs --wraps='git status' --description 'git status shortcut'
git status -sb $argv
end
# Only set if not already set
set -q EDITOR; or set -gx EDITOR nvim
# Platform-specific
if test (uname) = Darwin
set -gx HOMEBREW_PREFIX /opt/homebrew
end
When helping with Fish configuration:
Determine what the user needs:
~/.config/fish/functions/name.fishconf.d/40-aliases.fishset -gx in appropriate conf.d/ filefish_prompt functionUse appropriate tools:
Read to check existing configsEdit to modify existing filesWrite to create new function filesBash(fish:*) to test Fish commandsFollow project conventions:
CLAUDE.md for project-specific requirementsconf.d/*.fish numbering (10, 20, 30, 40...)type -q checksProvide working examples:
-l, -g, -U, -x)Explain Fish idioms:
set -gx instead of export VAR=value$argv instead of $1, $2...test instead of [[For detailed information, refer to:
xiaohongshu
technical spec
product ux expert
database patterns
Conduct multi-agent task orchestration and workflow coordination.
Initialize project with Conductor artifacts (product definition,
Expert in web animations, transitions, and motion design using Framer Motion and CSS
Creates Mermaid and ASCII diagrams for flowcharts, architecture, ERDs, state machines, mindmaps, and more. Use when user mentions diagram, flowchart, mermaid, ASCII diagram, text diagram, terminal diagram, visualize, C4, mindmap, architecture diagram, sequence diagram, ERD, or needs visual docume...
PostgreSQL bindings for H3 hexagonal grid system. Use when working with H3 cells in Postgres, including spatial indexing, geometry/geography integration, and raster analysis.
Context-Driven Development skill for projects using Conductor. Use this skill when you detect a `conductor/` directory in the project, when working on tasks defined in a `plan.md` file, or when the user asks about tracks, specs, or plans. Automatically applies TDD workflow, tracks task completion...
Display project status, active tracks, and next actions
Official Stakpak application containerization standard operating procedure, a step-by-step guidline to properly dockerize applications. This is a rule book curated by the Stakpak Team.
Generate, edit, and beat-sync AI video with leading models in one workspace.
The world's fastest calendar for remote work
Transform Your Design with AI Designer by ImgCreator.ai
Revolutionizing Video Production with AI-Powered Creativity
Extend an image past the frame and let AI fill the new aspect ratio.
Discover your celebrity doppelgänger with StarByFace!
ChainClarity explains 700+ crypto whitepapers in plain English, with layered summaries, comparisons, research tools, alerts, and a $4.99 Pro plan.
Opus.ai: Revolutionize Your Web Experience