Why do `jobs` and `dirs` run in command subsitution, process substitution, pipeline, and background jobs output the same as in original shell?

The name of the pictureThe name of the pictureThe name of the pictureClash 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?







share|improve this question



























    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?







    share|improve this question























      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?







      share|improve this question













      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?









      share|improve this question












      share|improve this question




      share|improve this question








      edited Jul 28 at 3:42
























      asked Jul 28 at 3:22









      Tim

      22.5k61222398




      22.5k61222398




















          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)






          share|improve this answer



















          • 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










          • 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











          • 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










          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%2f458984%2fwhy-do-jobs-and-dirs-run-in-command-subsitution-process-substitution-pipel%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
          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)






          share|improve this answer



















          • 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










          • 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











          • 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














          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)






          share|improve this answer



















          • 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










          • 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











          • 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












          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)






          share|improve this answer















          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)







          share|improve this answer















          share|improve this answer



          share|improve this answer








          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 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










          • 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










          • 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












          • 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










          • 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











          • 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







          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












           

          draft saved


          draft discarded


























           


          draft saved


          draft discarded














          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













































































          Popular posts from this blog

          How to check contact read email or not when send email to Individual?

          Bahrain

          Postfix configuration issue with fips on centos 7; mailgun relay