First script:
$ { mkdir dir; cd dir; pwd; } | cat; pwd;
./dir
.
Second script:
$ { mkdir dir; cd dir; pwd; }; pwd;
./dir
./dir
Why this | cat
has an effect on current directory? And how to solve it? I need the first script to work exactly as the second one. I don't want cat
to change my current directory back to .
.
Quoting from the manual:
Each command in a pipeline is executed in its own subshell (see Command Execution Environment).
Also see Grouping Commands:
{}
{ list; }
Placing a list of commands between curly braces causes the list to be executed in the current shell context. No subshell is created.
When you run:
{ mkdir -p dir; cd dir; pwd; } | cat; pwd
OR
{ mkdir -p dir; cd dir; pwd; } | date
OR
{ mkdir -p dir; cd dir; pwd; } | ls
You are running group of commands on LHS of pipe in a sub-shell and hence change dir
isn't reflected in current shell after both commands (LHS and RHS) complete.
However when you run:
{ mkdir -p dir; cd dir; pwd; }; pwd;
There is no pipe in between hence all the commands inside curly braces and pwd
outside curly brace run in the current shell itself hence you get changed directory.
PS: Also note that this line:
( mkdir -p dir; cd dir; pwd; )
Will also not change the current directory in current shell because commands inside square brackets execute in a sub shell whereas curly braces are just used for grouping.
It's not that the pipe goes back to the directory, it's that you've made the first command (prior to the semicolon) applicable only to the cat
command. You're essentially piping the output of the subprocess of the mkdir
and cd
and pwd
go to the cat
process.
For example:
{ mkdir dir; cd dir; pwd; } | cat; pwd;
First expands into two processes: 1) { mkdir dir; cd dir; pwd; } | cat;
and 2) pwd
The first process expands into two processes, { mkdir dir; cd dir; pwd; }
which then sends its stdout
to stdin
of cat
. When the first of these two processes finishes and the stdout
is collected, its subprocess exits and it is like the cd
never happened because the cd
only affects the directory of the process it was running in. The pwd
never actually changed $PWD
, it only printed that which was provided on stdin
.
To resolve this issue (assuming I understand what you are trying to do) I would change this to:
{ mkdir dir; cd dir; pwd; }; pwd; cd -
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With