13

In the cd, bash help page:

The variable CDPATH defines the search path for the directory containing
DIR.  Alternative directory names in CDPATH are separated by a colon (:).
A null directory name is the same as the current directory.  If DIR begins
with a slash (/), then CDPATH is not used.

But I don't understand the concept of "Alternative directory", and can't find an example that illustrates the use of the colon (:) with the cd command.

25

The variable is not set by default (at least in the systems I am familiar with) but can be set to use a different directory to search for the target dir you gave cd. This is probably easier to illustrate with an example:

$ echo $CDPATH    ## CDPATH is not set

$ cd etc          ## fails: there is no "etc" directory here
bash: cd: etc: No such file or directory
$ CDPATH="/"      ##CDPATH is now set to /
$ cd etc          ## This now moves us to /etc
/etc

In other words, the default behavior for cd foo is "move into the directory named 'foo' which is a subdirectory of the current directory or of any other directory that is given in CDPATH". When CDPATH is not set, cd will only look in the current directory but, when it is set, it will also look for a match in any of the directories you set it to.

The colon is not used with cd, it is used to separate the directories you want to set in CDPATH:

CDPATH="/path/to/dir1:/path/to/dir2:/path/to/dirN"
  • "but, when it is set, it will also look" -- Are you sure you meant to say "also"? With that word, I interpret what you say to mean that it only tries the paths in $CDPATH after it fails to find the directory from the current working directory. However, when I do mkdir -p a/b b; CDPATH=a; cd b it took me to a/b instead of b, contrary to what you said. – JoL Aug 10 '20 at 16:25
  • 1
    @JoL when you add something to the CDPATH variable, then cd will search there first. But it will still look in your current directory if it doesn't find anything in the CDPATH dir. That's what I meant by also: the directory you give in CDPATH doesn't replace the current directory, it is just one more place where cd will now search. That's why cd a will still work in your example, even though there is no a sub-dir in a. – terdon Aug 10 '20 at 16:28
  • @JoL: because of what you just showed, I believe it is probably a good idea to add "." in the beginning of CDPATH (e.g. export CDPATH=".:/path/to/one:/path/to/two"). That way you get your expected behavior (start looking in my own current folder first, then if that fails, search in the rest). – ttsiodras Aug 12 '20 at 12:53
  • @ttsiodras sure, if that's what you want, but I don't know that this is the "expected" behavior if you are using CDPATH. But yes, if you always want the PWD to be searched first, that's the way to do it. (PS. I had to look at your profile to be sure I wasn't addressing Σωτήρης Τσιόδρας, your last name is very famous in our shared country these days! :P) – terdon Aug 12 '20 at 13:17
  • @terdon You were addressing his youngest brother :-) And yes, he is a magnificent fellow - our country is very lucky to have him. – ttsiodras Aug 12 '20 at 13:46
7

In the manual, CDPATH is described this way:

The search path for the cd command. This is a colon-separated list of directories in which the shell looks for destination directories specified by the cd command. A sample value is ".:~:/usr".

For completeness, here is some experiment similar to terdon's.

$~> mkdir /tmp/2 ./2 ./3
$~> cd 2
$~/2> cd ..
$~> CDPATH=/tmp
$~> cd 2
/tmp/2
$~> cd ~
$~> cd 3
$~/3> 

As you can see, after setting CDPATH=/tmp, Bash looks in /tmp first for possible target directories. If not found in /tmp, it tries looking in the current directory. We could also note that (Shell Builtins)

If a non-empty directory name from CDPATH is used, or if - is the first argument, and the directory change is successful, the absolute pathname of the new working directory is written to the standard output.

I also want to share this:

$~> CDPATH=.:/tmp
$~> cd 2
/home/myuser/2
$~/2> cd 2
/tmp/2

In this continuation, CDPATH has been given two directories. The first is ., i.e., the current directory. Since it comes first, upon trying cd 2, we go to the /home/myuser/2, although /tmp/2 also exists. It is like $PATH, the first listed directories take precedence.

1

The other answers explain the basic use of CDPATH, but I think a particular use case is illustrative. Often, I find I want to do an operation repeatedly inside a series of subdirectories, starting from the same root.

cd ~/wrk
for d in */.git/hooks/; do
  ( cd "$d" && mv pre-commit pre-commit.off )
done

The subshell is necessary so that each iteration starts from the same root. Or is it? Can we avoid repeating subshells here? Yes, we can!

cd ~/wrk &&
CDPATH=$PWD
for d in */.git/hooks; do
  cd "$d" && mv pre-commit pre-commit.off
done

This has the added advantage that cd will tell us where we are at each step.

So what about the alternative directory names? I think Quasimodo's example is particularly good. If . is not in your CDPATH, then your CDPATH takes precedence. But if you want to be sure that the directories right in front of you take precedence, your CDPATH should start with ..

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.