Why does `cd` have no effect if output is piped?

The name of the pictureThe name of the pictureThe name of the pictureClash Royale CLAN TAG#URR8PPP











up vote
3
down vote

favorite












I accidentally typed



cd /tmp | tail


which is of course not what I meant. But to my surprise, I then did not change directory. Why is this? For comparison



cd /tmp > /tmp/foo


does result in a change of directory, so it's not the output redirection per sé. What's going on here?







share|improve this question



















  • The pipe spawns a subshell that exits when tail exits. I would have expected only tail to be in the subshell, but I guess the cd is as well.
    – jordanm
    Jun 22 at 16:21







  • 1




    But cd /tmp | pwd exhibits the same behavior -- pwd shows an unchanged working directory.
    – DopeGhoti
    Jun 22 at 16:23










  • Each part of the pipeline is a separate process (maybe except last command).
    – ctrl-alt-delor
    Jun 22 at 16:56














up vote
3
down vote

favorite












I accidentally typed



cd /tmp | tail


which is of course not what I meant. But to my surprise, I then did not change directory. Why is this? For comparison



cd /tmp > /tmp/foo


does result in a change of directory, so it's not the output redirection per sé. What's going on here?







share|improve this question



















  • The pipe spawns a subshell that exits when tail exits. I would have expected only tail to be in the subshell, but I guess the cd is as well.
    – jordanm
    Jun 22 at 16:21







  • 1




    But cd /tmp | pwd exhibits the same behavior -- pwd shows an unchanged working directory.
    – DopeGhoti
    Jun 22 at 16:23










  • Each part of the pipeline is a separate process (maybe except last command).
    – ctrl-alt-delor
    Jun 22 at 16:56












up vote
3
down vote

favorite









up vote
3
down vote

favorite











I accidentally typed



cd /tmp | tail


which is of course not what I meant. But to my surprise, I then did not change directory. Why is this? For comparison



cd /tmp > /tmp/foo


does result in a change of directory, so it's not the output redirection per sé. What's going on here?







share|improve this question











I accidentally typed



cd /tmp | tail


which is of course not what I meant. But to my surprise, I then did not change directory. Why is this? For comparison



cd /tmp > /tmp/foo


does result in a change of directory, so it's not the output redirection per sé. What's going on here?









share|improve this question










share|improve this question




share|improve this question









asked Jun 22 at 16:19









gerrit

1,11741326




1,11741326











  • The pipe spawns a subshell that exits when tail exits. I would have expected only tail to be in the subshell, but I guess the cd is as well.
    – jordanm
    Jun 22 at 16:21







  • 1




    But cd /tmp | pwd exhibits the same behavior -- pwd shows an unchanged working directory.
    – DopeGhoti
    Jun 22 at 16:23










  • Each part of the pipeline is a separate process (maybe except last command).
    – ctrl-alt-delor
    Jun 22 at 16:56
















  • The pipe spawns a subshell that exits when tail exits. I would have expected only tail to be in the subshell, but I guess the cd is as well.
    – jordanm
    Jun 22 at 16:21







  • 1




    But cd /tmp | pwd exhibits the same behavior -- pwd shows an unchanged working directory.
    – DopeGhoti
    Jun 22 at 16:23










  • Each part of the pipeline is a separate process (maybe except last command).
    – ctrl-alt-delor
    Jun 22 at 16:56















The pipe spawns a subshell that exits when tail exits. I would have expected only tail to be in the subshell, but I guess the cd is as well.
– jordanm
Jun 22 at 16:21





The pipe spawns a subshell that exits when tail exits. I would have expected only tail to be in the subshell, but I guess the cd is as well.
– jordanm
Jun 22 at 16:21





1




1




But cd /tmp | pwd exhibits the same behavior -- pwd shows an unchanged working directory.
– DopeGhoti
Jun 22 at 16:23




But cd /tmp | pwd exhibits the same behavior -- pwd shows an unchanged working directory.
– DopeGhoti
Jun 22 at 16:23












Each part of the pipeline is a separate process (maybe except last command).
– ctrl-alt-delor
Jun 22 at 16:56




