The lastpipe shopt is seems superior to <() in the sense that lastpipe returns exit status while <() always returns zero as demonstrated here: $ (read -r; echo $REPLY) < <(echo hi; false); echo $? hi 0 $ shopt -s lastpipe $ echo hi | (read -r; echo $REPLY; false); echo $? hi 1 Cons of having the lastpipe shopt automatically enabled by a future EAPI may include: 1) It could lead to confusion if lastpipe is silently enabled. People may ignore the lastpipe feature and use <() instead. 2) Since shell options are global, all bash code (including eclass functions) must be compatible with lastpipe. Maybe it's not that hard to be compatible though.
(In reply to Zac Medico from comment #0) > $ shopt -s lastpipe > $ echo hi | (read -r; echo $REPLY; false); echo $? > hi > 1 Not sure if I understand the intention. Why is lastpipe needed there? The return status is 1 even if it isn't enabled: $ shopt lastpipe lastpipe off $ echo hi | (read -r; echo $REPLY; false); echo $? hi 1 (Also, why a subshell? echo hi | { read -r; echo $REPLY; false; } appears to do the same.)
The point of <() is really to avoid moving the meat into a subshell. printf '%s\n' foo bar baz | (while read x; do foo+=($x); done) isn't going to work.
(In reply to Ulrich Müller from comment #1) > (In reply to Zac Medico from comment #0) > > $ shopt -s lastpipe > > $ echo hi | (read -r; echo $REPLY; false); echo $? > > hi > > 1 > > Not sure if I understand the intention. Why is lastpipe needed there? The > return status is 1 even if it isn't enabled: I suspect that some people will prefer the lastpipe style where the input source appears first rather than last. Here's a practical example applied to portage/bin/install-qa-check.d/05double-D: > diff --git a/bin/install-qa-check.d/05double-D b/bin/install-qa-check.d/05double-D > index 4b7737c0f..2554eb706 100644 > --- a/bin/install-qa-check.d/05double-D > +++ b/bin/install-qa-check.d/05double-D > @@ -1,15 +1,18 @@ > # Check for accidential install into ${D}/${D} > > DD_check() { > + local lastpipe_state=$(shopt -p lastpipe) > + shopt -s lastpipe > if [[ -d ${D%/}${D} ]] ; then > eqawarn "QA Notice: files installed in \${D}/\${D}:" > local files=() > - while read -r -d $'\0' i ; do > + find "${D%/}${D}" -print0 | while read -r -d $'\0' i ; do > files+=( "${i#${D%/}${D}}" ) > - done < <(find "${D%/}${D}" -print0) > + done > eqatag -v double-D "${files[@]/#//}" > die "Aborting due to QA concerns: ${#files[@]} files installed in ${D%/}${D}" > fi > + eval "${lastpipe_state}" > } > > DD_check > $ shopt lastpipe > lastpipe off > $ echo hi | (read -r; echo $REPLY; false); echo $? > hi > 1 > > (Also, why a subshell? echo hi | { read -r; echo $REPLY; false; } appears to > do the same.) It's a very contrived example, so please refer to my practical example. (In reply to Michał Górny from comment #2) > The point of <() is really to avoid moving the meat into a subshell. > > printf '%s\n' foo bar baz | (while read x; do foo+=($x); done) > > isn't going to work. Yeah, please refer to the above refactor of portage/bin/install-qa-check.d/05double-D.
(In reply to Zac Medico from comment #3) > (In reply to Ulrich Müller from comment #1) > > (In reply to Zac Medico from comment #0) > > > $ shopt -s lastpipe > > > $ echo hi | (read -r; echo $REPLY; false); echo $? > > > hi > > > 1 > > > > Not sure if I understand the intention. Why is lastpipe needed there? The > > return status is 1 even if it isn't enabled: > > I suspect that some people will prefer the lastpipe style where the input > source appears first rather than last. Here's a practical example applied to > portage/bin/install-qa-check.d/05double-D: > > diff --git a/bin/install-qa-check.d/05double-D b/bin/install-qa-check.d/05double-D > index 4b7737c0f..2554eb706 100644 > --- a/bin/install-qa-check.d/05double-D > +++ b/bin/install-qa-check.d/05double-D > @@ -1,15 +1,18 @@ > # Check for accidential install into ${D}/${D} > > DD_check() { > + local lastpipe_state=$(shopt -p lastpipe) > + shopt -s lastpipe > if [[ -d ${D%/}${D} ]] ; then > eqawarn "QA Notice: files installed in \${D}/\${D}:" > local files=() > - while read -r -d $'\0' i ; do > + find "${D%/}${D}" -print0 | while read -r -d $'\0' i ; do > files+=( "${i#${D%/}${D}}" ) > - done < <(find "${D%/}${D}" -print0) > + done > eqatag -v double-D "${files[@]/#//}" > die "Aborting due to QA concerns: ${#files[@]} files installed in ${D%/}${D}" > fi > + eval "${lastpipe_state}" > } > > DD_check To clarify the "superiority" mentioned in comment #0, we can use ${PIPESTATUS[@]} to check the status of the find command after the loop has completed.
Since checking return values is important (it's the basis of all robust code), we could probably ban <() on the grounds that lastpipe is provably superior.
(In reply to Zac Medico from comment #5) > Since checking return values is important (it's the basis of all robust > code), we could probably ban <() on the grounds that lastpipe is provably > superior. No, we shouldn't. You should use <(... || die).
(In reply to Michał Górny from comment #6) > (In reply to Zac Medico from comment #5) > > Since checking return values is important (it's the basis of all robust > > code), we could probably ban <() on the grounds that lastpipe is provably > > superior. > > No, we shouldn't. You should use <(... || die). That sounds reasonable, and I suppose that static analysis QA tools could assert that the <() status is checked in some way?
(In reply to Zac Medico from comment #5) > Since checking return values is important (it's the basis of all robust > code), we could probably ban <() on the grounds that lastpipe is provably > superior. Banning <() is a separate issue (though lastpipe would be a prerequisite for it). Maybe we shouldn't discuss it here because it would complicate things. In any case, it would be an add-on QA policy but not be part of the spec. Interestingly, POSIX doesn't specify the behaviour: "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." https://pubs.opengroup.org/onlinepubs/7990989775/xcu/chap2.html#tag_001_012 So, are there any known adverse effects of enabling lastpipe?
(In reply to Ulrich Müller from comment #8) > Interestingly, POSIX doesn't specify the behaviour: > "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." > https://pubs.opengroup.org/onlinepubs/7990989775/xcu/chap2.html#tag_001_012 > > So, are there any known adverse effects of enabling lastpipe? The behavior of the ${PIPESTATUS[@]} is identical, so the difference is that variables from the last shell in the pipeline will persist while variables from the first shell in the pipeline will we lost. This has potential to cause confusion if lastpipe is silently enabled.
(In reply to Zac Medico from comment #9) > (In reply to Ulrich Müller from comment #8) > > Interestingly, POSIX doesn't specify the behaviour: > > "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." > > https://pubs.opengroup.org/onlinepubs/7990989775/xcu/chap2.html#tag_001_012 > > > > So, are there any known adverse effects of enabling lastpipe? > > The behavior of the ${PIPESTATUS[@]} is identical, so the difference is that > variables from the last shell in the pipeline will persist while variables > from the first shell in the pipeline will we lost. This has potential to > cause confusion if lastpipe is silently enabled. Lately I've been using lastpipe in long-running event-driven bash scripts, and what I've found is that lastpipe may or may not be desired for any particular pipe. So, we can't expect a global lastpipe default to satisfy all use cases.
(In reply to Zac Medico from comment #10) > (In reply to Zac Medico from comment #9) > > (In reply to Ulrich Müller from comment #8) > > > Interestingly, POSIX doesn't specify the behaviour: > > > "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." > > > https://pubs.opengroup.org/onlinepubs/7990989775/xcu/chap2.html#tag_001_012 > > > > > > So, are there any known adverse effects of enabling lastpipe? > > > > The behavior of the ${PIPESTATUS[@]} is identical, so the difference is that > > variables from the last shell in the pipeline will persist while variables > > from the first shell in the pipeline will we lost. This has potential to > > cause confusion if lastpipe is silently enabled. > > Lately I've been using lastpipe in long-running event-driven bash scripts, > and what I've found is that lastpipe may or may not be desired for any > particular pipe. So, we can't expect a global lastpipe default to satisfy > all use cases. The decision about whether or not to use lastpipe for a particular pipe is governed by whether or not the main shell is producing or consuming data.
(In reply to Zac Medico from comment #10) > Lately I've been using lastpipe in long-running event-driven bash scripts, > and what I've found is that lastpipe may or may not be desired for any > particular pipe. So, we can't expect a global lastpipe default to satisfy > all use cases. Closing, as discussed in #-portage.