Why can't I pipe stuff into cd?
Example:
$ pwd >> ~/mloc
$ cd /
$ tail -n 1 ~/mloc | cd
cd fails. If do: cd $(tail -n 1 ~/mloc)
, it works.
I understand the last command I wrote works, but I don't understand why I can't pipe into cd.
Why can't I pipe stuff into cd?
Example:
$ pwd >> ~/mloc
$ cd /
$ tail -n 1 ~/mloc | cd
cd fails. If do: cd $(tail -n 1 ~/mloc)
, it works.
I understand the last command I wrote works, but I don't understand why I can't pipe into cd.
Piping to a process sends data to it in place of what you'd type after you have launched the process, not what you'd type as part of the command that launches the process.
(cd
is also not a process but that's less important, I address it below.)
Piping attaches one command's output to another command's input. Consider:
foo | bar
That runs bar
, runs foo
, and:
foo
's output on the terminal, it directs it to bar
as input.bar
from the terminal, it takes it from foo
's output.(Both those bullet points actually express the same thing.)
So, what happens when you run tail -n 1 ~/mloc | cd
?
cd
and, whenever cd
accepts input while running, it takes that input from the output of tail -n 1 ~/mloc
.cd
never accepts input while running.See standard streams (Wikipedia) for more information on the precise meaning of input and output in this answer. (Here, by input, I mean "standard input" and by output I mean "standard output.")
There is also the issue that cd
is not actually a program, but a shell builtin, so when you run cd
no new process is launched. But that is not really why what you're trying doesn't work, because:
Using pipes to pass command line arguments, as you've been attempting, will not ever work for any program.
There's no reason a shell couldn't be written to accommodate pipes to a shell builtin, considering that they accommodate pipes from shell builtins.
Note that sometimes when you use a shell builtin like it's a real program, what happens is that the real program of the same name is run instead. But there's no separate program for cd
, and we can pipe from cd
; for example, run cd blah 2>&1 | less
; if blah
doesn't exist or isn't a directory, you'll be able to view the error in less
.
Finally, consider what's different about cd $(tail -n 1 ~/mloc)
. This command:
tail -n 1 ~/mloc
and captures its output.cd
.