Each part of the pipeline is a separate process (maybe except last command).
– ctrl-alt-delor
Jun 22 at 16:56










1 Answer
1






active

oldest

votes

















up vote
3
down vote



accepted










Pipes involve subshells, portions of which are not run in the parent shell and thus cannot affect the working directory of that parent shell process. This is how ZSH behaves:



% cd /tmp
% cd /var/tmp | tail
% pwd
/tmp
% echo foo | cd /var/tmp
(pwd now: /var/tmp)
% cd /tmp
% echo foo | cd /var/tmp | echo bar
bar
% pwd
/tmp
%


Note how the directory only changed when the cd was the last command in the pipeline; this was run in the parent shell proper and thus was able to change the working directory of that process.



A useful use of this feature usually involves an explicit subshell and commands run therein:



dowork | ( cd elsewhere && domorework ) | andyetmore


also be sure to error check the cd call instead of assuming it worked, unless you like rsync output sprayed all over /, or other such hypothetical messes...






share|improve this answer





















  • I understand why tail would need to be in a subshell, but I don't understand by the cd must be in a subshell, for the pipe to work.
    – gerrit
    Jun 22 at 23:17










  • having the parent process also run at various random points throughout the pipeline and handling I/O and deadlocks correctly would be much more complicated than simply forking off N children with the I/O wired up correctly
    – thrig
    Jun 23 at 14:33










Your Answer







StackExchange.ready(function()
var channelOptions =
tags: "".split(" "),
id: "106"
;
initTagRenderer("".split(" "), "".split(" "), channelOptions);

StackExchange.using("externalEditor", function()
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled)
StackExchange.using("snippets", function()
createEditor();
);

else
createEditor();

);

function createEditor()
StackExchange.prepareEditor(
heartbeatType: 'answer',
convertImagesToLinks: false,
noModals: false,
showLowRepImageUploadWarning: true,
reputationToPostImages: null,
bindNavPrevention: true,
postfix: "",
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
);



);








 

draft saved


draft discarded


















StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2funix.stackexchange.com%2fquestions%2f451341%2fwhy-does-cd-have-no-effect-if-output-is-piped%23new-answer', 'question_page');

);

Post as a guest






























1 Answer
1






active

oldest

votes








1 Answer
1






active

oldest

votes









active

oldest

votes






active

oldest

votes








up vote
3
down vote



accepted










Pipes involve subshells, portions of which are not run in the parent shell and thus cannot affect the working directory of that parent shell process. This is how ZSH behaves:



% cd /tmp
% cd /var/tmp | tail
% pwd
/tmp
% echo foo | cd /var/tmp
(pwd now: /var/tmp)
% cd /tmp
% echo foo | cd /var/tmp | echo bar
bar
% pwd
/tmp
%


Note how the directory only changed when the cd was the last command in the pipeline; this was run in the parent shell proper and thus was able to change the working directory of that process.



A useful use of this feature usually involves an explicit subshell and commands run therein:



dowork | ( cd elsewhere && domorework ) | andyetmore


also be sure to error check the cd call instead of assuming it worked, unless you like rsync output sprayed all over /, or other such hypothetical messes...






share|improve this answer





















  • I understand why tail would need to be in a subshell, but I don't understand by the cd must be in a subshell, for the pipe to work.
    – gerrit
    Jun 22 at 23:17










  • having the parent process also run at various random points throughout the pipeline and handling I/O and deadlocks correctly would be much more complicated than simply forking off N children with the I/O wired up correctly
    – thrig
    Jun 23 at 14:33














up vote
3
down vote



accepted










Pipes involve subshells, portions of which are not run in the parent shell and thus cannot affect the working directory of that parent shell process. This is how ZSH behaves:



% cd /tmp
% cd /var/tmp | tail
% pwd
/tmp
% echo foo | cd /var/tmp
(pwd now: /var/tmp)
% cd /tmp
% echo foo | cd /var/tmp | echo bar
bar
% pwd
/tmp
%


Note how the directory only changed when the cd was the last command in the pipeline; this was run in the parent shell proper and thus was able to change the working directory of that process.



A useful use of this feature usually involves an explicit subshell and commands run therein:



dowork | ( cd elsewhere && domorework ) | andyetmore


also be sure to error check the cd call instead of assuming it worked, unless you like rsync output sprayed all over /, or other such hypothetical messes...






share|improve this answer





















  • I understand why tail would need to be in a subshell, but I don't understand by the cd must be in a subshell, for the pipe to work.
    – gerrit
    Jun 22 at 23:17










  • having the parent process also run at various random points throughout the pipeline and handling I/O and deadlocks correctly would be much more complicated than simply forking off N children with the I/O wired up correctly
    – thrig
    Jun 23 at 14:33












up vote
3
down vote



accepted







up vote
3
down vote



accepted






Pipes involve subshells, portions of which are not run in the parent shell and thus cannot affect the working directory of that parent shell process. This is how ZSH behaves:



% cd /tmp
% cd /var/tmp | tail
% pwd
/tmp
% echo foo | cd /var/tmp
(pwd now: /var/tmp)
% cd /tmp
% echo foo | cd /var/tmp | echo bar
bar
% pwd
/tmp
%


Note how the directory only changed when the cd was the last command in the pipeline; this was run in the parent shell proper and thus was able to change the working directory of that process.



A useful use of this feature usually involves an explicit subshell and commands run therein:



dowork | ( cd elsewhere && domorework ) | andyetmore


also be sure to error check the cd call instead of assuming it worked, unless you like rsync output sprayed all over /, or other such hypothetical messes...






share|improve this answer













Pipes involve subshells, portions of which are not run in the parent shell and thus cannot affect the working directory of that parent shell process. This is how ZSH behaves:



% cd /tmp
% cd /var/tmp | tail
% pwd
/tmp
% echo foo | cd /var/tmp
(pwd now: /var/tmp)
% cd /tmp
% echo foo | cd /var/tmp | echo bar
bar
% pwd
/tmp
%


Note how the directory only changed when the cd was the last command in the pipeline; this was run in the parent shell proper and thus was able to change the working directory of that process.



A useful use of this feature usually involves an explicit subshell and commands run therein:



dowork | ( cd elsewhere && domorework ) | andyetmore


also be sure to error check the cd call instead of assuming it worked, unless you like rsync output sprayed all over /, or other such hypothetical messes...







share|improve this answer













share|improve this answer



share|improve this answer











answered Jun 22 at 16:43









thrig

21.8k12751




21.8k12751











  • I understand why tail would need to be in a subshell, but I don't understand by the cd must be in a subshell, for the pipe to work.
    – gerrit
    Jun 22 at 23:17










  • having the parent process also run at various random points throughout the pipeline and handling I/O and deadlocks correctly would be much more complicated than simply forking off N children with the I/O wired up correctly
    – thrig
    Jun 23 at 14:33
















  • I understand why tail would need to be in a subshell, but I don't understand by the cd must be in a subshell, for the pipe to work.
    – gerrit
    Jun 22 at 23:17










  • having the parent process also run at various random points throughout the pipeline and handling I/O and deadlocks correctly would be much more complicated than simply forking off N children with the I/O wired up correctly
    – thrig
    Jun 23 at 14:33















I understand why tail would need to be in a subshell, but I don't understand by the cd must be in a subshell, for the pipe to work.
– gerrit
Jun 22 at 23:17




I understand why tail would need to be in a subshell, but I don't understand by the cd must be in a subshell, for the pipe to work.
– gerrit
Jun 22 at 23:17












having the parent process also run at various random points throughout the pipeline and handling I/O and deadlocks correctly would be much more complicated than simply forking off N children with the I/O wired up correctly
– thrig
Jun 23 at 14:33




having the parent process also run at various random points throughout the pipeline and handling I/O and deadlocks correctly would be much more complicated than simply forking off N children with the I/O wired up correctly
– thrig
Jun 23 at 14:33












 

draft saved


draft discarded


























 


draft saved


draft discarded














StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2funix.stackexchange.com%2fquestions%2f451341%2fwhy-does-cd-have-no-effect-if-output-is-piped%23new-answer', 'question_page');

);

Post as a guest













































































Popular posts from this blog

Peggy Mitchell

Palaiologos

The Forum (Inglewood, California)