1

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?

  • echo 'hi' | cd / produces no errors here with Bash on Linux (though nor does it change the current working directory, as I'm sure is explained somewhere else on the site). Which shell are you using that's giving an error? Or is this a question about what's allowed per POSIX standards? – derobert Feb 4 '16 at 22:44
  • 3
    In answer to the question posed in the title, cd doesn't always require an argument to change directories. Example: cd / ; pwd and now cd ; pwd. No argument supplied but the directory changed. – roaima Feb 4 '16 at 22:53
  • 3
  • 2
    There are many commands like cd: mv, cp, rm are three examples. I'd say that cd is consistent by not reading from stdin. – Andrea Corbellini Feb 4 '16 at 23:08
  • 1
    What do you mean by “different than other commands”? It's extremely rare for a command to accept the same things on standard input and on the command line. What on earth made you think that this was a common thing? – Gilles 'SO- stop being evil' Feb 5 '16 at 22:37
7

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.

  • But if, like you said, cd outputs on stdout on some cases, isn't the logical next step to make cd also accept input? I'm just trying to understand the design logic behind it. – Roflicide Feb 4 '16 at 23:42
  • My bad, cd output to stderr, not stdout. In any case, as I already wrote in my last paragraph, implementing such a feature would be pointless as not compatible with POSIX conforming shells, i.e. cd won't be able to change the current directory, quite a limitation given the fact this command has no other purpose. – jlliagre Feb 5 '16 at 1:32
  • @Roflicide no, a large number of commands write to stdout. Asking them all to accept stdin is not necessarily logical. – muru Feb 5 '16 at 5:59
3

Command-line arguments are not at all the same thing as stdin; even commands that use both generally use them for different things. Take cat for example:

echo foo bar | cat    # outputs "foo bar"
cat foo bar           # looks for files named "foo" and "bar", and concatenates them (if found)

If you look at most other commands that read from stdin, you'll find similar things: they don't treat arguments and stdin interchangeably, but as ways of providing different kinds of information to the command.

There are some commands that can take the same type of info either way, but even in those cases there's usually an option you have to specify to tell it which to use. For example, perl reads its program from stdin unless it's told to do otherwise:

echo 'print 1' | perl    # runs "print 1" as a perl program, which prints "1"
perl -e 'print 1'        # runs "print 1" as a perl program, which prints "1"
perl print 1             # tries to run a file named "print" as a script, giving it the argument "1"

...So, I think the premise of the question is false: most commands do not take the same sort of info from stdin that they do from the arguments, so cd is not unusual in this respect.

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.