/bin/sh: read variable from pipe [duplicate]

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











up vote
1
down vote

favorite













This question already has an answer here:



  • in bash, read after a pipe is not setting values

    2 answers



In bash or zsh, I can use following syntax to read from pipe into variables:



echo AAA BBB | read X Y ; echo $X


which will print AAA



Why does the same not work in /bin/sh?



I am using /bin/sh -> /bin/dash in Debian










share|improve this question















marked as duplicate by muru, Jeff Schaller, sebasth, Shadur, Kiwy Sep 11 at 12:57


This question has been asked before and already has an answer. If those answers do not fully address your question, please ask a new question.










  • 2




    for me, it doesn't work in bash either. Also, please clarify if you expect an answer for sh or dash.
    – RoVo
    Sep 11 at 7:06















up vote
1
down vote

favorite













This question already has an answer here:



  • in bash, read after a pipe is not setting values

    2 answers



In bash or zsh, I can use following syntax to read from pipe into variables:



echo AAA BBB | read X Y ; echo $X


which will print AAA



Why does the same not work in /bin/sh?



I am using /bin/sh -> /bin/dash in Debian










share|improve this question















marked as duplicate by muru, Jeff Schaller, sebasth, Shadur, Kiwy Sep 11 at 12:57


This question has been asked before and already has an answer. If those answers do not fully address your question, please ask a new question.










  • 2




    for me, it doesn't work in bash either. Also, please clarify if you expect an answer for sh or dash.
    – RoVo
    Sep 11 at 7:06













up vote
1
down vote

favorite









up vote
1
down vote

favorite












This question already has an answer here:



  • in bash, read after a pipe is not setting values

    2 answers



In bash or zsh, I can use following syntax to read from pipe into variables:



echo AAA BBB | read X Y ; echo $X


which will print AAA



Why does the same not work in /bin/sh?



I am using /bin/sh -> /bin/dash in Debian










share|improve this question
















This question already has an answer here:



  • in bash, read after a pipe is not setting values

    2 answers



In bash or zsh, I can use following syntax to read from pipe into variables:



echo AAA BBB | read X Y ; echo $X


which will print AAA



Why does the same not work in /bin/sh?



I am using /bin/sh -> /bin/dash in Debian





This question already has an answer here:



  • in bash, read after a pipe is not setting values

    2 answers







bash shell dash






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited Sep 11 at 8:36









franiis

1146




1146










asked Sep 11 at 6:41









Martin Vegter

61831113221




61831113221




marked as duplicate by muru, Jeff Schaller, sebasth, Shadur, Kiwy Sep 11 at 12:57


This question has been asked before and already has an answer. If those answers do not fully address your question, please ask a new question.






marked as duplicate by muru, Jeff Schaller, sebasth, Shadur, Kiwy Sep 11 at 12:57


This question has been asked before and already has an answer. If those answers do not fully address your question, please ask a new question.









  • 2




    for me, it doesn't work in bash either. Also, please clarify if you expect an answer for sh or dash.
    – RoVo
    Sep 11 at 7:06













  • 2




    for me, it doesn't work in bash either. Also, please clarify if you expect an answer for sh or dash.
    – RoVo
    Sep 11 at 7:06








2




2




for me, it doesn't work in bash either. Also, please clarify if you expect an answer for sh or dash.
– RoVo
Sep 11 at 7:06





for me, it doesn't work in bash either. Also, please clarify if you expect an answer for sh or dash.
– RoVo
Sep 11 at 7:06











4 Answers
4






active

oldest

votes

















up vote
3
down vote














Why does the same not work in '/bin/sh' ?




Assigning variables in a pipe does not work as expected in sh and bash because each command of a pipe runs in a subshell. Actually, the command does work, X and Y get declared, but they are not available outside the pipe.



The following will work:



echo AAA BBB | read X Y ; echo $X; 


But in your case:



try this,



read X Y <<< "AAA BBB"


or



read X Y < <(echo "AAA BBB")



Some useful links:



  • http://mywiki.wooledge.org/BashFAQ/024

  • bash: Assign variable from pipe?

  • Read values into a shell variable from a pipe





share|improve this answer


















  • 2




    for me, it is not working in bash (4.3.48).
    – RoVo
    Sep 11 at 6:53










  • Thanks, I made it clear that this answer is for sh. I don't use dash, so someone else might help.
    – RoVo
    Sep 11 at 6:58







  • 1




    "in Bash < 4.4"? Is there some reason to think that would work differently in Bash 4.4 or later?
    – ilkkachu
    Sep 11 at 8:16






  • 1




    @Stephen Kitt said earlier in a now deleted comment that the command works for him in 4.4.x. Also, OP reports that it works for him in bash. Unfortunately, I did not find sources for that...
    – RoVo
    Sep 11 at 8:19






  • 1




    I’m not sure what I was smoking earlier, the initial command doesn’t work for me on Bash 4.4 either now (and there’s nothing in the changes from 4.3 to 4.4 which would explain the difference in behaviour).
    – Stephen Kitt
    Sep 11 at 8:47


















up vote
2
down vote














in bash or zsh, I can use following syntax to read from pipe into variables.



echo AAA BBB | read X Y ; echo $X



