Configuration Information [Automatically generated, do not change]: Machine: x86_64 OS: linux-gnu Compiler: gcc Compilation CFLAGS: -DPROGRAM='bash' -DCONF_HOSTTYPE='x86_64' -DCONF_OSTYPE='linux-gnu' -DCONF_MACHTYPE='x86_64-pc-linux-gnu' -DCONF_VENDOR='pc' -DLOCALEDIR='/usr/share/locale' -DPACKAGE='bash' -DSHELL -DHAVE_CONFIG_H -I. -I../bash -I../bash/include -I../bash/lib -g -O2 -Wall uname output: Linux torchio 2.6.32-5-amd64 #1 SMP Fri Sep 9 20:23:16 UTC 2011 x86_64 GNU/Linux Machine Type: x86_64-pc-linux-gnu
Bash Version: 4.1 Patch Level: 5 Release Status: release Description: It looks as if bash is not waiting for a process-substition process which is reading stdin to complete before bash moves on to executing the next statement. Repeat-By: #!/bin/bash LOCK_DIR=/tmp/$$ spew_and_slurp_with_lock() { local I for ((I=0; I<1000; I++)); do echo "some junk" done > >(mkdir $LOCK_DIR; cat > /dev/null; rmdir $LOCK_DIR) } main() { local J rm -fr $LOCK_DIR for ((J=0; J<1000; J++)); do spew_and_slurp_with_lock done } main Expected output: nothing Actual output: rmdir errors ('cos dir already deleted) and mkdir errors ('cos dir already exists) A bit more info ... The actual process in my real script's process substitution list was sqlite3, which was randomly complaining that the database was locked; for the purposes of demonstrating the problem mkdir+cat+rmdir is a reasonable simulation of sqlite3 (both sqlite3 and mkdir+cat+rmdir slurp stdin and use locking). (I use a main() function here simply to allow be to below unambiguously references bits of code above.) The expected output was nothing. The actual output was: mkdir: cannot create directory `/tmp/2076': File exists rmdir: failed to remove `/tmp/2076': No such file or directory mkdir: cannot create directory `/tmp/2076': File exists rmdir: failed to remove `/tmp/2076': No such file or directory ... The number of failing mkdir/rmdir pairs is not consistent: fiori$ ./demo 2>&1 | wc -l 468 fiori$ ./demo 2>&1 | wc -l 470 fiori$ ./demo 2>&1 | wc -l 458 fiori$ I.e. somewhere between 20-25%. But that's just due to timing. It seems to me that the process-substituted list has not finished before bash moves on to executing the next commmand (in this case: looping back round in main() to call spew_and_slurp_with_lock() again). I.e. the N+1'th loop's mkdir is running before the N'th loop's rmdir, and that results in the 'File exists' message. The bash man page does not mention that the sustitute process runs asynchronously, and, indeed, an added call to 'wait' immediately after the 'for' loop in spew_and_slurp_with_lock() reaps nothing. A second odd behaviour, which might just be another symptom of an un-waited-for child process is that when the script finishes the following things happen in the following order: I get a prompt, an rmdir complains. Like this: ... mkdir: cannot create directory `/tmp/12961': File exists rmdir: failed to remove `/tmp/12961': No such file or directory mkdir: cannot create directory `/tmp/12961': File exists fiori$ rmdir: failed to remove `/tmp/12961': No such file or directory Thanks! Alexis