whi 0.1.0

Magically simple PATH management - improved which with PATH manipulation
whi-0.1.0 is not a library.
Visit the last successful build: whi-0.8.1

whi

Stupid simple PATH management

whi is a powerful which replacement with PATH manipulation. Find executables, see all matches, and reorder your PATH with simple shell commands.

Features

  • Better than which: Shows winner by default, all matches with -a
  • PATH manipulation: Move, swap, and prefer executables with shell integration
  • Winner indication: Clearly marks which executable would actually run with color
  • PATH indices (-i): Shows the PATH index for each match
  • Full PATH listing (-f): Displays complete PATH with indices
  • Follow symlinks (-l): Resolves and shows canonical targets
  • File metadata (-s): Shows inode, device, size, and modification time
  • Combinable flags: Unix-style flag combining (e.g., -ais, -ifl)
  • Pipe-friendly: Quiet by default, all output to stdout
  • Zero dependencies: Only libc for isatty(3)

Installation

cargo install whi

Or build from source:

git clone https://github.com/alexykn/whi
cd whi
cargo build --release

Quick Start

Shell Integration (Recommended)

whi provides shell integration that gives you commands to manipulate your PATH directly in your current shell session. Without shell integration, whi --move and similar commands would only output a new PATH string - they can't modify your actual shell's PATH variable.

To enable shell integration, add this to your shell config:

Bash (~/.bashrc):

eval "$(whi init bash)"

Zsh (~/.zshrc):

eval "$(whi init zsh)"

Fish (~/.config/fish/config.fish):

whi init fish | source

The whi init <shell> command outputs shell-specific functions that you can evaluate/source. This provides five powerful commands:

  • whim FROM TO - Move PATH entry from index FROM to index TO

    $ whim 10 1      # Move entry at index 10 to position 1
    
  • whis IDX1 IDX2 - Swap two PATH entries

    $ whis 10 41     # Swap entries at indices 10 and 41
    
  • whip NAME INDEX - Make executable at INDEX win (prefer it over others)

    $ whip cargo 50  # Make cargo at index 50 the winner
    
  • whia NAME - Show all matches with indices (shortcut for whi -ia)

    $ whia cargo     # Equivalent to: whi -ia cargo
    
  • whii [NAME] - Show PATH entries or matches with indices (shortcut for whi -i)

    $ whii           # Show all PATH entries with indices
    $ whii cargo     # Show cargo matches with indices
    

These commands actually modify your current shell's PATH environment variable, so changes take effect immediately without restarting your shell or sourcing config files

Basic Usage

View all PATH entries (with or without indices):

$ whi
/Users/user/.rustup/toolchains/stable-aarch64-apple-darwin/bin
/opt/homebrew/bin
/usr/local/bin
/usr/bin
...

$ whi -i    # Or use the whii shortcut
[1] /Users/user/.rustup/toolchains/stable-aarch64-apple-darwin/bin
[2] /opt/homebrew/bin
[3] /usr/local/bin
[4] /usr/bin
...

Find an executable (like which) - shows only the winner:

$ whi cargo
/Users/user/.rustup/toolchains/stable-aarch64-apple-darwin/bin/cargo

See all matches with -a:

$ whi -a cargo
/Users/user/.rustup/toolchains/stable-aarch64-apple-darwin/bin/cargo
/opt/homebrew/bin/cargo
/Users/user/.cargo/bin/cargo

With PATH indices using -i (or use whia cargo shortcut):

$ whi -ai cargo
[1] /Users/user/.rustup/toolchains/stable-aarch64-apple-darwin/bin/cargo
[2] /opt/homebrew/bin/cargo
[5] /Users/user/.cargo/bin/cargo

Follow symlinks with -l to see what they point to:

$ whi -ail cargo
[1] /Users/user/.rustup/toolchains/stable-aarch64-apple-darwin/bin/cargo
[2] /opt/homebrew/bin/cargo → /opt/homebrew/Cellar/rustup/1.28.2/bin/rustup-init
[5] /Users/user/.cargo/bin/cargo → /Users/user/.cargo/bin/rustup

Show detailed metadata with -s:

$ whi -as cargo
/Users/user/.rustup/toolchains/stable-aarch64-apple-darwin/bin/cargo
  inode: 152583153, device: 16777233, size: 30854216 bytes
  created:  2025-09-27 10:30:17
  modified: 2025-09-27 10:30:17
/opt/homebrew/bin/cargo
  inode: 103789726, device: 16777233, size: 11154288 bytes
  created:  2025-04-28 15:56:34
  modified: 2025-04-28 15:56:34
/Users/user/.cargo/bin/cargo
  inode: 117539552, device: 16777233, size: 11174016 bytes
  created:  2025-09-03 07:12:56
  modified: 2025-09-03 07:12:56

Combine flags for all matches with indices and symlinks:

$ whi -ail python
[3] /usr/local/bin/python → /usr/local/Cellar/python@3.11/3.11.5/bin/python3.11
[8] /usr/bin/python
[12] /opt/homebrew/bin/python → /opt/homebrew/Cellar/python@3.12/3.12.0/bin/python3.12

PATH Manipulation Examples

See which cargo is winning and make a different one win:

$ whia cargo
[1] /Users/user/.rustup/toolchains/stable-aarch64-apple-darwin/bin/cargo
[2] /opt/homebrew/bin/cargo
[5] /Users/user/.cargo/bin/cargo

$ whip cargo 5    # Make cargo at index 5 the winner
$ whia cargo
[1] /Users/user/.cargo/bin/cargo
[2] /Users/user/.rustup/toolchains/stable-aarch64-apple-darwin/bin/cargo
[3] /opt/homebrew/bin/cargo

Move PATH entries to reorder them:

$ whim 10 1      # Move entry at index 10 to position 1
$ whim 50 3      # Move entry at index 50 to position 3

Swap two PATH entries:

$ whis 10 41     # Swap entries at indices 10 and 41

Other Usage Examples

Read multiple names from stdin:

$ echo -e "python\\nnode\\ncargo" | whi
/usr/bin/python
/usr/local/bin/node
/Users/user/.cargo/bin/cargo

Check multiple executables at once:

$ whi python node cargo gcc
/usr/bin/python
/usr/local/bin/node
/Users/user/.cargo/bin/cargo
/usr/bin/gcc

Show all PATH entries (with or without indices):

$ whi          # Plain listing
/Users/user/.rustup/toolchains/stable-aarch64-apple-darwin/bin
/opt/homebrew/bin
/usr/local/bin
/usr/bin
...

$ whi -i       # With indices
[1] /Users/user/.rustup/toolchains/stable-aarch64-apple-darwin/bin
[2] /opt/homebrew/bin
[3] /usr/local/bin
[4] /usr/bin
...

Use custom PATH:

$ whi --path="/usr/local/bin:/usr/bin" python
/usr/local/bin/python

Command-Line Options

Flags

Short flags can be combined Unix-style (e.g., -ai = -a -i, -ais = -a -i -s).

  • -a, --all - Show all PATH matches (default: only winner)
  • -f, --full - Show all matches + full PATH listing (implies -a; directories with matches highlighted in color)
  • -i, --index - Show PATH index next to each entry
  • -l, -L, --follow-symlinks - Resolve and show canonical targets
  • -o, --one - Only print the first match per name
  • -s, --stat - Include inode/device/mtime/size metadata
  • -0, --print0 - NUL-separated output for use with xargs
  • -q, --quiet - Suppress non-fatal stderr warnings
  • --silent - Print nothing to stderr, use exit codes only
  • --show-nonexec - Also list files that exist but aren't executable
  • -h, --help - Print help information

PATH Manipulation

These commands output a modified PATH string to stdout. Use shell integration (see above) to actually modify your current shell's PATH.

  • --move <FROM> <TO> - Move PATH entry from index FROM to index TO

    $ whi --move 10 1
    /path/at/10:/path/at/1:/path/at/2:...
    
  • --swap <IDX1> <IDX2> - Swap PATH entries at indices IDX1 and IDX2

    $ whi --swap 10 41
    /modified/path/string/...
    
  • --prefer <NAME> <INDEX> - Make executable NAME at INDEX win

    $ whi --prefer cargo 50
    /modified/path/string/...
    

Other Options

  • --path <PATH> - Override environment PATH string

    $ whi --path="/usr/local/bin:/usr/bin" python
    
  • --color <WHEN> - Colorize output: auto, never, always [default: auto]

    $ whi --color=always cargo
    

Shell Integration Command

  • whi init <SHELL> - Output shell integration code for bash, zsh, or fish
    $ whi init bash    # Output bash functions
    $ whi init zsh     # Output zsh functions
    $ whi init fish    # Output fish functions
    

Exit Codes

  • 0 - All names found
  • 1 - At least one not found
  • 2 - Usage error
  • 3 - I/O or environment error

Examples

Find all versions of Python in PATH:

$ whi -a python python3 python3.11

Check which node would run with indices:

$ whi -i node

Use with xargs to check executables:

$ whi -0 python node cargo | xargs -0 -n1 file

Find all versions with metadata:

$ whi -ais gcc

Show all PATH entries with indices:

$ whi -i       # Or use whii shortcut
[1] /usr/local/bin
[2] /usr/bin
[3] /bin
...

Comparison with which

Feature which whi
Show first match ✓ (default)
Show all matches Some versions with -a ✓ With -a
Show PATH indices ✓ With -i
Full PATH listing ✓ With -f
Follow symlinks Some versions ✓ With -l/-L
File metadata ✓ With -s
PATH manipulation ✓ With shell integration
Combinable flags
Multiple names
Stdin input
Pipe-friendly Varies

Why?

Ever wonder:

  • Which version of python or node is actually running?
  • How to make a different version win without editing shell configs?
  • What other versions exist on your PATH?
  • What's the actual order of your PATH directories?

whi answers all these questions and lets you manipulate your PATH on the fly with simple shell commands.

License

MIT

Author

Alexander Knott alexander.knott@posteo.de