Why do `jobs` and `dirs` run in command subsitution, process substitution, pipeline, and background jobs output the same as in original shell?
Clash Royale CLAN TAG#URR8PPP
.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty margin-bottom:0;
up vote
1
down vote
favorite
If I am correct, command substitution, process substitution, pipeline, and background jobs run the commands specified within themselves in a subshell not in the original shell.
But when the commands are jobs
or dirs
, they output exactly the same as when they are run directly in the original shell:
echo $( jobs )
cat <(jobs)
jobs | less
echo $( dirs )
cat <(dirs)
dirs | less
dirs &
Why is that? Is it because the subshells inherit the jobs and dirs stack from the original shell, or because jobs
and dirs
are run in the original shell instead of the subshells?
But
jobs &
doesn't output anything. Why is it different from the other commands? Thanks.
Related Does sourcing a script in subshells still allow the commands in the script to access the state of the original shell?
bash
add a comment |Â
up vote
1
down vote
favorite
If I am correct, command substitution, process substitution, pipeline, and background jobs run the commands specified within themselves in a subshell not in the original shell.
But when the commands are jobs
or dirs
, they output exactly the same as when they are run directly in the original shell:
echo $( jobs )
cat <(jobs)
jobs | less
echo $( dirs )
cat <(dirs)
dirs | less
dirs &
Why is that? Is it because the subshells inherit the jobs and dirs stack from the original shell, or because jobs
and dirs
are run in the original shell instead of the subshells?
But
jobs &
doesn't output anything. Why is it different from the other commands? Thanks.
Related Does sourcing a script in subshells still allow the commands in the script to access the state of the original shell?
bash
add a comment |Â
up vote
1
down vote
favorite
up vote
1
down vote
favorite
If I am correct, command substitution, process substitution, pipeline, and background jobs run the commands specified within themselves in a subshell not in the original shell.
But when the commands are jobs
or dirs
, they output exactly the same as when they are run directly in the original shell:
echo $( jobs )
cat <(jobs)
jobs | less
echo $( dirs )
cat <(dirs)
dirs | less
dirs &
Why is that? Is it because the subshells inherit the jobs and dirs stack from the original shell, or because jobs
and dirs
are run in the original shell instead of the subshells?
But
jobs &
doesn't output anything. Why is it different from the other commands? Thanks.
Related Does sourcing a script in subshells still allow the commands in the script to access the state of the original shell?
bash
If I am correct, command substitution, process substitution, pipeline, and background jobs run the commands specified within themselves in a subshell not in the original shell.
But when the commands are jobs
or dirs
, they output exactly the same as when they are run directly in the original shell:
echo $( jobs )
cat <(jobs)
jobs | less
echo $( dirs )
cat <(dirs)
dirs | less
dirs &
Why is that? Is it because the subshells inherit the jobs and dirs stack from the original shell, or because jobs
and dirs
are run in the original shell instead of the subshells?
But
jobs &
doesn't output anything. Why is it different from the other commands? Thanks.
Related Does sourcing a script in subshells still allow the commands in the script to access the state of the original shell?
bash
edited Jul 28 at 3:42
asked Jul 28 at 3:22
Tim
22.5k61222398
22.5k61222398
add a comment |Â
add a comment |Â
1 Answer
1
active
oldest
votes
up vote
2
down vote
accepted
The first part of this answer is that jobs
and dirs
are built-ins, so typically bash will just run those directly instead of invoking a subshell.
That's true for the cases where there are pipes or command substitution ($(jobs)
) or process substitution (<(jobs)
).
That's not really the case for running the command in background (jobs &
) or requesting a subshell explicitly (with ( jobs )
.)
So that explains the last part of your question. When you run jobs
in a subshell, it's indeed showing the jobs for the subshell itself.
Here's a good demonstration of this concept:
$ sleep 1001 &
[1] 15927
$ sleep 1002 &
[2] 15940
$ jobs
[1]- Running sleep 1001 &
[2]+ Running sleep 1002 &
$ ( sleep 1003 & jobs )
[1]+ Running sleep 1003 &
$ jobs
[1]- Running sleep 1001 &
[2]+ Running sleep 1002 &
You'll see that the case where jobs
is running in a subshell, only the jobs of that subshell (in this case sleep 1003
) will be displayed.
Now, to wrap up, we need to address the middle part of the question, which is why dirs &
(which does indeed run in a subshell, as would ( dirs )
) will still show the directories saved in the pushd stack.
It turns out that this is because the shell exports the list of directories in the special array variable DIRSTACK
, which is then inherited by subshells. (You can read more about DIRSTACK
here.)
One way to demonstrate how this works is to use pushd
on the subshell and see how that doesn't affect the directory stack of the original shell:
$ dirs
~
$ pushd ~/tmp
~/tmp ~
$ ( dirs; pushd / >/dev/null; dirs )
~/tmp ~
/ ~/tmp ~
$ dirs
~/tmp ~
I believe that should address all the items you asked about.
UPDATE: bash has a special provision to make jobs | less
work, having the jobs
command run in the current shell (which is not the case for other built-ins.)
The code has a check that is stored in a jobs_hack
variable, which is later checked to make it run without creating a sub-shell and allow piping the output of jobs
to another command.
See here for the relevant part of the source code that implements this. (As of bash 4.4)
1
where do you get the basis for your initial argument? in my experiencebash
is particularly notorious for needless childing... i would assume$!
is a major factor here, and maybe a sloppy handover/lazy check where$$
remains unaltered. too lazy to check now, though.
â mikeserv
Jul 28 at 7:30
Thanks. "the shell exports the list of directories in the special array variable DIRSTACK", butenv
doesn't showDIRSTACK
â Tim
Jul 30 at 20:58
Do you find any general rule about which other builtin commands used in either of the five cases are run in subshells or in original shells?
â Tim
Jul 30 at 21:08
Incd .. | pwd
,cd ..
runs in a subshell not in the original shell. Why is it different fromjobs | cat
?
â Tim
Jul 30 at 22:59
Hi @Tim, I updated the answer to address that. Indeed, there's a special case forjobs
, bash will recognize it and force it to run in the current shell process, exactly in order to support this use case, of piping its output to another command. I hope that helps!
â Filipe Brandenburger
Jul 30 at 23:27
add a comment |Â
1 Answer
1
active
oldest
votes
1 Answer
1
active
oldest
votes
active
oldest
votes
active
oldest
votes
up vote
2
down vote
accepted
The first part of this answer is that jobs
and dirs
are built-ins, so typically bash will just run those directly instead of invoking a subshell.
That's true for the cases where there are pipes or command substitution ($(jobs)
) or process substitution (<(jobs)
).
That's not really the case for running the command in background (jobs &
) or requesting a subshell explicitly (with ( jobs )
.)
So that explains the last part of your question. When you run jobs
in a subshell, it's indeed showing the jobs for the subshell itself.
Here's a good demonstration of this concept:
$ sleep 1001 &
[1] 15927
$ sleep 1002 &
[2] 15940
$ jobs
[1]- Running sleep 1001 &
[2]+ Running sleep 1002 &
$ ( sleep 1003 & jobs )
[1]+ Running sleep 1003 &
$ jobs
[1]- Running sleep 1001 &
[2]+ Running sleep 1002 &
You'll see that the case where jobs
is running in a subshell, only the jobs of that subshell (in this case sleep 1003
) will be displayed.
Now, to wrap up, we need to address the middle part of the question, which is why dirs &
(which does indeed run in a subshell, as would ( dirs )
) will still show the directories saved in the pushd stack.
It turns out that this is because the shell exports the list of directories in the special array variable DIRSTACK
, which is then inherited by subshells. (You can read more about DIRSTACK
here.)
One way to demonstrate how this works is to use pushd
on the subshell and see how that doesn't affect the directory stack of the original shell:
$ dirs
~
$ pushd ~/tmp
~/tmp ~
$ ( dirs; pushd / >/dev/null; dirs )
~/tmp ~
/ ~/tmp ~
$ dirs
~/tmp ~
I believe that should address all the items you asked about.
UPDATE: bash has a special provision to make jobs | less
work, having the jobs
command run in the current shell (which is not the case for other built-ins.)
The code has a check that is stored in a jobs_hack
variable, which is later checked to make it run without creating a sub-shell and allow piping the output of jobs
to another command.
See here for the relevant part of the source code that implements this. (As of bash 4.4)
1
where do you get the basis for your initial argument? in my experiencebash
is particularly notorious for needless childing... i would assume$!
is a major factor here, and maybe a sloppy handover/lazy check where$$
remains unaltered. too lazy to check now, though.
â mikeserv
Jul 28 at 7:30
Thanks. "the shell exports the list of directories in the special array variable DIRSTACK", butenv
doesn't showDIRSTACK
â Tim
Jul 30 at 20:58
Do you find any general rule about which other builtin commands used in either of the five cases are run in subshells or in original shells?
â Tim
Jul 30 at 21:08
Incd .. | pwd
,cd ..
runs in a subshell not in the original shell. Why is it different fromjobs | cat
?
â Tim
Jul 30 at 22:59
Hi @Tim, I updated the answer to address that. Indeed, there's a special case forjobs
, bash will recognize it and force it to run in the current shell process, exactly in order to support this use case, of piping its output to another command. I hope that helps!
â Filipe Brandenburger
Jul 30 at 23:27
add a comment |Â
up vote
2
down vote
accepted
The first part of this answer is that jobs
and dirs
are built-ins, so typically bash will just run those directly instead of invoking a subshell.
That's true for the cases where there are pipes or command substitution ($(jobs)
) or process substitution (<(jobs)
).
That's not really the case for running the command in background (jobs &
) or requesting a subshell explicitly (with ( jobs )
.)
So that explains the last part of your question. When you run jobs
in a subshell, it's indeed showing the jobs for the subshell itself.
Here's a good demonstration of this concept:
$ sleep 1001 &
[1] 15927
$ sleep 1002 &
[2] 15940
$ jobs
[1]- Running sleep 1001 &
[2]+ Running sleep 1002 &
$ ( sleep 1003 & jobs )
[1]+ Running sleep 1003 &
$ jobs
[1]- Running sleep 1001 &
[2]+ Running sleep 1002 &
You'll see that the case where jobs
is running in a subshell, only the jobs of that subshell (in this case sleep 1003
) will be displayed.
Now, to wrap up, we need to address the middle part of the question, which is why dirs &
(which does indeed run in a subshell, as would ( dirs )
) will still show the directories saved in the pushd stack.
It turns out that this is because the shell exports the list of directories in the special array variable DIRSTACK
, which is then inherited by subshells. (You can read more about DIRSTACK
here.)
One way to demonstrate how this works is to use pushd
on the subshell and see how that doesn't affect the directory stack of the original shell:
$ dirs
~
$ pushd ~/tmp
~/tmp ~
$ ( dirs; pushd / >/dev/null; dirs )
~/tmp ~
/ ~/tmp ~
$ dirs
~/tmp ~
I believe that should address all the items you asked about.
UPDATE: bash has a special provision to make jobs | less
work, having the jobs
command run in the current shell (which is not the case for other built-ins.)
The code has a check that is stored in a jobs_hack
variable, which is later checked to make it run without creating a sub-shell and allow piping the output of jobs
to another command.
See here for the relevant part of the source code that implements this. (As of bash 4.4)
1
where do you get the basis for your initial argument? in my experiencebash
is particularly notorious for needless childing... i would assume$!
is a major factor here, and maybe a sloppy handover/lazy check where$$
remains unaltered. too lazy to check now, though.
â mikeserv
Jul 28 at 7:30
Thanks. "the shell exports the list of directories in the special array variable DIRSTACK", butenv
doesn't showDIRSTACK
â Tim
Jul 30 at 20:58
Do you find any general rule about which other builtin commands used in either of the five cases are run in subshells or in original shells?
â Tim
Jul 30 at 21:08
Incd .. | pwd
,cd ..
runs in a subshell not in the original shell. Why is it different fromjobs | cat
?
â Tim
Jul 30 at 22:59
Hi @Tim, I updated the answer to address that. Indeed, there's a special case forjobs
, bash will recognize it and force it to run in the current shell process, exactly in order to support this use case, of piping its output to another command. I hope that helps!
â Filipe Brandenburger
Jul 30 at 23:27
add a comment |Â
up vote
2
down vote
accepted
up vote
2
down vote
accepted
The first part of this answer is that jobs
and dirs
are built-ins, so typically bash will just run those directly instead of invoking a subshell.
That's true for the cases where there are pipes or command substitution ($(jobs)
) or process substitution (<(jobs)
).
That's not really the case for running the command in background (jobs &
) or requesting a subshell explicitly (with ( jobs )
.)
So that explains the last part of your question. When you run jobs
in a subshell, it's indeed showing the jobs for the subshell itself.
Here's a good demonstration of this concept:
$ sleep 1001 &
[1] 15927
$ sleep 1002 &
[2] 15940
$ jobs
[1]- Running sleep 1001 &
[2]+ Running sleep 1002 &
$ ( sleep 1003 & jobs )
[1]+ Running sleep 1003 &
$ jobs
[1]- Running sleep 1001 &
[2]+ Running sleep 1002 &
You'll see that the case where jobs
is running in a subshell, only the jobs of that subshell (in this case sleep 1003
) will be displayed.
Now, to wrap up, we need to address the middle part of the question, which is why dirs &
(which does indeed run in a subshell, as would ( dirs )
) will still show the directories saved in the pushd stack.
It turns out that this is because the shell exports the list of directories in the special array variable DIRSTACK
, which is then inherited by subshells. (You can read more about DIRSTACK
here.)
One way to demonstrate how this works is to use pushd
on the subshell and see how that doesn't affect the directory stack of the original shell:
$ dirs
~
$ pushd ~/tmp
~/tmp ~
$ ( dirs; pushd / >/dev/null; dirs )
~/tmp ~
/ ~/tmp ~
$ dirs
~/tmp ~
I believe that should address all the items you asked about.
UPDATE: bash has a special provision to make jobs | less
work, having the jobs
command run in the current shell (which is not the case for other built-ins.)
The code has a check that is stored in a jobs_hack
variable, which is later checked to make it run without creating a sub-shell and allow piping the output of jobs
to another command.
See here for the relevant part of the source code that implements this. (As of bash 4.4)
The first part of this answer is that jobs
and dirs
are built-ins, so typically bash will just run those directly instead of invoking a subshell.
That's true for the cases where there are pipes or command substitution ($(jobs)
) or process substitution (<(jobs)
).
That's not really the case for running the command in background (jobs &
) or requesting a subshell explicitly (with ( jobs )
.)
So that explains the last part of your question. When you run jobs
in a subshell, it's indeed showing the jobs for the subshell itself.
Here's a good demonstration of this concept:
$ sleep 1001 &
[1] 15927
$ sleep 1002 &
[2] 15940
$ jobs
[1]- Running sleep 1001 &
[2]+ Running sleep 1002 &
$ ( sleep 1003 & jobs )
[1]+ Running sleep 1003 &
$ jobs
[1]- Running sleep 1001 &
[2]+ Running sleep 1002 &
You'll see that the case where jobs
is running in a subshell, only the jobs of that subshell (in this case sleep 1003
) will be displayed.
Now, to wrap up, we need to address the middle part of the question, which is why dirs &
(which does indeed run in a subshell, as would ( dirs )
) will still show the directories saved in the pushd stack.
It turns out that this is because the shell exports the list of directories in the special array variable DIRSTACK
, which is then inherited by subshells. (You can read more about DIRSTACK
here.)
One way to demonstrate how this works is to use pushd
on the subshell and see how that doesn't affect the directory stack of the original shell:
$ dirs
~
$ pushd ~/tmp
~/tmp ~
$ ( dirs; pushd / >/dev/null; dirs )
~/tmp ~
/ ~/tmp ~
$ dirs
~/tmp ~
I believe that should address all the items you asked about.
UPDATE: bash has a special provision to make jobs | less
work, having the jobs
command run in the current shell (which is not the case for other built-ins.)
The code has a check that is stored in a jobs_hack
variable, which is later checked to make it run without creating a sub-shell and allow piping the output of jobs
to another command.
See here for the relevant part of the source code that implements this. (As of bash 4.4)
edited Jul 30 at 23:26
answered Jul 28 at 4:24
Filipe Brandenburger
2,894417
2,894417
1
where do you get the basis for your initial argument? in my experiencebash
is particularly notorious for needless childing... i would assume$!
is a major factor here, and maybe a sloppy handover/lazy check where$$
remains unaltered. too lazy to check now, though.
â mikeserv
Jul 28 at 7:30
Thanks. "the shell exports the list of directories in the special array variable DIRSTACK", butenv
doesn't showDIRSTACK
â Tim
Jul 30 at 20:58
Do you find any general rule about which other builtin commands used in either of the five cases are run in subshells or in original shells?
â Tim
Jul 30 at 21:08
Incd .. | pwd
,cd ..
runs in a subshell not in the original shell. Why is it different fromjobs | cat
?
â Tim
Jul 30 at 22:59
Hi @Tim, I updated the answer to address that. Indeed, there's a special case forjobs
, bash will recognize it and force it to run in the current shell process, exactly in order to support this use case, of piping its output to another command. I hope that helps!
â Filipe Brandenburger
Jul 30 at 23:27
add a comment |Â
1
where do you get the basis for your initial argument? in my experiencebash
is particularly notorious for needless childing... i would assume$!
is a major factor here, and maybe a sloppy handover/lazy check where$$
remains unaltered. too lazy to check now, though.
â mikeserv
Jul 28 at 7:30
Thanks. "the shell exports the list of directories in the special array variable DIRSTACK", butenv
doesn't showDIRSTACK
â Tim
Jul 30 at 20:58
Do you find any general rule about which other builtin commands used in either of the five cases are run in subshells or in original shells?
â Tim
Jul 30 at 21:08
Incd .. | pwd
,cd ..
runs in a subshell not in the original shell. Why is it different fromjobs | cat
?
â Tim
Jul 30 at 22:59
Hi @Tim, I updated the answer to address that. Indeed, there's a special case forjobs
, bash will recognize it and force it to run in the current shell process, exactly in order to support this use case, of piping its output to another command. I hope that helps!
â Filipe Brandenburger
Jul 30 at 23:27
1
1
where do you get the basis for your initial argument? in my experience
bash
is particularly notorious for needless childing... i would assume $!
is a major factor here, and maybe a sloppy handover/lazy check where $$
remains unaltered. too lazy to check now, though.â mikeserv
Jul 28 at 7:30
where do you get the basis for your initial argument? in my experience
bash
is particularly notorious for needless childing... i would assume $!
is a major factor here, and maybe a sloppy handover/lazy check where $$
remains unaltered. too lazy to check now, though.â mikeserv
Jul 28 at 7:30
Thanks. "the shell exports the list of directories in the special array variable DIRSTACK", but
env
doesn't show DIRSTACK
â Tim
Jul 30 at 20:58
Thanks. "the shell exports the list of directories in the special array variable DIRSTACK", but
env
doesn't show DIRSTACK
â Tim
Jul 30 at 20:58
Do you find any general rule about which other builtin commands used in either of the five cases are run in subshells or in original shells?
â Tim
Jul 30 at 21:08
Do you find any general rule about which other builtin commands used in either of the five cases are run in subshells or in original shells?
â Tim
Jul 30 at 21:08
In
cd .. | pwd
, cd ..
runs in a subshell not in the original shell. Why is it different from jobs | cat
?â Tim
Jul 30 at 22:59
In
cd .. | pwd
, cd ..
runs in a subshell not in the original shell. Why is it different from jobs | cat
?â Tim
Jul 30 at 22:59
Hi @Tim, I updated the answer to address that. Indeed, there's a special case for
jobs
, bash will recognize it and force it to run in the current shell process, exactly in order to support this use case, of piping its output to another command. I hope that helps!â Filipe Brandenburger
Jul 30 at 23:27
Hi @Tim, I updated the answer to address that. Indeed, there's a special case for
jobs
, bash will recognize it and force it to run in the current shell process, exactly in order to support this use case, of piping its output to another command. I hope that helps!â Filipe Brandenburger
Jul 30 at 23:27
add a comment |Â
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2funix.stackexchange.com%2fquestions%2f458984%2fwhy-do-jobs-and-dirs-run-in-command-subsitution-process-substitution-pipel%23new-answer', 'question_page');
);
Post as a guest
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password