views:

192

answers:

1

Here's a puzzler: can anyone explain why cd fails when the output is redirected to a pipe?

E.g.:

james@machine:~$ cd /tmp                          # fine, no problem
james@machine:~$ cd /tmp | grep 'foo'             # doesn't work
james@machine:~$ cd /tmp | tee -a output.log      # doesn't work
james@machine:~$ cd /tmp >out.log                 # does work

Verified on OSX, Ubuntu and RHEL.

Any ideas?

EDIT: Seem strange that I'm piping the output of cd? The reason is that it's from a function wrapping arbitrary shell commands with log entries and dealing with output.

+11  A: 

When you redirect the output, it spawns a child shell process, changes the directory in the child process, and exits. When you don't redirect the output, it doesn't spawn any new process because it is a built-in shell command.

Tmdean
This is promising, but the spawned command still seems to running in the current directory: output sent to a file doesn't respect the cd... I'd be happy to accept this with more explanation, perhaps a workdaround? ;)
Alabaster Codify
You mean output to out.log in your example? That file is created and redirection is set up before the cd command is executed.
Timo Metsälä
Exactly... If I recall my OS class correctly, the shell forks a child process, the child process opens the new stdin, stdout, and/or stderr, then it executes its command.
Tmdean
I mean that this: "cd /tmp | echo 'foo' >out.log" creates out.log in the current directory, not in /tmp. The spawned child is not running in /tmp - unless you mean the spawned child's stdout is set before the cd is executed?
Alabaster Codify
Yes, that's what I meant.
Tmdean