No, you can't. Not in Bash with the default settings.



$ ./bash5.0-alpha -c 'echo AAA BBB | read X Y ; echo "Bash=$BASH_VERSION X="$X""'
Bash=5.0.0(1)-alpha X=""
$ bash -c 'echo AAA BBB | read X Y ; echo "Bash=$BASH_VERSION X="$X""'
Bash=4.4.12(1)-release X=""


Bash runs all the commands in a pipeline in separate subshell environments, so the changes to shell variables aren't visible outside the pipeline. Dash is similar here.



Zsh and ksh (AT&T implementations, not pdksh or derivatives) run the last command of the pipeline in the main shell environment, so there that works:



$ zsh -c 'echo AAA BBB | read X Y ; echo "Zsh=$ZSH_VERSION X="$X""'
Zsh=5.3.1 X="AAA"


In Bash, you can shopt -s lastpipe to have it do what ksh and zsh do (only works in non-interactive shells though):



$ bash -O lastpipe -c 'echo AAA BBB | read X Y ; echo "Bash=$BASH_VERSION X="$X""'
Bash=4.4.12(1)-release X="AAA"


But I don't think there's such an option for Dash.



In Bash you could also use process substitution instead of the pipe, but that's not an option in Dash either.




The workarounds would revolve around making the right-hand side of the loop a compound statement or a function, and so using the value read from the pipe in the same environment it was read in.



$ dash -c 'echo AAA BBB | read X Y ; echo "X="$X""; '
X="AAA"
$ dash -c 'f() read X Y ; echo "X="$X""; ; echo AAA BBB | f'
X="AAA"


Or use a here document:



read X Y << EOF
$(echo AAA BBB)
EOF





