On Sun, Jun 26, 2011 at 4:06 PM, Dave Reisner <d@falconindy.com> wrote:
On Sun, Jun 26, 2011 at 03:12:24PM +0200, Kurt J. Bosch wrote:
Tom Gundersen, 2011-06-26 13:51:
On Sun, Jun 26, 2011 at 1:03 PM, Kurt J. Bosch <kjb-temp-2009@alpenjodel.de> wrote:
The following test case (run in a terminal)
#!/bin/bash
# custom override example stat_busy() { if (( PUSH_MSG )); then # This triggers the error in "$@" below # actual code was: # echo set message "$1"> "$spl_fifo"& :& fi echo "$1" BUSY }
status() { stat_busy "$1" shift "$@" local retval=$? (( retval == 0 ))&& echo DONE || echo FAIL "($retval)" }
PUSH_MSG=0 status "test #0" cat<(echo foo) PUSH_MSG=1 status "test #1" cat<(echo foo)
[...]
CCing Tom Gundersen.
Thanks.
I have not figured it out, but here is a more minimal test:
#!/bin/bash
test_one() { : & "$@" }
test_two() { : "$@" }
# working test_one eval 'cat<(echo foo)' test_two cat<(echo foo)
#not working test_one cat<(echo foo)
Confirmed.
-- Kurt
Now I see it (at least in Tom's example). It's expected behavior. You're only allowed to read the file descriptor created by a PE once. However, because file descriptors are inherited by subshells, when the subshell ends, the file descriptor is closed and it goes away. Look at what happens when you modify the script slightly:
-------------------
#!/bin/bash
test_one() { ls /dev/fd/ : & ls /dev/fd/ "$@" }
test_one cat <(echo foo)
-------------------
And then run it with debug output....
+foo[11]: test_one cat /dev/fd/63 +foo[4]: ls /dev/fd/ ++foo[11]: echo foo 0 1 2 3 63 +foo[6]: ls /dev/fd/ +foo[5]: : 0 1 2 3 +foo[7]: cat /dev/fd/63 cat: /dev/fd/63: No such file or directory
The subshell inherits the descriptor and closes it on exit, destroying it for the parent. The eval "works" because the FD for the process substitution isn't created until _after_ the subshell.
Can we _not_ do this? Our old solution didn't require voodoo like this, and it worked just fine (albeit a few more SLOC). Not everything needs to be a one line operation. Perhaps we could just write a simple function to take care of all these 1 line files that we write to:
write_oneline_file() { local file=$1 line=$2 mode=$3
printf '%s\n' "$line" >"$file" [[ $mode ]] && chmod "$mode" "$file" }
Which satisfies both parties, as it appears to be a one liner in execution, but it's actually sane on the back end.
Thanks for your explanation Dave. I like your solution, should make things more readable. -t [sorry for duplicate, forgot CC]