Linux – Why Does the cd Command Handle STDIN Differently?

linuxshellstdin

Commands like cd cannot have output piped to them in order to change directories–they require command-line arguments.

Why does the cd command (and those similar to it, such as mv, cp, & rm) not function like most other commands when it comes to reading in STDIN? What's the logic behind preventing it from reading standard input to change directories?

The best answer I could find stated:

cd is not an external command – it is a shell builtin function. It runs in the context of the current shell, and not, as external commands do, in a fork/exec'd context as a separate process.

However, to me the above answer does not really explain it at all: Why does cd handle STDIN different than many other commands who read in STDIN?

Best Answer

The commands that read stdin are almost all of the filter family, i.e. programs that transform a flow of text data to a transformed one.

cat , sed, awk, gzip and even sh are good examples of such "filters".

The cited commands, cp, mv and rm are definitely not filters but commands that do things with the arguments passed, here files or directories.

The cd command is similar to them, it expects an argument (or simulate a default one if not provided), and generally doesn't output anything on stdout, although it might output something on it in some cases like when using CDPATH.

Even if one want to create a cd variant that take the target directory from stdin, it wouldn't have any effect when used in a pipeline in the Bourne shell, dash and bash to name a few. The last component of the command being run in a subshell, the change to a new directory won't affect the current shell. e.g.: echo /tmp | cd would work with ksh93 but not bash, dash, zsh, sh, ...

cd <(echo /tmp) would work with shells supporting process substitution (at least ksh, bash, zsh) but wouldn't have any significant advantage compared to cd $(echo tmp)

The only use case that might be of interest would be something like:

echo tmp | (cd ; pwd)

Finally, such a variant would need to sort out the case it was given no argument but the expected behavior is to change the directory to the users's home or it was given no argument but the expected behavior is to read the name of the target directory from stdin. As there is no reliable way to decide, this is doomed.

Related Question