zsh
is one of the few shells (the other ones being tcsh
(which
originated as a csh
script for csh
users, which also had its limitation, tcsh
made it a builtin as an improvement)) where which
does something sensible since it's a shell builtin, but somehow you or your OS (via some rc
file) broke it by replacing it with a call to the system which
command which can't do anything sensible reliably since it doesn't have access to the interns of the shell so can't know how that shell interprets a command name.
In zsh, all of which
, type
, whence
and where
are builtin commands that are all used to find out about what commands are, but with different outputs. They're all there for historical reason, you can get all of their behaviours with different flags to the whence
command.
You can get the details of what each does by running:
info -f zsh --index-search=which
Or type info zsh
, then bring up the index with i
, and enter the builtin name (completion is available).
And avoid using /usr/bin/which
. There's no shell nowadays where that which
is needed. As Timothy says, use the builtin that your shell provides for that. Most POSIX shells will have the type
command, and you can use command -v
to only get the path of a command (though both type
and command -v
are optional in POSIX (but not Unix, and not any longer in LSB), they are available in most if not all the Bourne-like shells you're likely to ever come across).
(BTW, it looks like /usr/bin
appears twice in your $PATH
, you could add a typeset -U path
to your ~/.zshrc
)
Yes, your interpretation is correct (from skimming your long question).
Parameter expansion flags apply to parameter expansions. When you want it applied to any arbitrary string instead, you need to either store that string in a variable as in:
var=%1N
filename=${(%)var}
Or (as a hack) you can use the ${var:-string}
parameter expansion and leave the var
part empty: ${(%):-%1N}
. That's a common trick(see 1
2
3
4
5
6
7
8
9
10
11
12
13 here for instance), though that makes for pretty illegible code. Alternatively, you could use the ${param+string}
syntax and use a parameter like $-
or $0
or $#
that is always set (${(%)-+%1N}
). That's neither shorter nor more legible though.
Here, you can also use print -P %1N
Best Answer
oh-my-zsh
enable two things, which cause this behavior:cd
to that directorycd
command (or an implied cd with theAUTO_CD
option set) is not a directory, and does not begin with a slash, try to expand the expression as if it were preceded by a~
In your case, when typing
HOME
,AUTO_CD
madezsh
performedcd HOME
,CDABLE_VARS
madezsh
performedcd ~HOME
,~HOME
was expanded to your home directory.You can call
zsh
with--xtrace
option to see what happened: