bug-bash
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

bash process substitution process not awaited before next statement star


From: alexis
Subject: bash process substitution process not awaited before next statement started?
Date: Wed, 23 Nov 2011 08:41:56 +0100 (CET)

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



reply via email to

[Prev in Thread] Current Thread [Next in Thread]