0

I'm just curious, when I'm using the cd command in bash, commands

cd foobar

and

cd ./foobar

work in the same way. I understand, that ./ refers to the current catalogue directory, but why then does "cd foobar" work? Is it just default, that when I'm not writing ./ on the beginning, program adds it on its own, or is it more complicated?

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
user3387666
  • 237
  • 1
  • 3
  • 9
  • 3
    I'm not sure that this is legitimately a question about software development as opposed to user-level semantics. Consider SuperUser or http://unix.stackexchange.com/ for this kind of thing in the future. – Charles Duffy Jan 25 '16 at 17:06
  • You might want to take a look at this question: [source code for unix environments 'cd' command](http://stackoverflow.com/questions/881560/source-code-for-unix-environments-cd-command) – Rany Albeg Wein Jan 25 '16 at 17:15
  • It seems to me to be a perfectly legitimate question for SO. It should be considered as 'and what would I need to do to implement it' or thereabouts. – Jonathan Leffler Jan 25 '16 at 17:21
  • If the real question is what one needs to do to implement their own shell, asking about bash as opposed to about the baseline POSIX specification's requirements is making a great deal of extra work for oneself. – Charles Duffy Jan 25 '16 at 17:26

2 Answers2

9

The cd command in bash (somewhat indirectly, as described below) invokes the chdir() syscall, behavior of which is specified by POSIX. The cd shell comand itself also has a POSIX specification for its behavior, in perhaps more detail than is appropriate for an accessible/readable definition.

Yes, the default for all operations (not only chdir() but also fopen() and others) is the current working directory.

This isn't specific to bash, but is operating-system-level behavior: "Current working directory" is part of the metadata about each process tracked by the kernel, and impacts filesystem-level requests made to the kernel: Any program, in any language, can call chdir("foo") or open("foo", O_RDONLY), and behavior will be to look for foo in the current directory, as inherited from the parent process or modified with prior chdir() calls.


That said, for the purposes of bash, cd ./foo is more specific than merely cd foo: The former says that you explicitly want the foo subdirectory of the current working directory. In bash, if the CDPATH shell variable is set, then cd foo will look in all directories listed in it, whereas cd ./foo explicitly only asks for foo under the current working directory.

Try this experiment:

# setup
tempdir=$(mkdir -d "${TMPDIR:-/tmp}/cdpath-test.XXXXXX")
mkdir -p "$tmpdir/i-am-a-test-directory"
CDPATH=".:$tempdir"

# this works, because CDPATH is honored
cd /
cd i-am-a-test-directory

# this does not, because you're explicitly asking for a directory that does not exist
cd /
cd ./i-am-a-test-directory

# cleanup
rm -rf "$tempdir"
unset CDPATH
Charles Duffy
  • 280,126
  • 43
  • 390
  • 441
2

Ignoring the CDPATH environment variable for the time being, the name after cd is a directory path name. There are only two sorts of path name in Unix:

  • absolute names that begin with a /
  • relative names which don't start with a /

All relative names are treated by the kernel as relative to the current directory — as if the name was prefixed by ./.

If you have CDPATH set, it complicates the search, and it is then conceivable that cd somewhere and cd ./somewhere land you in different directories. A directory name with no leading / and with no leading . or .. component (where cd .hidden doesn't count — the leading component is .hidden— but cd ./visible or cd ../visible do count) is searched for using CDPATH.

For example, consider this tree structure (only directories shown):

.                - current directory
./somewhere
./src
./src/somewhere

Suppose you have CDPATH=src:. Then cd somewhere will go to ./src/somewhere and cd ./somewhere will go (unsurprisingly) to ./somewhere. If you type a name such as cd src/somewhere, the cd command will search for a sub-directory /xyz/pqr/src/somewhere for each directory /xyz/pqr on CDPATH in turn. I perpetually use CDPATH (7 directories on my own machines; 14 on my work machines).

  • Rule of thumb: use CDPATH=:…whatever…

That puts the current directory first on the search path, and is usually the most sane behaviour.

A similar story applies to searching for ordinary external (non-aliased, non-function, non-builtin) commands. Command names that start with a slash are absolute pathnames; command names containing a slash are relative to the current directory; command names without a slash are searched for on $PATH.

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278