What I want to accomplish is: jump to a directory and list its content.

The function bash function I've added in .bash_aliases is:

function zl(){
  z $1 && ls

however, when invoke this function, i get the following error:

❯ zl node
z: command not found

But the z command works perfectly when I use it alone.

Why can't I use the z command inside the function?

Fixes I've tried:

  1. adding source /home/me/z.sh to the function
function zl(){
  source /home/nair/z.sh
  z $1 && ls

edit: z is a jump around command

1 Answer 1


According to the source of that z, it's meant to be an alias. Aliases are a bit like C preprocessor macros, they're not command or functions. They're from the C shell which doesn't have functions, and don't really belong in Bourne-like shells, but people keep using them mainly because csh was a very popular shell for a long time.

Aliases are expanded at the time they're read, not at the time they're executed (if executing an alias even made sense). So in functions, they are expanded into the body of the function at the time the body of the function is read, so here you'd need the alias to have been already defined by the time the function definition is read by the shell, so you need to make sure your function definition comes after the line that does . /path/to/z.sh or source /path/to/z.sh in your ~/.bashrc and make sure both statements are read and executed one after the other (are not part of the same compound command for instance).

Alternatively, since that alias is defined as:

alias ${_Z_CMD:-z}='_z 2>&1'

(note the missing quotes around the parameter expansion, a mistake you too made), you could write your function as:

  _z "$@" && ls

(add the 2>&1 if you do want stderr to be merged into stdout)

With "$@" we pass all the arguments zl receives along to _z, not just the first, let alone the first after being subjected to split+glob as you did by leaving that $1 unquoted.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .