in bash, read after a pipe is not setting values












17















Edit : original title was "read fails in bash"



With ksh I'm using read as a convenient way to separate values:



$ echo 1 2 3 4 5 | read a b dump
$ echo $b $a
2 1
$


But it fails in bash :



$ echo 1 2 3 4 5 | read a b dump
$ echo $b $a

$


I didn't find a reason in the man page why it fails, any idea ?










share|improve this question




















  • 1





    This is discussed (somewhat obscurely) in page 024 of Greg’s Bash FAQ.

    – Scott
    Jul 11 '14 at 18:27
















17















Edit : original title was "read fails in bash"



With ksh I'm using read as a convenient way to separate values:



$ echo 1 2 3 4 5 | read a b dump
$ echo $b $a
2 1
$


But it fails in bash :



$ echo 1 2 3 4 5 | read a b dump
$ echo $b $a

$


I didn't find a reason in the man page why it fails, any idea ?










share|improve this question




















  • 1





    This is discussed (somewhat obscurely) in page 024 of Greg’s Bash FAQ.

    – Scott
    Jul 11 '14 at 18:27














17












17








17


2






Edit : original title was "read fails in bash"



With ksh I'm using read as a convenient way to separate values:



$ echo 1 2 3 4 5 | read a b dump
$ echo $b $a
2 1
$


But it fails in bash :



$ echo 1 2 3 4 5 | read a b dump
$ echo $b $a

$


I didn't find a reason in the man page why it fails, any idea ?










share|improve this question
















Edit : original title was "read fails in bash"



With ksh I'm using read as a convenient way to separate values:



$ echo 1 2 3 4 5 | read a b dump
$ echo $b $a
2 1
$


But it fails in bash :



$ echo 1 2 3 4 5 | read a b dump
$ echo $b $a

$


I didn't find a reason in the man page why it fails, any idea ?







bash shell pipe read






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited Oct 21 '18 at 10:52









Gilles

534k12810741594




534k12810741594










asked Jul 11 '14 at 10:34









EmmanuelEmmanuel

3,03411120




3,03411120








  • 1





    This is discussed (somewhat obscurely) in page 024 of Greg’s Bash FAQ.

    – Scott
    Jul 11 '14 at 18:27














  • 1





    This is discussed (somewhat obscurely) in page 024 of Greg’s Bash FAQ.

    – Scott
    Jul 11 '14 at 18:27








1




1





This is discussed (somewhat obscurely) in page 024 of Greg’s Bash FAQ.

– Scott
Jul 11 '14 at 18:27





This is discussed (somewhat obscurely) in page 024 of Greg’s Bash FAQ.

– Scott
Jul 11 '14 at 18:27










2 Answers
2






active

oldest

votes


















22














bash runs the right-hand side of a pipeline in a subshell context, so changes to variables (which is what read does) are not preserved — they die when the subshell does, at the end of the command.



Instead, you can use process substitution:



$ read a b dump < <(echo 1 2 3 4 5)
$ echo $b $a
2 1


In this case, read is running within our primary shell, and our output-producing command runs in the subshell. The <(...) syntax creates a subshell and connects its output to a pipe, which we redirect into the input of read with the ordinary < operation. Because read ran in our main shell the variables are set correctly.



As pointed out in a comment, if your goal is literally to split a string into variables somehow, you can use a here string:



read a b dump <<<"1 2 3 4 5"


I assume there's more to it than that, but this is a better option if there isn't.






share|improve this answer



















  • 3





    Or even read a b dump <<< '1 2 3 4 5'.

    – choroba
    Jul 11 '14 at 10:41











  • Thank you to all, btw I noted that mksh (on cygwin) is doing the same as bash.

    – Emmanuel
    Jul 11 '14 at 10:56











  • @Michael Homer Good explanation! I found another one example that can explain that every command in pipeline run in own subshell: cat /etc/passwd | (read -r line ; echo $line). But next echo of $line which is not in pipeline put nothing on screen, because value was existed just between parentheses (subshell) . Hope, It helps someone.

    – Yurij Goncharuk
    May 3 '18 at 10:28





















14














This is not a bash bug as POSIX allows both bash and ksh behaviors, leading to the unfortunate discrepancy you are observing.



http://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_12



Additionally, each command of a multi-command pipeline is in a subshell environment; as an extension, however, any or all commands in a pipeline may be executed in the current environment. All other commands shall be executed in the current shell environment.



However, with bash 4.2 and newer, you can set the lastpipe option in non interactive scripts to get the expected result, eg:



#!/bin/bash

echo 1 2 3 4 5 | read a b dump
echo before: $b $a
shopt -s lastpipe
echo 1 2 3 4 5 | read a b dump
echo after: $b $a


Output:



before:
after: 2 1





share|improve this answer





















  • 1





    +1 thank you for the "lastpipe" info. sorry for the delay

    – Emmanuel
    Jul 29 '14 at 14:47






  • 1





    the problem with lastpipe is that it doesn't work in other shells (e.g. dash). there's basically no way to do this portable short of running everything in that subshell, see stackoverflow.com/questions/36268479/…

    – anarcat
    Feb 8 '17 at 15:46






  • 1





    @anarcat This is correct but the question asked here was about bash.

    – jlliagre
    Feb 8 '17 at 15:49











  • @anarcat: This may change in the future since there is a wish to change POSIX for another reason (PIPE Status) see here: unix.stackexchange.com/questions/476834/… Changing other shells is not trivial, it took me several months to rewrite the parser and interpeter on the Bourne Shell (bosh) to implement the faster behavior of the modern ksh.

    – schily
    Oct 21 '18 at 13:42













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',
autoActivateHeartbeat: false,
convertImagesToLinks: false,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: null,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
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%2f143958%2fin-bash-read-after-a-pipe-is-not-setting-values%23new-answer', 'question_page');
}
);

Post as a guest















Required, but never shown

























2 Answers
2






active

oldest

votes








2 Answers
2






active

oldest

votes









active

oldest

votes






active

oldest

votes









22














bash runs the right-hand side of a pipeline in a subshell context, so changes to variables (which is what read does) are not preserved — they die when the subshell does, at the end of the command.



Instead, you can use process substitution:



$ read a b dump < <(echo 1 2 3 4 5)
$ echo $b $a
2 1


In this case, read is running within our primary shell, and our output-producing command runs in the subshell. The <(...) syntax creates a subshell and connects its output to a pipe, which we redirect into the input of read with the ordinary < operation. Because read ran in our main shell the variables are set correctly.



As pointed out in a comment, if your goal is literally to split a string into variables somehow, you can use a here string:



read a b dump <<<"1 2 3 4 5"


I assume there's more to it than that, but this is a better option if there isn't.






share|improve this answer



















  • 3





    Or even read a b dump <<< '1 2 3 4 5'.

    – choroba
    Jul 11 '14 at 10:41











  • Thank you to all, btw I noted that mksh (on cygwin) is doing the same as bash.

    – Emmanuel
    Jul 11 '14 at 10:56











  • @Michael Homer Good explanation! I found another one example that can explain that every command in pipeline run in own subshell: cat /etc/passwd | (read -r line ; echo $line). But next echo of $line which is not in pipeline put nothing on screen, because value was existed just between parentheses (subshell) . Hope, It helps someone.

    – Yurij Goncharuk
    May 3 '18 at 10:28


















22














bash runs the right-hand side of a pipeline in a subshell context, so changes to variables (which is what read does) are not preserved — they die when the subshell does, at the end of the command.



Instead, you can use process substitution:



$ read a b dump < <(echo 1 2 3 4 5)
$ echo $b $a
2 1


In this case, read is running within our primary shell, and our output-producing command runs in the subshell. The <(...) syntax creates a subshell and connects its output to a pipe, which we redirect into the input of read with the ordinary < operation. Because read ran in our main shell the variables are set correctly.



As pointed out in a comment, if your goal is literally to split a string into variables somehow, you can use a here string:



read a b dump <<<"1 2 3 4 5"


I assume there's more to it than that, but this is a better option if there isn't.






share|improve this answer



















  • 3





    Or even read a b dump <<< '1 2 3 4 5'.

    – choroba
    Jul 11 '14 at 10:41











  • Thank you to all, btw I noted that mksh (on cygwin) is doing the same as bash.

    – Emmanuel
    Jul 11 '14 at 10:56











  • @Michael Homer Good explanation! I found another one example that can explain that every command in pipeline run in own subshell: cat /etc/passwd | (read -r line ; echo $line). But next echo of $line which is not in pipeline put nothing on screen, because value was existed just between parentheses (subshell) . Hope, It helps someone.

    – Yurij Goncharuk
    May 3 '18 at 10:28
















22












22








22







bash runs the right-hand side of a pipeline in a subshell context, so changes to variables (which is what read does) are not preserved — they die when the subshell does, at the end of the command.



Instead, you can use process substitution:



$ read a b dump < <(echo 1 2 3 4 5)
$ echo $b $a
2 1


In this case, read is running within our primary shell, and our output-producing command runs in the subshell. The <(...) syntax creates a subshell and connects its output to a pipe, which we redirect into the input of read with the ordinary < operation. Because read ran in our main shell the variables are set correctly.



As pointed out in a comment, if your goal is literally to split a string into variables somehow, you can use a here string:



read a b dump <<<"1 2 3 4 5"


I assume there's more to it than that, but this is a better option if there isn't.






share|improve this answer













bash runs the right-hand side of a pipeline in a subshell context, so changes to variables (which is what read does) are not preserved — they die when the subshell does, at the end of the command.



Instead, you can use process substitution:



$ read a b dump < <(echo 1 2 3 4 5)
$ echo $b $a
2 1


In this case, read is running within our primary shell, and our output-producing command runs in the subshell. The <(...) syntax creates a subshell and connects its output to a pipe, which we redirect into the input of read with the ordinary < operation. Because read ran in our main shell the variables are set correctly.



As pointed out in a comment, if your goal is literally to split a string into variables somehow, you can use a here string:



read a b dump <<<"1 2 3 4 5"


I assume there's more to it than that, but this is a better option if there isn't.







share|improve this answer












share|improve this answer



share|improve this answer










answered Jul 11 '14 at 10:40









Michael HomerMichael Homer

47.3k8124162




47.3k8124162








  • 3





    Or even read a b dump <<< '1 2 3 4 5'.

    – choroba
    Jul 11 '14 at 10:41











  • Thank you to all, btw I noted that mksh (on cygwin) is doing the same as bash.

    – Emmanuel
    Jul 11 '14 at 10:56











  • @Michael Homer Good explanation! I found another one example that can explain that every command in pipeline run in own subshell: cat /etc/passwd | (read -r line ; echo $line). But next echo of $line which is not in pipeline put nothing on screen, because value was existed just between parentheses (subshell) . Hope, It helps someone.

    – Yurij Goncharuk
    May 3 '18 at 10:28
















  • 3





    Or even read a b dump <<< '1 2 3 4 5'.

    – choroba
    Jul 11 '14 at 10:41











  • Thank you to all, btw I noted that mksh (on cygwin) is doing the same as bash.

    – Emmanuel
    Jul 11 '14 at 10:56











  • @Michael Homer Good explanation! I found another one example that can explain that every command in pipeline run in own subshell: cat /etc/passwd | (read -r line ; echo $line). But next echo of $line which is not in pipeline put nothing on screen, because value was existed just between parentheses (subshell) . Hope, It helps someone.

    – Yurij Goncharuk
    May 3 '18 at 10:28










3




3





Or even read a b dump <<< '1 2 3 4 5'.

– choroba
Jul 11 '14 at 10:41





Or even read a b dump <<< '1 2 3 4 5'.

– choroba
Jul 11 '14 at 10:41













Thank you to all, btw I noted that mksh (on cygwin) is doing the same as bash.

– Emmanuel
Jul 11 '14 at 10:56





Thank you to all, btw I noted that mksh (on cygwin) is doing the same as bash.

– Emmanuel
Jul 11 '14 at 10:56













@Michael Homer Good explanation! I found another one example that can explain that every command in pipeline run in own subshell: cat /etc/passwd | (read -r line ; echo $line). But next echo of $line which is not in pipeline put nothing on screen, because value was existed just between parentheses (subshell) . Hope, It helps someone.

– Yurij Goncharuk
May 3 '18 at 10:28







@Michael Homer Good explanation! I found another one example that can explain that every command in pipeline run in own subshell: cat /etc/passwd | (read -r line ; echo $line). But next echo of $line which is not in pipeline put nothing on screen, because value was existed just between parentheses (subshell) . Hope, It helps someone.

– Yurij Goncharuk
May 3 '18 at 10:28















14














This is not a bash bug as POSIX allows both bash and ksh behaviors, leading to the unfortunate discrepancy you are observing.



http://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_12



Additionally, each command of a multi-command pipeline is in a subshell environment; as an extension, however, any or all commands in a pipeline may be executed in the current environment. All other commands shall be executed in the current shell environment.



However, with bash 4.2 and newer, you can set the lastpipe option in non interactive scripts to get the expected result, eg:



#!/bin/bash

echo 1 2 3 4 5 | read a b dump
echo before: $b $a
shopt -s lastpipe
echo 1 2 3 4 5 | read a b dump
echo after: $b $a


Output:



before:
after: 2 1





share|improve this answer





















  • 1





    +1 thank you for the "lastpipe" info. sorry for the delay

    – Emmanuel
    Jul 29 '14 at 14:47






  • 1





    the problem with lastpipe is that it doesn't work in other shells (e.g. dash). there's basically no way to do this portable short of running everything in that subshell, see stackoverflow.com/questions/36268479/…

    – anarcat
    Feb 8 '17 at 15:46






  • 1





    @anarcat This is correct but the question asked here was about bash.

    – jlliagre
    Feb 8 '17 at 15:49











  • @anarcat: This may change in the future since there is a wish to change POSIX for another reason (PIPE Status) see here: unix.stackexchange.com/questions/476834/… Changing other shells is not trivial, it took me several months to rewrite the parser and interpeter on the Bourne Shell (bosh) to implement the faster behavior of the modern ksh.

    – schily
    Oct 21 '18 at 13:42


















14














This is not a bash bug as POSIX allows both bash and ksh behaviors, leading to the unfortunate discrepancy you are observing.



http://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_12



Additionally, each command of a multi-command pipeline is in a subshell environment; as an extension, however, any or all commands in a pipeline may be executed in the current environment. All other commands shall be executed in the current shell environment.



However, with bash 4.2 and newer, you can set the lastpipe option in non interactive scripts to get the expected result, eg:



#!/bin/bash

echo 1 2 3 4 5 | read a b dump
echo before: $b $a
shopt -s lastpipe
echo 1 2 3 4 5 | read a b dump
echo after: $b $a


Output:



before:
after: 2 1





share|improve this answer





















  • 1





    +1 thank you for the "lastpipe" info. sorry for the delay

    – Emmanuel
    Jul 29 '14 at 14:47






  • 1





    the problem with lastpipe is that it doesn't work in other shells (e.g. dash). there's basically no way to do this portable short of running everything in that subshell, see stackoverflow.com/questions/36268479/…

    – anarcat
    Feb 8 '17 at 15:46






  • 1





    @anarcat This is correct but the question asked here was about bash.

    – jlliagre
    Feb 8 '17 at 15:49











  • @anarcat: This may change in the future since there is a wish to change POSIX for another reason (PIPE Status) see here: unix.stackexchange.com/questions/476834/… Changing other shells is not trivial, it took me several months to rewrite the parser and interpeter on the Bourne Shell (bosh) to implement the faster behavior of the modern ksh.

    – schily
    Oct 21 '18 at 13:42
















14












14








14







This is not a bash bug as POSIX allows both bash and ksh behaviors, leading to the unfortunate discrepancy you are observing.



http://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_12



Additionally, each command of a multi-command pipeline is in a subshell environment; as an extension, however, any or all commands in a pipeline may be executed in the current environment. All other commands shall be executed in the current shell environment.



However, with bash 4.2 and newer, you can set the lastpipe option in non interactive scripts to get the expected result, eg:



#!/bin/bash

echo 1 2 3 4 5 | read a b dump
echo before: $b $a
shopt -s lastpipe
echo 1 2 3 4 5 | read a b dump
echo after: $b $a


Output:



before:
after: 2 1





share|improve this answer















This is not a bash bug as POSIX allows both bash and ksh behaviors, leading to the unfortunate discrepancy you are observing.



http://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_12



Additionally, each command of a multi-command pipeline is in a subshell environment; as an extension, however, any or all commands in a pipeline may be executed in the current environment. All other commands shall be executed in the current shell environment.



However, with bash 4.2 and newer, you can set the lastpipe option in non interactive scripts to get the expected result, eg:



#!/bin/bash

echo 1 2 3 4 5 | read a b dump
echo before: $b $a
shopt -s lastpipe
echo 1 2 3 4 5 | read a b dump
echo after: $b $a


Output:



before:
after: 2 1






share|improve this answer














share|improve this answer



share|improve this answer








edited Jul 12 '14 at 9:25

























answered Jul 12 '14 at 9:18









jlliagrejlliagre

46.9k783133




46.9k783133








  • 1





    +1 thank you for the "lastpipe" info. sorry for the delay

    – Emmanuel
    Jul 29 '14 at 14:47






  • 1





    the problem with lastpipe is that it doesn't work in other shells (e.g. dash). there's basically no way to do this portable short of running everything in that subshell, see stackoverflow.com/questions/36268479/…

    – anarcat
    Feb 8 '17 at 15:46






  • 1





    @anarcat This is correct but the question asked here was about bash.

    – jlliagre
    Feb 8 '17 at 15:49











  • @anarcat: This may change in the future since there is a wish to change POSIX for another reason (PIPE Status) see here: unix.stackexchange.com/questions/476834/… Changing other shells is not trivial, it took me several months to rewrite the parser and interpeter on the Bourne Shell (bosh) to implement the faster behavior of the modern ksh.

    – schily
    Oct 21 '18 at 13:42
















  • 1





    +1 thank you for the "lastpipe" info. sorry for the delay

    – Emmanuel
    Jul 29 '14 at 14:47






  • 1





    the problem with lastpipe is that it doesn't work in other shells (e.g. dash). there's basically no way to do this portable short of running everything in that subshell, see stackoverflow.com/questions/36268479/…

    – anarcat
    Feb 8 '17 at 15:46






  • 1





    @anarcat This is correct but the question asked here was about bash.

    – jlliagre
    Feb 8 '17 at 15:49











  • @anarcat: This may change in the future since there is a wish to change POSIX for another reason (PIPE Status) see here: unix.stackexchange.com/questions/476834/… Changing other shells is not trivial, it took me several months to rewrite the parser and interpeter on the Bourne Shell (bosh) to implement the faster behavior of the modern ksh.

    – schily
    Oct 21 '18 at 13:42










1




1





+1 thank you for the "lastpipe" info. sorry for the delay

– Emmanuel
Jul 29 '14 at 14:47





+1 thank you for the "lastpipe" info. sorry for the delay

– Emmanuel
Jul 29 '14 at 14:47




1




1





the problem with lastpipe is that it doesn't work in other shells (e.g. dash). there's basically no way to do this portable short of running everything in that subshell, see stackoverflow.com/questions/36268479/…

– anarcat
Feb 8 '17 at 15:46





the problem with lastpipe is that it doesn't work in other shells (e.g. dash). there's basically no way to do this portable short of running everything in that subshell, see stackoverflow.com/questions/36268479/…

– anarcat
Feb 8 '17 at 15:46




1




1





@anarcat This is correct but the question asked here was about bash.

– jlliagre
Feb 8 '17 at 15:49





@anarcat This is correct but the question asked here was about bash.

– jlliagre
Feb 8 '17 at 15:49













@anarcat: This may change in the future since there is a wish to change POSIX for another reason (PIPE Status) see here: unix.stackexchange.com/questions/476834/… Changing other shells is not trivial, it took me several months to rewrite the parser and interpeter on the Bourne Shell (bosh) to implement the faster behavior of the modern ksh.

– schily
Oct 21 '18 at 13:42







@anarcat: This may change in the future since there is a wish to change POSIX for another reason (PIPE Status) see here: unix.stackexchange.com/questions/476834/… Changing other shells is not trivial, it took me several months to rewrite the parser and interpeter on the Bourne Shell (bosh) to implement the faster behavior of the modern ksh.

– schily
Oct 21 '18 at 13:42




















draft saved

draft discarded




















































Thanks for contributing an answer to Unix & Linux Stack Exchange!


  • Please be sure to answer the question. Provide details and share your research!

But avoid



  • Asking for help, clarification, or responding to other answers.

  • Making statements based on opinion; back them up with references or personal experience.


To learn more, see our tips on writing great answers.




draft saved


draft discarded














StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2funix.stackexchange.com%2fquestions%2f143958%2fin-bash-read-after-a-pipe-is-not-setting-values%23new-answer', 'question_page');
}
);

Post as a guest















Required, but never shown





















































Required, but never shown














Required, but never shown












Required, but never shown







Required, but never shown

































Required, but never shown














Required, but never shown












Required, but never shown







Required, but never shown







Popular posts from this blog

How to reconfigure Docker Trusted Registry 2.x.x to use CEPH FS mount instead of NFS and other traditional...

is 'sed' thread safe

How to make a Squid Proxy server?