up is a Bash and Zsh script that takes the hassle out of navigating parent and ancestor directories. Effortlessly jump multiple levels by index or directory name with autocomplete and regex support. Inspect and dive into directories interactively with fzf—and optionally track your path history for seamless recall.
Kiss tedious cd .. chains goodbye!
Animated GIF generated programmatically with vhs
Animated GIF captured manually with LICEcap
-
Multi-Level Navigation
- Jump up multiple directory levels by index:
up(jumps one level)up 2(jumps two levels)up 3(jumps three levels)
- Jump up multiple directory levels by index:
-
Tab Completion
- Autocomplete parent and ancestor directory names with auto-escape (e.g.,
\!\[special\ dir\]/). - Supports Unicode directories (e.g.,
ダン·メイソン/,日本語/,привет/, emojis like📂/).
- Autocomplete parent and ancestor directory names with auto-escape (e.g.,
-
Regex-Based Navigation
- Use
-rfor general matches,-sfor "starts with,"-efor "ends with," or-xfor exact matches. - Combine with
-ifor case-insensitivity or export_UP_REGEX_DEFAULT=truefor default regex behavior.
- Use
-
Verbose Feedback
- View directory change details with
-vor enable persistent verbosity with_UP_ALWAYS_VERBOSE=true. - Customize output colors with style variables or disable them with
_UP_NO_STYLES=true.
- View directory change details with
-
History Features (Optional)
-
Error Handling
- Provides proper exit codes and styled error messages (
_UP_ERR_STYLE) for clarity; useful for scripts or shell prompts like starship.
- Provides proper exit codes and styled error messages (
-
Compatibility
Download the git repo to your preferred destination. For example:
git clone https://github.com/LittleWalter/up ~/.local/share/shell/upAdd to .bashrc or .bash_profile on Apple macOS systems:
source ~/.local/share/shell/up/up.bash # The `up` function
source ~/.local/share/shell/up/up_completion.bash # `up` completionAssuming your Bash config is at ~/.bashrc, use this snippet to download and append the lines in one step:
git clone https://github.com/LittleWalter/up ~/.local/share/shell/up
echo 'source ~/.local/share/shell/up/up.bash' >> ~/.bashrc
echo 'source ~/.local/share/shell/up/up_completion.bash' >> ~/.bashrcDownload the git repo to your preferred destination. For example:
git clone https://github.com/LittleWalter/up ~/.local/share/shell/upThese scripts are fully compatible with Zsh using bashcompinit.
The autoload lines enable autocompletion modules.
Add to .zshrc:
autoload -U +X compinit && compinit # Enable Zsh completion
autoload -U +X bashcompinit && bashcompinit # Enable Bash completion compatibility
source ~/.local/share/shell/up/up.bash # The `up` function
source ~/.local/share/shell/up/up_completion.bash # `up` completionAssuming your Zsh config is at ~/.zshrc, use this snippet to download and append the lines in one step:
git clone https://github.com/LittleWalter/up ~/.local/share/shell/up
echo 'autoload -U +X compinit && compinit' >> ~/.zshrc
echo 'autoload -U +X bashcompinit && bashcompinit' >> ~/.zshrc
echo 'source ~/.local/share/shell/up/up.bash' >> ~/.zshrc
echo 'source ~/.local/share/shell/up/up_completion.bash' >> ~/.zshrcThe man page for up provides detailed usage information that complements the -h/--help flags and this README. Installing it is optional but recommended for improved command-line documentation.
To install the man page, run the following commands:
cd ~/.config/shell/up/man # Navigate to the directory where the scripts are located
chmod +x install_up_man_page.bash # Ensure the script is executable
./install_up_man_page.bash # Run the installation scriptAfter installation, verify that the man page is available by running:
man upFollowing best practices, I recommend using the XDG Base Directory Specification to reduce HOME directory clutter.
By default, XDG_CONFIG_HOME is $HOME/.config and XDG_DATA_HOME is $HOME/.local/share. However, these paths might not be explicitly defined in your shell configuration; verify with echo $XDG_CONFIG_HOME.
For this project, somewhere within XDG_DATA_HOME makes sense.
Within your .bashrc or .zshrc, or more appropriately .zshenv, you may define these as environment variables:
export XDG_CONFIG_HOME="$HOME/.config" # Configuration files
export XDG_DATA_HOME="$HOME/.local/share" # Persistent data storage
export XDG_CACHE_HOME="$HOME/.cache" # Non-essential files such as shell command history, log files, etc.up offers two straightforward methods to configure environment variables: directly in your shell configuration or through an optional configuration file.
For a complete list of available environment variables and their default values, refer to up --help or consult the optional man page.
Define environment variables directly in your shell configuration file (.bashrc, .zshrc, or .zshenv). This approach integrates seamlessly into your existing shell setup:
export _UP_ERR_STYLE=true
export _UP_HISTFILE=$HOME/.cache/up/up_history.log
export _UP_HISTSIZE=1000
export _UP_ALWAYS_VERBOSE=true
...You can centralize your environment variable definitions in a dedicated configuration file. By default, up looks for ~/.config/up/up_settings.conf. To use a custom path, set the _UP_CONFIG_FILE environment variable:
export _UP_CONFIG_FILE=$HOME/.config/up/my_custom_config.confThe configuration file uses simple key-value pairs to define environment variables:
# ╻ ╻┏━┓ ┏━┓┏━╸╺┳╸╺┳╸╻┏┓╻┏━╸┏━┓ ┏━╸┏━┓┏┓╻┏━╸
# ┃ ┃┣━┛ ┗━┓┣╸ ┃ ┃ ┃┃┗┫┃╺┓┗━┓ ┃ ┃ ┃┃┗┫┣╸
# ┗━┛╹ ╺━╸┗━┛┗━╸ ╹ ╹ ╹╹ ╹┗━┛┗━┛╹┗━╸┗━┛╹ ╹╹
# REF: `man up` or `up --help` for info on environent variables
# Genenal Settings
_UP_ALWAYS_VERBOSE=false
# PWD Settings
_UP_ALWAYS_IGNORE_CASE=false
_UP_REGEX_DEFAULT=false
_UP_FZF_PWDOPTS=(
--height=50%
--layout=reverse
--prompt=" Path: "
--header=" cd ^P"
--preview="eza --color=always --icons --tree {}"
--bind="ctrl-p:toggle-preview"
--bind="ctrl-l:change-preview(eza --color=always --icons -laah {})"
--bind="ctrl-i:change-preview(echo '\`stat\`:'; ustat {})"
--bind="ctrl-t:change-preview(eza --color=always --icons --tree {})"
--bind="ctrl-j:preview-page-down,ctrl-k:preview-page-up"
--preview-window=70%,border-double,top
--preview-label="[ ^L ^T ^I ^J ^K ]"
# Catppuccin Mocha theme
--color="fg:#c6aad9,hl:#f5a97f"
--color="fg+:#f4dbd6,bg+:#272935,hl+:#94e2d5"
--color="info:#a6da95,prompt:#c6a0f6,pointer:#e28b83,marker:#94e2d5,spinner:#f5a97f,header:#e5c890"
)
# History Settings
_UP_ENABLE_HIST=true
_UP_HISTFILE=$XDG_CACHE_HOME/up_history.log
_UP_HISTSIZE=1000
_UP_FZF_HISTOPTS=(
--height=50%
--layout=reverse
--prompt=" Path: "
--header=" cd ^P ^D Missing Paths Omitted"
--preview="eza --color=always --icons --tree {}"
--bind="ctrl-p:toggle-preview"
--bind="ctrl-l:change-preview(eza --color=always --icons -laah {})"
--bind="ctrl-i:change-preview(echo '\`stat\`:'; ustat {})"
--bind="ctrl-t:change-preview(eza --color=always --icons --tree {})"
--bind="ctrl-d:execute(rmd -l {})" # Run custom `rm -rf` script
--preview-window=hidden
--bind="ctrl-j:preview-page-down,ctrl-k:preview-page-up"
--preview-window=70%,border-double,top
--preview-label="[ ^L ^T ^I ^J ^K ]"
# Catppuccin Mocha theme
--color="fg:#b7bdf8,hl:#f4dbd6"
--color="fg+:#f4dbd6,bg+:#272935,hl+:#c6a0f6"
--color="info:#94e2d5,prompt:#f5c2e7,pointer:#f5a97f,marker:#94e2d5,spinner:#e28b83,header:#a6da95"
)
_UP_EXCLUDED_PATHS=(
"$HOME"
)
# Style Settings: Catppuccin Mocha theme
_UP_NO_STYLES=false
_UP_DIR_CHANGE_STYLE="\033[38;2;249;226;175m"
_UP_ERR_STYLE="\033[48;2;243;160;168m\033[38;2;30;30;46m"
_UP_PWD_STYLE="\033[38;2;166;227;161m"
_UP_OLDPWD_STYLE="\033[38;2;88;91;112m"
_UP_REGEX_STYLE="\033[38;2;116;199;236m"Environment variables are expanded automatically (e.g., $HOME becomes /home/user). Variables defined in the shell configuration take precedence over those in the configuration file, allowing flexibility.
$ up <optional: integer>$ pwd
/Volumes/WD_SSD_1TB/Pictures/wallpapers/apple
$ up
$ pwd
/Volumes/WD_SSD_1TB/Pictures/wallpapers$ up 3
$ pwd
/Volumes/WD_SSD_1TB$ up <tab>
/ Pictures/ Volumes/ WD_SSD_1TB/ wallpapers/To autocomplete the only directory that starts with Pic:
$ up Pic<tab>
$ up Pictures/-i/--ignore-case: Perform case-insensitive regex jumps with the-s,-e, and-rflags.-s/--starts-with: Jump to the nearest directory that starts with a given regex pattern.- Automatically prefixes your regex with
^for matching at the start.
- Automatically prefixes your regex with
-e/--ends-with: Jump to the nearest directory that ends with a given regex pattern.- Appends your regex with
$for matching at the end.
- Appends your regex with
-r/--regex: Jump to the nearest directory that matches any part of your regex.-x/--exact: Jump to an exact directory name match (default behavior).- Useful when
_UP_REGEX_DEFAULT=trueis exported for regex-based navigation by default.
- Useful when
Example: To jump to the closest directory containing SSD within /Volumes/WD_SSD_1TB/Pictures/wallpapers/apple:
$ up -r SSD
$ pwd
/Volumes/WD_SSD_1TBExample: To jump to the same location ignoring case:
$ up -i ssd
$ pwd
/Volumes/WD_SSD_1TBPrefer regex-based navigation every time without the need for explicit flags? Add the following line to .bashrc, .zshrc, or .zshenv:
export _UP_REGEX_DEFAULT=trueUse the -x flag for exact matches to temporarily disable this behavior.
$ pwd
/Volumes/WD_SSD_1TB/Pictures/wallpapers/apple
$ up -x Volumes
$ pwd
/VolumesSimplify your workflow by setting up aliases while preserving default behavior. Add to .bashrc or .zshrc:
alias u='up -i' # Jump to the nearest regex match, ignore case
alias m='up -m' # Open most frequently visited paths in `fzf`
alias recent='up -R 1d' # List paths accessed in the last dayCheck for conflicts using command -v <alias>.
Jump by fzf (Fuzzy Finder)
Use an optional interactive fuzzy finder to jump directories in your PWD, use the -f / --fzf flags.
$ up -f
$ up --fzfWhen eza is not installed, the default fzf options for listing ancestor paths of the current working directory are:
FZF_PWDOPTS_DEFAULT=(
--height=50%
--layout=reverse
--prompt=" Path: "
--header=" cd ^P"
--preview="tree -C {}"
--bind="ctrl-l:change-preview(ls --color=always -lAh {})"
--bind="ctrl-i:change-preview(echo '\`stat\` Information:'; stat {})"
--bind="ctrl-t:change-preview(tree -C {})"
--bind="ctrl-p:toggle-preview"
--bind="ctrl-j:preview-page-down,ctrl-k:preview-page-up"
--preview-window=70%,border-double,top
--preview-label="[ ^L ^T ^I ^J ^K ]"
)NOTE: The Nerd Fonts for icons might not render in this Markdown file.
If eza is installed, then the tree and ls respective equivalents are used for preview for icon support: eza --color=always --tree --icons {}, eza --color=always --icons -laah {}.
Default fzf keybinds:
Ctrl-P: Toggle previewCtrl-J/Ctrl-K: Preview PGUP/PGDNCtrl-T:treein previewCtrl-L:ls --color=always -lAhin previewCtrl-I:statinformation in preview
The line --layout=reverse will display fzf below the prompt line; --height=50% uses half of the available terminal emulator window.
To customize the display of fzf, export _UP_FZF_PWDOPTS within .bashrc, .zshrc, or .zshenv.
For example,
# Define an array of fzf options for PWD
_UP_FZF_PWDOPTS=(
--height=50%
--layout=reverse
--prompt="Select: "
--preview="ls -A {}"
--bind="ctrl-p:toggle-preview"
)
export _UP_FZF_PWDOPTSFor inspiration, check out this detailed fzf guide.
Just like the cd command, up will generally not output text upon successful execution.
To display extra information such as $OLDPWD and $PWD after calling up:
$ up -v [integer or directory name]
$ up --verbose [integer or directory name]$ up -v Pictures/
up: jumped 2 dirs to nearest: Pictures
old: /Volumes/WD_SSD_1TB/Pictures/wallpapers/apple
pwd: /Volumes/WD_SSD_1TB/Pictures$ up verbose 2
up: jumped 2 dirs
old: /Volumes/WD_SSD_1TB/Pictures/wallpapers/apple
pwd: /Volumes/WD_SSD_1TB/PicturesPrefer verbose mode every time without polluting your aliases? Add the following line to .bashrc, .zshrc, or .zshenv:
export _UP_ALWAYS_VERBOSE=trueFor the sake of completeness, navigating to your HOME and previous paths are included.
HOME is the only valid full path up allows; all other arguments must be a single directory name.
You don't have to be in a HOME directory for this to work.
$ pwd
/Volumes/WD_SSD_1TB/Pictures/wallpapers/apple
$ up ~
$ pwd
/home/mwallace
$ up -
$ pwd
/Volumes/WD_SSD_1TB/Pictures/wallpapers/appleDefine output styles to tailor how directory changes, errors, and other terminal messages appear. Setting environment variables allows you to enhance readability and match colors to your terminal theme.
Set ANSI escape sequences in your shell configuration file (i.e., .bashrc, .zshrc, or .zshenv) to avoid editing up.bash manually.
_UP_DIR_CHANGE_STYLEfor the number of parent directories jumped.- Default: Orange (
\033[0;33m)
- Default: Orange (
_UP_ERR_STYLEfor error messages.- Default: Red (
\033[0;31m)
- Default: Red (
_UP_OLDPWD_STYLEfor the previous directory.- Default: Light Gray (
\033[0;37m)
- Default: Light Gray (
_UP_PWD_STYLEfor your current working directory.- Default: Light Green (
\033[0;32m)
- Default: Light Green (
_UP_REGEX_STYLEfor regular expression patterns, e.g.,'^big_kahuna_.urger$'.- Default: Cyan (
\033[0;36m)
- Default: Cyan (
Default values represent standard ANSI colors, which work reliably across most terminal emulators.
Some terminal emulators may be flexible displaying basic colors and automatically match your preconfigured terminal theme, depending on the capabilities of your terminal emulator (e.g., WezTerm for advanced color support).
Refer to this GitHub Gist for more styling ideas.
If your terminal emulator supports the full RGB spectrum, you may define style variables using a mix-and-match of foreground (\033[38;2;<r>;<g>;<b>m) and background (\033[48;2;<r>;<g>;<b>m) colors.
# `up` style theme: based on Catppuccin Mocha
# REF: https://github.com/catppuccin/catppuccin
# NOTE: ANSI escape format
# Foreground = "\033[38;2;<r>;<g>;<b>m"
# Background = "\033[48;2;<r>;<g>;<b>m"
export _UP_DIR_CHANGE_STYLE="\033[38;2;249;226;175m" # Yellow
export _UP_ERR_STYLE="\033[48;2;243;160;168m\033[38;2;30;30;46m" # Red background, "Crust" foreground
export _UP_OLDPWD_STYLE="\033[38;2;88;91;112m" # "Surface2"
export _UP_PWD_STYLE="\033[38;2;166;227;161m" # Green
export _UP_REGEX_STYLE="\033[38;2;116;199;236m" # SapphireTo turn off styling and display plaintext only, add the following line to .bashrc, .zshrc, or .zshenv:
export _UP_NO_STYLES=trueTo track path history with up, add to .bashrc, .zshrc, or .zshenv:
export _UP_ENABLE_HIST=trueBy default, the path history file is located at ~/.cache/up_history.log with a maximum size (in lines) of 250.
Export the _UP_HISTFILE and _UP_HISTSIZE to your preferred path and maximum size in .bashrc, .zshrc, or .zshenv.
export _UP_HISTFILE="$XDG_CACHE_HOME/up/up_path_history.log"
export _UP_HISTSIZE=1000Exclude paths from history logging with the _UP_EXCLUDED_PATHS environent variable in .bashrc, .zshrc, or .zshenv:
_UP_EXCLUDED_PATHS=(
"$HOME"
"$HOME/.Trash"
"$HOME/.ssh"
"/tmp"
"/var/log"
)
export _UP_EXCLUDED_PATHSWhile the history file is ordered by oldest to newest, path histories are indexed by most recent.
$ up -l
$ up --list-histTo show the list of most frequently visited paths, use -L, --list-freq flags:
$ up -L
$ up --list-freqTo jump to an index, use the -j / --jump-hist flags:
$ up -j 34 # jump to the 34th most recent tracked pathDisplay the size of the history with -S / --size:
$ up --size
up: history size: [=================...] 88% (221/250)Clear history entries with -c / --clear and passing a timeframe argument in the form <integer>(min|h|d|m), where min represents minutes, h for hours, d for days, and m for months.
For example, to remove history entries older than 5 days:
$ up --clear 5d
up: cleared 31 history entries older than 5d: /home/mrpink/.cache/up_history.logTo clear all history, pass no timeframe argument:
$ up -c
up: history file cleared: /home/mrpink/.cache/up_history.logUse the verbose flag (-v) before -c / --clear to display and confirm the removed paths.
$ up -vc 12h
Removing 14 Entries:
2025-04-13 22:58:09 /home/dietpi
2025-04-13 23:34:30 /home/dietpi/.cache
2025-04-13 23:36:25 /home/dietpi
2025-04-14 01:51:14 /home/dietpi/.local
2025-04-14 01:51:19 /home/dietpi/.local/share
2025-04-14 01:51:24 /home/dietpi/.local/share/bin
2025-04-14 01:51:36 /home/dietpi
2025-04-14 01:52:39 /home/dietpi/bin
2025-04-14 01:54:11 /home/dietpi
2025-04-14 01:59:55 /home/dietpi/.local/share/bin
2025-04-14 02:00:06 /home/dietpi/.local/share/bin/.fzf
2025-04-14 02:00:14 /home/dietpi/.local/share/bin/.fzf/bin
2025-04-14 02:00:38 /home/dietpi
2025-04-14 02:07:08 /home/dietpi/.config
2025-04-14 02:07:15 /home/dietpi
Confirm clear of path history entries older than 12h (Y/n): y
up: cleared 14 history entries older than 12h: /home/dietpi/.cache/up_history.logPrune missing paths in history file with -p / --prune-hist:
$ up --prune-hist
up: pruned history: removed 28 invalid paths (24 remaining, max: 250)$ up -F
$ up --fzf-histTo filter by most recent paths, use -R, --fzf-recent flags passing <integer>[min|h|d|m] argument:
$ up -R # Paths accessed in the last hour
$ up --fzf-recent 15min # Paths accessed in the last 15 minutes
$ up -R 5h # Paths accessed in the last 5 hours
$ up -R 2d # Paths accessed in the last 2 days
$ up -R 1m # Paths accessed in the last monthTo filter by the most frequently visited paths, use -m, --fzf-freq flags:
$ up -m
$ up --fzf-freqWhen eza is not installed, the default fzf options for listing historic paths are:
FZF_HISTOPTS_DEFAULT=(
--height=50%
--layout=reverse
--prompt=" Path: "
--header=" cd ^P Missing Paths Omitted"
--preview-window=hidden
--preview="tree -C {}"
--bind="ctrl-l:change-preview(ls --color=always -lAh {})"
--bind="ctrl-t:change-preview(tree -C {})"
--bind="ctrl-i:change-preview(echo '\`stat\` Information:'; stat {})"
--bind="ctrl-p:toggle-preview"
--bind="ctrl-j:preview-page-down,ctrl-k:preview-page-up"
--preview-window=70%,border-double,top
--preview-label="[ ^L ^T ^I ^J ^K ]"
)The preview window is hidden by default; Ctrl-P to toggle the preview window.
In the header, "Missing Paths Omitted" denotes non-jumpable paths in history are skipped.
To customize the display of fzf, export _UP_FZF_HISTOPTS within .bashrc, .zshrc, or .zshenv.
# Example: Define array-based fzf options w/ `ls -A` preview
_UP_FZF_HISTOPTS=(
--height=50%
--layout=reverse
--prompt="Select: "
--preview="ls -A {}"
--bind="ctrl-p:toggle-preview"
)
export _UP_FZF_HISTOPTSTo access the following wrapper functions, set the _UP_ENABLE_HIST environment variable within .bashrc, .zshrc, or .zshenv:
export _UP_ENABLE_HIST=trueBy default, up only tracks its own path history when _UP_ENABLE_HIST=true is exported.
To capture and track global path histories, use the up_passthru helper function by adding aliases to .bashrc and .zshrc.
# up: Global history logging
alias cd='up_passthru cd' # cd: Use `builtin cd -- <path>` to a skip logging
alias z='up_passthru z' # zoxideph is a wrapper for up that focuses on path history navigation.
If you are tracking path history of cd, zoxide, jump, etc., using up_passthru, this is a more intuitive interface.




