12

Maybe I'm missing it, but I don't find it documented that cd '' should succeed. Since there is no directory with the name '', it seems obvious that it should fail. For example,

mydir=
cd -- "$mydir" || exit 1     # succeeds!!
echo wrong

Seems like a bug in about a million scripts, just waiting to happen. Is this some sort of backwards-compatible-bug kind of thing? Do I really have to do a separate check for an empty variable name every time I cd? FWIW, shellcheck doesn't catch this, either.

7
  • 1
    I cannot answer this but would like to add that this happens (in bash) only with cd -L (the default) but not with cd -P. Commented 2 days ago
  • @HaukeLaging I guess that's the solution for my scripting then. Just gotta retrain myself to use cd -P all the time.
    – jrw32982
    Commented 2 days ago
  • Seems to be legitimate behaviour: stackoverflow.com/a/42893829/2072269
    – muru
    Commented 2 days ago
  • @muru Thanks for that pointer. But doesn't sound legitimate to me, especially seeing as the behavior is inconsistent. As with so many things, it sounds like the answer is "because". And sounds like, for bash, the solution is "always use cd -P". Just another gotcha to file away.
    – jrw32982
    Commented 2 days ago
  • 1
    If you're in e.g. /tmp, running cd foo in Bash 5.2 calls chdir("/tmp/foo"), i.e. it determines the full path itself; while with cd -P foo, it just calls chdir("foo") and lets the OS resolve it. (it does try to readlink() the path components first, though.) Probably has something to do with how it handles cd .., removing one path component from PWD, regardless of if it was a symlink and the filesystem .. would actually be elsewhere. So cd "" might just append the empty string to the current directory and then try to resolve any ..s. Ending up with just the current dir.
    – ilkkachu
    Commented yesterday

1 Answer 1

26

The most recent POSIX specification for the cd utility (Issue 8, from 2024) has this in the OPERANDS section:

[...] If directory is an empty string, cd shall write a diagnostic message to standard error and exit with non-zero status. [...]

However, at the time of writing (2025), this is a fairly recent addition, and the previous issue of the standard said that it was "unspecified" what an empty operand would cause the utility to do, leaving it up to the implementors of the standard to provide a useful consistent behaviour.

All shells I use daily (bash, zsh, OpenBSD ksh, ash) treat cd '' as cd . (or the first reachable directory in $CDPATH if set), while the (very much non-POSIX) rc (and derivatives) and fish shell generate an error for cd ''.

The cd of csh/tcsh reports an error unless $cdpath in set in which case like on those shells mentioned above for $CDPATH, it chdir()s to the first reachable directory in that array.

If these shells aspire to be POSIX compliant (some do, others don't, but tend to align the general behaviour of built-in standard utilities to the common standard), I'm sure they will be updated over time to conform to the new specification.

In fact, the most recent development version of bash does this:

bash-5.3$ mydir=
bash-5.3$ cd "$mydir"
bash: cd: null directory
bash-5.3$ echo "$?"
1
bash-5.3$ echo "$BASH_VERSION"
5.3.0(1)-rc1

In the meantime, if this is important to your own scripts, you should test the value of the shell variable used as the operand to cd. A minimal thing to do could be to use something like cd "${mydir:?Empty or unset variable}" in your script:

$ mydir=
$ cd "${mydir:?Empty or unset variable}"
bash: mydir: Empty or unset variable
$ echo "$?"
1

... or do a separate sanity check on the variable before its use.

8
  • 2
    Kind of weird that, when updating a formal standard, what seems to be the de-facto standard is then rejected rather than adopted or accepted as it was. Personally, the empty string being the same as the current directory makes sense to me. Having to do cd ${dir:-.} or [[ $dir ]] && cd $dir seems needlessly verbose to encode that the directory you change into should default to the current dir.
    – JoL
    Commented yesterday
  • 3
    @JoL While I agree with you, and I guess it was the same reasoning that the maintainers of the different shell had in the absence of POSIX specification on that point, there is a point in "whatever you did to end up cding on an empty directory is wrong" probably made more sense for whoever is creating the POSIX specification
    – DrakaSAN
    Commented yesterday
  • 1
    @JoL The change was proposed and debated here: austingroupbugs.net/view.php?id=1047
    – Kusalananda
    Commented yesterday
  • 4
    @JoL for what it's worth, I would have expected cd "" to take me to ~/, that is to act like cd with no arguments. Maybe others also felt this way so the de facto "standard" was changed because it was a surprising behavior?
    – terdon
    Commented yesterday
  • 2
    Yes, that's a fair point, @JoL. But nevertheless, I am an example here: I had never encountered this before, and when I read the question title, I was expecting the answers to explain that cd '' "works" because it is moving you to your ~/. Now, if I had thought about it a little bit more, I would probably have realized the very good point you made above, but I hadn't, so I was surprised. I am just thinking that part of why they chose to error out instead of having it behave like cd . is for folks who might have the same misconception I did.
    – terdon
    Commented yesterday

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.