Why can't I 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.
Solution 1:
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:
- instead of showing
foo
's output on the terminal, it directs it tobar
as input. - instead of taking input to
bar
from the terminal, it takes it fromfoo
's output.
(Both those bullet points actually express the same thing.)
So, what happens when you run tail -n 1 ~/mloc | cd
?
- It runs
cd
and, whenevercd
accepts input while running, it takes that input from the output oftail -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 fromcd
; for example, runcd blah 2>&1 | less
; ifblah
doesn't exist or isn't a directory, you'll be able to view the error inless
.
Finally, consider what's different about cd $(tail -n 1 ~/mloc)
. This command:
- Runs
tail -n 1 ~/mloc
and captures its output. - Instead of displaying the output, constructs a command consisting of it appended to
cd
. - Runs that command.