How to Make the z Alias Work in Non-Interactive Bash Shells

3 min read.

If you use zoxide and notice the z alias is missing in non-interactive bash shells — cron jobs, CI scripts, or subshells spawned by tools — this is why and how to fix it.

Why z doesn't work in non-interactive bash shells

When you run eval "$(zoxide init bash)" in your ~/.zshrc or ~/.bashrc, it defines the z shell function for interactive sessions. But non-interactive bash shells (launched with bash -c ... or by tools internally) don't source those files. They skip .bashrc entirely.

So z is simply never defined, and you get command not found.

The fix: BASH_ENV

Bash has one hook for non-interactive shells: the BASH_ENV environment variable. Before running any commands, bash reads and sources the file pointed to by $BASH_ENV — no flags needed, no special config.

Create a minimal env file:

echo 'export _ZO_DOCTOR=0' > ~/.bash_env
echo 'eval "$(zoxide init bash)"' >> ~/.bash_env

_ZO_DOCTOR=0 suppresses the warning zoxide prints when it detects a non-interactive shell. It must come before the eval.

Then export BASH_ENV from your shell so it's inherited by every subprocess:

echo 'export BASH_ENV="$HOME/.bash_env"' >> ~/.zshrc
source ~/.zshrc

That's it. Any bash subshell spawned from your terminal session will now have z available.

Verify it

cd /tmp && z your-project && pwd

No warnings, navigates correctly.

Why not just add it to ~/.bashrc?

Non-interactive bash shells don't source ~/.bashrc. That file is only read by interactive non-login bash shells. BASH_ENV is the only official hook bash provides for non-interactive shells.

Keep ~/.bash_env minimal — only what you actually need in non-interactive contexts. Don't dump your full shell config there; it runs on every bash invocation.

Latest Posts