share|improve this answer





























    up vote
    0
    down vote













    No, this does not set X and Y (after the semicolon).




    echo AAA BBB | read X Y ; echo $X



    $ bash -c 'echo AAA BBB | read X Y ; echo "<$X>"'
    <>


    The same happens in dash.



    To get it to work in dash you need to resort to older solutions (here-doc):



    $ read X Y <<_EOT_
    > AAA BBB
    > _EOT_
    $ echo "<$X>"
    <AAA>


    As a command to try shells (sadly the newlines can not be removed (no one-liner)):



    $ bash -c 'read X Y <<_EOT_
    AAA BBB
    _EOT_
    echo "<$X>" '
    <AAA>


    That works exactly the same in dash, zsh, ksh, and many others:



    $ dash -c 'read X Y <<_EOT_
    AAA BBB
    _EOT_
    echo "<$X>" '
    <AAA>


    Newer alternatives (that do not work in dash) to the here-doc may be:




    1. here-string (works in bash, ksh, zsh):



      $ bash -c 'read X Y <<<"AAA BBB"; echo "<$X>" '
      <AAA>



    2. Process substitution (works in bash, ksh, zsh):



      $ bash -c 'read X Y < <(echo AAA BBB) ; echo "<$X>" '
      <AAA>


    An alternative that prints the value and works in dash, but does not keep the variable set in dash or bash (but does in ksh and zsh), is:




    1. Group command:



      $ dash -c 'echo "AAA BBB" | read X Y ; echo "<$X>"; ; echo "<$X>" '
      <AAA>
      <>


      Note that this last solution may be set to keep the variables set in bash with the lastpipe option (not for interactive use) or in ksh/zsh by default:



      $ bash -c 'shopt -s lastpipe;echo "AAA BBB"| read X Y;echo "1<$X>"; ;echo "2<$X>"'
      1<AAA>
      2<AAA>

      $ ksh -c 'echo "AAA BBB"| read X Y;echo "1<$X>"; ;echo "2<$X>"'
      1<AAA>
      2<AAA>

      $ zsh -c 'echo "AAA BBB"| read X Y;echo "1<$X>"; ; echo "2<$X>"'
      1<AAA>
      2<AAA>






    share|improve this answer






















    • Presumably, the OP is using the lastpipe option in bash. Try bash -O lastpipe -c 'echo AAA BBB | read X Y; echo "<$X>"'
      – Stéphane Chazelas
      Sep 11 at 9:50










    • @StéphaneChazelas Yes, the user may use (may be using) lastpipe, but I didn't read any confirmation of that. Details added anyway.
      – Isaac
      Sep 11 at 10:01

















    up vote
    -3
    down vote













    Be careful with variable assignments from a process in a pipeline. The POSIX standard does not require a specific behavior.



    Modern shells like ksh93 and recent versions of the Bourne Shell let the main shell be the parent of both processes in your pipeline and in case the rightmost process is a builtin command, this command is even run in the main shell.



    Another variant is to use the above method but to always run the rightmost command in another process.



    The old version is how the original Bourne Shell worked: The shell forks and the forked process creates all other proceses from the pipe and finally converts into the rightmost process.



    The last version needs a lot less code than the others but is slower. Because of the code size, this was used in 1976.



    The first variant is the fastest variant but needs more code than the others, but it it the only variant that runs the variable assignment in the orginal shell process, which is required to have the modified variable value in the main shell.






    share|improve this answer



























      4 Answers
      4






      active

      oldest

      votes








      4 Answers
      4






      active

      oldest

      votes









      active

      oldest

      votes






      active

      oldest

      votes








      up vote
      3
      down vote














      Why does the same not work in '/bin/sh' ?




      Assigning variables in a pipe does not work as expected in sh and bash because each command of a pipe runs in a subshell. Actually, the command does work, X and Y get declared, but they are not available outside the pipe.



      The following will work:



      echo AAA BBB | read X Y ; echo $X; 


      But in your case:



      try this,



      read X Y <<< "AAA BBB"


      or



      read X Y < <(echo "AAA BBB")



      Some useful links:



      • http://mywiki.wooledge.org/BashFAQ/024

      • bash: Assign variable from pipe?

      • Read values into a shell variable from a pipe





      share|improve this answer


















      • 2




        for me, it is not working in bash (4.3.48).
        – RoVo
        Sep 11 at 6:53










      • Thanks, I made it clear that this answer is for sh. I don't use dash, so someone else might help.
        – RoVo
        Sep 11 at 6:58







      • 1




        "in Bash < 4.4"? Is there some reason to think that would work differently in Bash 4.4 or later?
        – ilkkachu
        Sep 11 at 8:16






      • 1




        @Stephen Kitt said earlier in a now deleted comment that the command works for him in 4.4.x. Also, OP reports that it works for him in bash. Unfortunately, I did not find sources for that...
        – RoVo
        Sep 11 at 8:19






      • 1




        I’m not sure what I was smoking earlier, the initial command doesn’t work for me on Bash 4.4 either now (and there’s nothing in the changes from 4.3 to 4.4 which would explain the difference in behaviour).
        – Stephen Kitt
        Sep 11 at 8:47















      up vote
      3
      down vote














      Why does the same not work in '/bin/sh' ?




      Assigning variables in a pipe does not work as expected in sh and bash because each command of a pipe runs in a subshell. Actually, the command does work, X and Y get declared, but they are not available outside the pipe.



      The following will work:



      echo AAA BBB | read X Y ; echo $X; 


      But in your case:



      try this,



      read X Y <<< "AAA BBB"


      or



      read X Y < <(echo "AAA BBB")



      Some useful links:



      • http://mywiki.wooledge.org/BashFAQ/024

      • bash: Assign variable from pipe?

      • Read values into a shell variable from a pipe





      share|improve this answer


















      • 2




        for me, it is not working in bash (4.3.48).
        – RoVo
        Sep 11 at 6:53










      • Thanks, I made it clear that this answer is for sh. I don't use dash, so someone else might help.
        – RoVo
        Sep 11 at 6:58







      • 1




        "in Bash < 4.4"? Is there some reason to think that would work differently in Bash 4.4 or later?
        – ilkkachu
        Sep 11 at 8:16






      • 1




        @Stephen Kitt said earlier in a now deleted comment that the command works for him in 4.4.x. Also, OP reports that it works for him in bash. Unfortunately, I did not find sources for that...
        – RoVo
        Sep 11 at 8:19






      • 1




        I’m not sure what I was smoking earlier, the initial command doesn’t work for me on Bash 4.4 either now (and there’s nothing in the changes from 4.3 to 4.4 which would explain the difference in behaviour).
        – Stephen Kitt
        Sep 11 at 8:47













      up vote
      3
      down vote










      up vote
      3
      down vote










      Why does the same not work in '/bin/sh' ?




      Assigning variables in a pipe does not work as expected in sh and bash because each command of a pipe runs in a subshell. Actually, the command does work, X and Y get declared, but they are not available outside the pipe.



      The following will work:



      echo AAA BBB | read X Y ; echo $X; 


      But in your case:



      try this,



      read X Y <<< "AAA BBB"


      or



      read X Y < <(echo "AAA BBB")



      Some useful links:



      • http://mywiki.wooledge.org/BashFAQ/024

      • bash: Assign variable from pipe?

      • Read values into a shell variable from a pipe





      share|improve this answer















      Why does the same not work in '/bin/sh' ?




      Assigning variables in a pipe does not work as expected in sh and bash because each command of a pipe runs in a subshell. Actually, the command does work, X and Y get declared, but they are not available outside the pipe.



      The following will work:



      echo AAA BBB | read X Y ; echo $X; 


      But in your case:



      try this,



      read X Y <<< "AAA BBB"


      or



      read X Y < <(echo "AAA BBB")



      Some useful links:



      • http://mywiki.wooledge.org/BashFAQ/024

      • bash: Assign variable from pipe?

      • Read values into a shell variable from a pipe






      share|improve this answer














      share|improve this answer



      share|improve this answer








      edited Sep 11 at 8:48

























      answered Sep 11 at 6:48









      RoVo

      1,800213




      1,800213







      • 2




        for me, it is not working in bash (4.3.48).
        – RoVo
        Sep 11 at 6:53










      • Thanks, I made it clear that this answer is for sh. I don't use dash, so someone else might help.
        – RoVo
        Sep 11 at 6:58







      • 1




        "in Bash < 4.4"? Is there some reason to think that would work differently in Bash 4.4 or later?
        – ilkkachu
        Sep 11 at 8:16






      • 1




        @Stephen Kitt said earlier in a now deleted comment that the command works for him in 4.4.x. Also, OP reports that it works for him in bash. Unfortunately, I did not find sources for that...
        – RoVo
        Sep 11 at 8:19






      • 1




        I’m not sure what I was smoking earlier, the initial command doesn’t work for me on Bash 4.4 either now (and there’s nothing in the changes from 4.3 to 4.4 which would explain the difference in behaviour).
        – Stephen Kitt
        Sep 11 at 8:47













      • 2




        for me, it is not working in bash (4.3.48).
        – RoVo
        Sep 11 at 6:53










      • Thanks, I made it clear that this answer is for sh. I don't use dash, so someone else might help.
        – RoVo
        Sep 11 at 6:58







      • 1




        "in Bash < 4.4"? Is there some reason to think that would work differently in Bash 4.4 or later?
        – ilkkachu
        Sep 11 at 8:16






      • 1




        @Stephen Kitt said earlier in a now deleted comment that the command works for him in 4.4.x. Also, OP reports that it works for him in bash. Unfortunately, I did not find sources for that...
        – RoVo
        Sep 11 at 8:19






      • 1




        I’m not sure what I was smoking earlier, the initial command doesn’t work for me on Bash 4.4 either now (and there’s nothing in the changes from 4.3 to 4.4 which would explain the difference in behaviour).
        – Stephen Kitt
        Sep 11 at 8:47








      2




      2




      for me, it is not working in bash (4.3.48).
      – RoVo
      Sep 11 at 6:53




      for me, it is not working in bash (4.3.48).
      – RoVo
      Sep 11 at 6:53












      Thanks, I made it clear that this answer is for sh. I don't use dash, so someone else might help.
      – RoVo
      Sep 11 at 6:58





      Thanks, I made it clear that this answer is for sh. I don't use dash, so someone else might help.
      – RoVo
      Sep 11 at 6:58





      1




      1




      "in Bash < 4.4"? Is there some reason to think that would work differently in Bash 4.4 or later?
      – ilkkachu
      Sep 11 at 8:16




      "in Bash < 4.4"? Is there some reason to think that would work differently in Bash 4.4 or later?
      – ilkkachu
      Sep 11 at 8:16




      1




      1




      @Stephen Kitt said earlier in a now deleted comment that the command works for him in 4.4.x. Also, OP reports that it works for him in bash. Unfortunately, I did not find sources for that...
      – RoVo
      Sep 11 at 8:19




      @Stephen Kitt said earlier in a now deleted comment that the command works for him in 4.4.x. Also, OP reports that it works for him in bash. Unfortunately, I did not find sources for that...
      – RoVo
      Sep 11 at 8:19




      1




      1




      I’m not sure what I was smoking earlier, the initial command doesn’t work for me on Bash 4.4 either now (and there’s nothing in the changes from 4.3 to 4.4 which would explain the difference in behaviour).
      – Stephen Kitt
      Sep 11 at 8:47





      I’m not sure what I was smoking earlier, the initial command doesn’t work for me on Bash 4.4 either now (and there’s nothing in the changes from 4.3 to 4.4 which would explain the difference in behaviour).
      – Stephen Kitt
      Sep 11 at 8:47













      up vote
      2
      down vote














      in bash or zsh, I can use following syntax to read from pipe into variables.



      echo AAA BBB | read X Y ; echo $X



      No, you can't. Not in Bash with the default settings.



      $ ./bash5.0-alpha -c 'echo AAA BBB | read X Y ; echo "Bash=$BASH_VERSION X="$X""'
      Bash=5.0.0(1)-alpha X=""
      $ bash -c 'echo AAA BBB | read X Y ; echo "Bash=$BASH_VERSION X="$X""'
      Bash=4.4.12(1)-release X=""


      Bash runs all the commands in a pipeline in separate subshell environments, so the changes to shell variables aren't visible outside the pipeline. Dash is similar here.



      Zsh and ksh (AT&T implementations, not pdksh or derivatives) run the last command of the pipeline in the main shell environment, so there that works:



      $ zsh -c 'echo AAA BBB | read X Y ; echo "Zsh=$ZSH_VERSION X="$X""'
      Zsh=5.3.1 X="AAA"


      In Bash, you can shopt -s lastpipe to have it do what ksh and zsh do (only works in non-interactive shells though):



      $ bash -O lastpipe -c 'echo AAA BBB | read X Y ; echo "Bash=$BASH_VERSION X="$X""'
      Bash=4.4.12(1)-release X="AAA"


      But I don't think there's such an option for Dash.



      In Bash you could also use process substitution instead of the pipe, but that's not an option in Dash either.




      The workarounds would revolve around making the right-hand side of the loop a compound statement or a function, and so using the value read from the pipe in the same environment it was read in.



      $ dash -c 'echo AAA BBB | read X Y ; echo "X="$X""; '
      X="AAA"
      $ dash -c 'f() read X Y ; echo "X="$X""; ; echo AAA BBB | f'
      X="AAA"


      Or use a here document:



      read X Y << EOF
      $(echo AAA BBB)
      EOF





      share|improve this answer


























        up vote
        2
        down vote














        in bash or zsh, I can use following syntax to read from pipe into variables.



        echo AAA BBB | read X Y ; echo $X



        No, you can't. Not in Bash with the default settings.



        $ ./bash5.0-alpha -c 'echo AAA BBB | read X Y ; echo "Bash=$BASH_VERSION X="$X""'
        Bash=5.0.0(1)-alpha X=""
        $ bash -c 'echo AAA BBB | read X Y ; echo "Bash=$BASH_VERSION X="$X""'
        Bash=4.4.12(1)-release X=""


        Bash runs all the commands in a pipeline in separate subshell environments, so the changes to shell variables aren't visible outside the pipeline. Dash is similar here.



        Zsh and ksh (AT&T implementations, not pdksh or derivatives) run the last command of the pipeline in the main shell environment, so there that works:



        $ zsh -c 'echo AAA BBB | read X Y ; echo "Zsh=$ZSH_VERSION X="$X""'
        Zsh=5.3.1 X="AAA"


        In Bash, you can shopt -s lastpipe to have it do what ksh and zsh do (only works in non-interactive shells though):



        $ bash -O lastpipe -c 'echo AAA BBB | read X Y ; echo "Bash=$BASH_VERSION X="$X""'
        Bash=4.4.12(1)-release X="AAA"


        But I don't think there's such an option for Dash.



        In Bash you could also use process substitution instead of the pipe, but that's not an option in Dash either.




        The workarounds would revolve around making the right-hand side of the loop a compound statement or a function, and so using the value read from the pipe in the same environment it was read in.



        $ dash -c 'echo AAA BBB | read X Y ; echo "X="$X""; '
        X="AAA"
        $ dash -c 'f() read X Y ; echo "X="$X""; ; echo AAA BBB | f'
        X="AAA"


        Or use a here document:



        read X Y << EOF
        $(echo AAA BBB)
        EOF





        share|improve this answer
























          up vote
          2
          down vote










          up vote
          2
          down vote










          in bash or zsh, I can use following syntax to read from pipe into variables.



          echo AAA BBB | read X Y ; echo $X



          No, you can't. Not in Bash with the default settings.



          $ ./bash5.0-alpha -c 'echo AAA BBB | read X Y ; echo "Bash=$BASH_VERSION X="$X""'
          Bash=5.0.0(1)-alpha X=""
          $ bash -c 'echo AAA BBB | read X Y ; echo "Bash=$BASH_VERSION X="$X""'
          Bash=4.4.12(1)-release X=""


          Bash runs all the commands in a pipeline in separate subshell environments, so the changes to shell variables aren't visible outside the pipeline. Dash is similar here.



          Zsh and ksh (AT&T implementations, not pdksh or derivatives) run the last command of the pipeline in the main shell environment, so there that works:



          $ zsh -c 'echo AAA BBB | read X Y ; echo "Zsh=$ZSH_VERSION X="$X""'
          Zsh=5.3.1 X="AAA"


          In Bash, you can shopt -s lastpipe to have it do what ksh and zsh do (only works in non-interactive shells though):



          $ bash -O lastpipe -c 'echo AAA BBB | read X Y ; echo "Bash=$BASH_VERSION X="$X""'
          Bash=4.4.12(1)-release X="AAA"


          But I don't think there's such an option for Dash.



          In Bash you could also use process substitution instead of the pipe, but that's not an option in Dash either.




          The workarounds would revolve around making the right-hand side of the loop a compound statement or a function, and so using the value read from the pipe in the same environment it was read in.



          $ dash -c 'echo AAA BBB | read X Y ; echo "X="$X""; '
          X="AAA"
          $ dash -c 'f() read X Y ; echo "X="$X""; ; echo AAA BBB | f'
          X="AAA"


          Or use a here document:



          read X Y << EOF
          $(echo AAA BBB)
          EOF





          share|improve this answer















          in bash or zsh, I can use following syntax to read from pipe into variables.



          echo AAA BBB | read X Y ; echo $X



          No, you can't. Not in Bash with the default settings.



          $ ./bash5.0-alpha -c 'echo AAA BBB | read X Y ; echo "Bash=$BASH_VERSION X="$X""'
          Bash=5.0.0(1)-alpha X=""
          $ bash -c 'echo AAA BBB | read X Y ; echo "Bash=$BASH_VERSION X="$X""'
          Bash=4.4.12(1)-release X=""


          Bash runs all the commands in a pipeline in separate subshell environments, so the changes to shell variables aren't visible outside the pipeline. Dash is similar here.



          Zsh and ksh (AT&T implementations, not pdksh or derivatives) run the last command of the pipeline in the main shell environment, so there that works:



          $ zsh -c 'echo AAA BBB | read X Y ; echo "Zsh=$ZSH_VERSION X="$X""'
          Zsh=5.3.1 X="AAA"


          In Bash, you can shopt -s lastpipe to have it do what ksh and zsh do (only works in non-interactive shells though):



          $ bash -O lastpipe -c 'echo AAA BBB | read X Y ; echo "Bash=$BASH_VERSION X="$X""'
          Bash=4.4.12(1)-release X="AAA"


          But I don't think there's such an option for Dash.



          In Bash you could also use process substitution instead of the pipe, but that's not an option in Dash either.




          The workarounds would revolve around making the right-hand side of the loop a compound statement or a function, and so using the value read from the pipe in the same environment it was read in.



          $ dash -c 'echo AAA BBB | read X Y ; echo "X="$X""; '
          X="AAA"
          $ dash -c 'f() read X Y ; echo "X="$X""; ; echo AAA BBB | f'
          X="AAA"


          Or use a here document:



          read X Y << EOF
          $(echo AAA BBB)
          EOF






          share|improve this answer














          share|improve this answer



          share|improve this answer








          edited Sep 11 at 9:53









          Stéphane Chazelas

          286k53528867




          286k53528867










          answered Sep 11 at 8:27









          ilkkachu

          52.2k679144




          52.2k679144




















              up vote
              0
              down vote













              No, this does not set X and Y (after the semicolon).




              echo AAA BBB | read X Y ; echo $X



              $ bash -c 'echo AAA BBB | read X Y ; echo "<$X>"'
              <>


              The same happens in dash.



              To get it to work in dash you need to resort to older solutions (here-doc):



              $ read X Y <<_EOT_
              > AAA BBB
              > _EOT_
              $ echo "<$X>"
              <AAA>


              As a command to try shells (sadly the newlines can not be removed (no one-liner)):



              $ bash -c 'read X Y <<_EOT_
              AAA BBB
              _EOT_
              echo "<$X>" '
              <AAA>


              That works exactly the same in dash, zsh, ksh, and many others:



              $ dash -c 'read X Y <<_EOT_
              AAA BBB
              _EOT_
              echo "<$X>" '
              <AAA>


              Newer alternatives (that do not work in dash) to the here-doc may be:




              1. here-string (works in bash, ksh, zsh):



                $ bash -c 'read X Y <<<"AAA BBB"; echo "<$X>" '
                <AAA>



              2. Process substitution (works in bash, ksh, zsh):



                $ bash -c 'read X Y < <(echo AAA BBB) ; echo "<$X>" '
                <AAA>


              An alternative that prints the value and works in dash, but does not keep the variable set in dash or bash (but does in ksh and zsh), is:




              1. Group command:



                $ dash -c 'echo "AAA BBB" | read X Y ; echo "<$X>"; ; echo "<$X>" '
                <AAA>
                <>


                Note that this last solution may be set to keep the variables set in bash with the lastpipe option (not for interactive use) or in ksh/zsh by default:



                $ bash -c 'shopt -s lastpipe;echo "AAA BBB"| read X Y;echo "1<$X>"; ;echo "2<$X>"'
                1<AAA>
                2<AAA>

                $ ksh -c 'echo "AAA BBB"| read X Y;echo "1<$X>"; ;echo "2<$X>"'
                1<AAA>
                2<AAA>

                $ zsh -c 'echo "AAA BBB"| read X Y;echo "1<$X>"; ; echo "2<$X>"'
                1<AAA>
                2<AAA>






              share|improve this answer






















              • Presumably, the OP is using the lastpipe option in bash. Try bash -O lastpipe -c 'echo AAA BBB | read X Y; echo "<$X>"'
                – Stéphane Chazelas
                Sep 11 at 9:50










              • @StéphaneChazelas Yes, the user may use (may be using) lastpipe, but I didn't read any confirmation of that. Details added anyway.
                – Isaac
                Sep 11 at 10:01














              up vote
              0
              down vote













              No, this does not set X and Y (after the semicolon).




              echo AAA BBB | read X Y ; echo $X



              $ bash -c 'echo AAA BBB | read X Y ; echo "<$X>"'
              <>


              The same happens in dash.



              To get it to work in dash you need to resort to older solutions (here-doc):



              $ read X Y <<_EOT_
              > AAA BBB
              > _EOT_
              $ echo "<$X>"
              <AAA>


              As a command to try shells (sadly the newlines can not be removed (no one-liner)):



              $ bash -c 'read X Y <<_EOT_
              AAA BBB
              _EOT_
              echo "<$X>" '
              <AAA>


              That works exactly the same in dash, zsh, ksh, and many others:



              $ dash -c 'read X Y <<_EOT_
              AAA BBB
              _EOT_
              echo "<$X>" '
              <AAA>


              Newer alternatives (that do not work in dash) to the here-doc may be:




              1. here-string (works in bash, ksh, zsh):



                $ bash -c 'read X Y <<<"AAA BBB"; echo "<$X>" '
                <AAA>



              2. Process substitution (works in bash, ksh, zsh):



                $ bash -c 'read X Y < <(echo AAA BBB) ; echo "<$X>" '
                <AAA>


              An alternative that prints the value and works in dash, but does not keep the variable set in dash or bash (but does in ksh and zsh), is:




              1. Group command:



                $ dash -c 'echo "AAA BBB" | read X Y ; echo "<$X>"; ; echo "<$X>" '
                <AAA>
                <>


                Note that this last solution may be set to keep the variables set in bash with the lastpipe option (not for interactive use) or in ksh/zsh by default:



                $ bash -c 'shopt -s lastpipe;echo "AAA BBB"| read X Y;echo "1<$X>"; ;echo "2<$X>"'
                1<AAA>
                2<AAA>

                $ ksh -c 'echo "AAA BBB"| read X Y;echo "1<$X>"; ;echo "2<$X>"'
                1<AAA>
                2<AAA>

                $ zsh -c 'echo "AAA BBB"| read X Y;echo "1<$X>"; ; echo "2<$X>"'
                1<AAA>
                2<AAA>






              share|improve this answer






















              • Presumably, the OP is using the lastpipe option in bash. Try bash -O lastpipe -c 'echo AAA BBB | read X Y; echo "<$X>"'
                – Stéphane Chazelas
                Sep 11 at 9:50










              • @StéphaneChazelas Yes, the user may use (may be using) lastpipe, but I didn't read any confirmation of that. Details added anyway.
                – Isaac
                Sep 11 at 10:01












              up vote
              0
              down vote










              up vote
              0
              down vote









              No, this does not set X and Y (after the semicolon).




              echo AAA BBB | read X Y ; echo $X



              $ bash -c 'echo AAA BBB | read X Y ; echo "<$X>"'
              <>


              The same happens in dash.



              To get it to work in dash you need to resort to older solutions (here-doc):



              $ read X Y <<_EOT_
              > AAA BBB
              > _EOT_
              $ echo "<$X>"
              <AAA>


              As a command to try shells (sadly the newlines can not be removed (no one-liner)):



              $ bash -c 'read X Y <<_EOT_
              AAA BBB
              _EOT_
              echo "<$X>" '
              <AAA>


              That works exactly the same in dash, zsh, ksh, and many others:



              $ dash -c 'read X Y <<_EOT_
              AAA BBB
              _EOT_
              echo "<$X>" '
              <AAA>


              Newer alternatives (that do not work in dash) to the here-doc may be:




              1. here-string (works in bash, ksh, zsh):



                $ bash -c 'read X Y <<<"AAA BBB"; echo "<$X>" '
                <AAA>



              2. Process substitution (works in bash, ksh, zsh):



                $ bash -c 'read X Y < <(echo AAA BBB) ; echo "<$X>" '
                <AAA>


              An alternative that prints the value and works in dash, but does not keep the variable set in dash or bash (but does in ksh and zsh), is:




              1. Group command:



                $ dash -c 'echo "AAA BBB" | read X Y ; echo "<$X>"; ; echo "<$X>" '
                <AAA>
                <>


                Note that this last solution may be set to keep the variables set in bash with the lastpipe option (not for interactive use) or in ksh/zsh by default:



                $ bash -c 'shopt -s lastpipe;echo "AAA BBB"| read X Y;echo "1<$X>"; ;echo "2<$X>"'
                1<AAA>
                2<AAA>

                $ ksh -c 'echo "AAA BBB"| read X Y;echo "1<$X>"; ;echo "2<$X>"'
                1<AAA>
                2<AAA>

                $ zsh -c 'echo "AAA BBB"| read X Y;echo "1<$X>"; ; echo "2<$X>"'
                1<AAA>
                2<AAA>






              share|improve this answer














              No, this does not set X and Y (after the semicolon).




              echo AAA BBB | read X Y ; echo $X



              $ bash -c 'echo AAA BBB | read X Y ; echo "<$X>"'
              <>


              The same happens in dash.



              To get it to work in dash you need to resort to older solutions (here-doc):



              $ read X Y <<_EOT_
              > AAA BBB
              > _EOT_
              $ echo "<$X>"
              <AAA>


              As a command to try shells (sadly the newlines can not be removed (no one-liner)):



              $ bash -c 'read X Y <<_EOT_
              AAA BBB
              _EOT_
              echo "<$X>" '
              <AAA>


              That works exactly the same in dash, zsh, ksh, and many others:



              $ dash -c 'read X Y <<_EOT_
              AAA BBB
              _EOT_
              echo "<$X>" '
              <AAA>


              Newer alternatives (that do not work in dash) to the here-doc may be:




              1. here-string (works in bash, ksh, zsh):



                $ bash -c 'read X Y <<<"AAA BBB"; echo "<$X>" '
                <AAA>



              2. Process substitution (works in bash, ksh, zsh):



                $ bash -c 'read X Y < <(echo AAA BBB) ; echo "<$X>" '
                <AAA>


              An alternative that prints the value and works in dash, but does not keep the variable set in dash or bash (but does in ksh and zsh), is:




              1. Group command:



                $ dash -c 'echo "AAA BBB" | read X Y ; echo "<$X>"; ; echo "<$X>" '
                <AAA>
                <>


                Note that this last solution may be set to keep the variables set in bash with the lastpipe option (not for interactive use) or in ksh/zsh by default:



                $ bash -c 'shopt -s lastpipe;echo "AAA BBB"| read X Y;echo "1<$X>"; ;echo "2<$X>"'
                1<AAA>
                2<AAA>

                $ ksh -c 'echo "AAA BBB"| read X Y;echo "1<$X>"; ;echo "2<$X>"'
                1<AAA>
                2<AAA>

                $ zsh -c 'echo "AAA BBB"| read X Y;echo "1<$X>"; ; echo "2<$X>"'
                1<AAA>
                2<AAA>







              share|improve this answer














              share|improve this answer



              share|improve this answer








              edited Sep 11 at 11:05









              ctrl-alt-delor

              9,20431948




              9,20431948










              answered Sep 11 at 9:43









              Isaac

              7,28911035




              7,28911035











              • Presumably, the OP is using the lastpipe option in bash. Try bash -O lastpipe -c 'echo AAA BBB | read X Y; echo "<$X>"'
                – Stéphane Chazelas
                Sep 11 at 9:50










              • @StéphaneChazelas Yes, the user may use (may be using) lastpipe, but I didn't read any confirmation of that. Details added anyway.
                – Isaac
                Sep 11 at 10:01
















              • Presumably, the OP is using the lastpipe option in bash. Try bash -O lastpipe -c 'echo AAA BBB | read X Y; echo "<$X>"'
                – Stéphane Chazelas
                Sep 11 at 9:50










              • @StéphaneChazelas Yes, the user may use (may be using) lastpipe, but I didn't read any confirmation of that. Details added anyway.
                – Isaac
                Sep 11 at 10:01















              Presumably, the OP is using the lastpipe option in bash. Try bash -O lastpipe -c 'echo AAA BBB | read X Y; echo "<$X>"'
              – Stéphane Chazelas
              Sep 11 at 9:50




              Presumably, the OP is using the lastpipe option in bash. Try bash -O lastpipe -c 'echo AAA BBB | read X Y; echo "<$X>"'
              – Stéphane Chazelas
              Sep 11 at 9:50












              @StéphaneChazelas Yes, the user may use (may be using) lastpipe, but I didn't read any confirmation of that. Details added anyway.
              – Isaac
              Sep 11 at 10:01




              @StéphaneChazelas Yes, the user may use (may be using) lastpipe, but I didn't read any confirmation of that. Details added anyway.
              – Isaac
              Sep 11 at 10:01










              up vote
              -3
              down vote













              Be careful with variable assignments from a process in a pipeline. The POSIX standard does not require a specific behavior.



              Modern shells like ksh93 and recent versions of the Bourne Shell let the main shell be the parent of both processes in your pipeline and in case the rightmost process is a builtin command, this command is even run in the main shell.



              Another variant is to use the above method but to always run the rightmost command in another process.



              The old version is how the original Bourne Shell worked: The shell forks and the forked process creates all other proceses from the pipe and finally converts into the rightmost process.



              The last version needs a lot less code than the others but is slower. Because of the code size, this was used in 1976.



              The first variant is the fastest variant but needs more code than the others, but it it the only variant that runs the variable assignment in the orginal shell process, which is required to have the modified variable value in the main shell.






              share|improve this answer
























                up vote
                -3
                down vote













                Be careful with variable assignments from a process in a pipeline. The POSIX standard does not require a specific behavior.



                Modern shells like ksh93 and recent versions of the Bourne Shell let the main shell be the parent of both processes in your pipeline and in case the rightmost process is a builtin command, this command is even run in the main shell.



                Another variant is to use the above method but to always run the rightmost command in another process.



                The old version is how the original Bourne Shell worked: The shell forks and the forked process creates all other proceses from the pipe and finally converts into the rightmost process.



                The last version needs a lot less code than the others but is slower. Because of the code size, this was used in 1976.



                The first variant is the fastest variant but needs more code than the others, but it it the only variant that runs the variable assignment in the orginal shell process, which is required to have the modified variable value in the main shell.






                share|improve this answer






















                  up vote
                  -3
                  down vote










                  up vote
                  -3
                  down vote









                  Be careful with variable assignments from a process in a pipeline. The POSIX standard does not require a specific behavior.



                  Modern shells like ksh93 and recent versions of the Bourne Shell let the main shell be the parent of both processes in your pipeline and in case the rightmost process is a builtin command, this command is even run in the main shell.



                  Another variant is to use the above method but to always run the rightmost command in another process.



                  The old version is how the original Bourne Shell worked: The shell forks and the forked process creates all other proceses from the pipe and finally converts into the rightmost process.



                  The last version needs a lot less code than the others but is slower. Because of the code size, this was used in 1976.



                  The first variant is the fastest variant but needs more code than the others, but it it the only variant that runs the variable assignment in the orginal shell process, which is required to have the modified variable value in the main shell.






                  share|improve this answer












                  Be careful with variable assignments from a process in a pipeline. The POSIX standard does not require a specific behavior.



                  Modern shells like ksh93 and recent versions of the Bourne Shell let the main shell be the parent of both processes in your pipeline and in case the rightmost process is a builtin command, this command is even run in the main shell.



                  Another variant is to use the above method but to always run the rightmost command in another process.



                  The old version is how the original Bourne Shell worked: The shell forks and the forked process creates all other proceses from the pipe and finally converts into the rightmost process.



                  The last version needs a lot less code than the others but is slower. Because of the code size, this was used in 1976.



                  The first variant is the fastest variant but needs more code than the others, but it it the only variant that runs the variable assignment in the orginal shell process, which is required to have the modified variable value in the main shell.







                  share|improve this answer












                  share|improve this answer



                  share|improve this answer










                  answered Sep 11 at 7:45









                  schily

                  9,64131537




                  9,64131537












                      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