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
-r
for general matches,-s
for "starts with,"-e
for "ends with," or-x
for exact matches. - Combine with
-i
for case-insensitivity or export_UP_REGEX_DEFAULT=true
for default regex behavior.
- Use
-
Verbose Feedback
- View directory change details with
-v
or 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/up
Add 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` completion
Assuming 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' >> ~/.bashrc
Download the git repo to your preferred destination. For example:
git clone https://github.com/LittleWalter/up ~/.local/share/shell/up
These 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` completion
Assuming 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' >> ~/.zshrc
The 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 script
After installation, verify that the man page is available by running:
man up
Following 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.conf
The 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-r
flags.-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=true
is 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_1TB
Example: To jump to the same location ignoring case:
$ up -i ssd
$ pwd
/Volumes/WD_SSD_1TB
Prefer regex-based navigation every time without the need for explicit flags? Add the following line to .bashrc
, .zshrc
, or .zshenv
:
export _UP_REGEX_DEFAULT=true
Use the -x
flag for exact matches to temporarily disable this behavior.
$ pwd
/Volumes/WD_SSD_1TB/Pictures/wallpapers/apple
$ up -x Volumes
$ pwd
/Volumes
Simplify 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 day
Check 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 --fzf
When 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
:tree
in previewCtrl-L
:ls --color=always -lAh
in previewCtrl-I
:stat
information 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_PWDOPTS
For 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/Pictures
Prefer verbose mode every time without polluting your aliases? Add the following line to .bashrc
, .zshrc
, or .zshenv
:
export _UP_ALWAYS_VERBOSE=true
For 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/apple
Define 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_STYLE
for the number of parent directories jumped.- Default: Orange (
\033[0;33m
)
- Default: Orange (
_UP_ERR_STYLE
for error messages.- Default: Red (
\033[0;31m
)
- Default: Red (
_UP_OLDPWD_STYLE
for the previous directory.- Default: Light Gray (
\033[0;37m
)
- Default: Light Gray (
_UP_PWD_STYLE
for your current working directory.- Default: Light Green (
\033[0;32m
)
- Default: Light Green (
_UP_REGEX_STYLE
for 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" # Sapphire
To turn off styling and display plaintext only, add the following line to .bashrc
, .zshrc
, or .zshenv
:
export _UP_NO_STYLES=true
To track path history with up
, add to .bashrc
, .zshrc
, or .zshenv
:
export _UP_ENABLE_HIST=true
By 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=1000
Exclude 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_PATHS
While the history file is ordered by oldest to newest, path histories are indexed by most recent.
$ up -l
$ up --list-hist
To show the list of most frequently visited paths, use -L
, --list-freq
flags:
$ up -L
$ up --list-freq
To jump to an index, use the -j
/ --jump-hist
flags:
$ up -j 34 # jump to the 34th most recent tracked path
Display 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.log
To clear all history, pass no timeframe argument:
$ up -c
up: history file cleared: /home/mrpink/.cache/up_history.log
Use 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.log
Prune 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-hist
To 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 month
To filter by the most frequently visited paths, use -m
, --fzf-freq
flags:
$ up -m
$ up --fzf-freq
When 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_HISTOPTS
To access the following wrapper functions, set the _UP_ENABLE_HIST
environment variable within .bashrc
, .zshrc
, or .zshenv
:
export _UP_ENABLE_HIST=true
By 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' # zoxide
ph
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.