プロセス置換の実行順序について


以下の`diff <(ps -e) <(ps -e)`の実行結果を見ると、ひとつのコマンド呼び出し中のプロセス置換の実行順序は決まってないように思われます。

[code]

    $ diff <(ps -e) <(ps -e)
    $ diff <(ps -e) <(ps -e)
    232d231
    < 18157 pts/1    00:00:00 bash
    236d234
    < 18161 pts/1    00:00:00 ps
    $ diff <(ps -e) <(ps -e)
    232a233
    > 18163 pts/1    00:00:00 bash
    234a236
    > 18166 pts/1    00:00:00 ps
    
    <略>
    
    $ diff <(ps -e) <(ps -e)
    234c234
    < 20740 pts/1    00:00:00 bash
    ---
    > 20740 pts/1    00:00:00 bash <defunct>
    236d235
    < 20742 pts/1    00:00:00 ps
    
[/code]

プロセス置換を直列に実行させる、もしくは順序を定めて実行させる方法はありますか？




まぁ、Linux であれば `flock(1)` を使って `process substitution` の処理を直列に実行させる事は可能です。

**subst.sh**

[code]

    #!/bin/bash
    diff <(ps -e) <(ps -e)
    
    # Process trace
    $ strace -tt -e execve -f ./subst.sh 2>&1 | grep -E 'execve\("/bin/ps"|exited with 0'
    [pid 28373] 11:46:32.822097 execve("/bin/ps", ["ps", "-e"], [/* 64 vars */]) = 0
    [pid 28375] 11:46:32.830374 execve("/bin/ps", ["ps", "-e"], [/* 64 vars */]) = 0
    [pid 28373] 11:46:33.076616 +++ exited with 0 +++
    [pid 28375] 11:46:33.099348 +++ exited with 0 +++
    
[/code]

**subst_with_flock.sh**

[code]

    #!/bin/bash
    lock=$0
    diff <(flock "$lock" ps -e) <(flock "$lock" ps -e)
    
    # Process trace
    $ strace -tt -e execve -f ./subst_with_flock.sh 2>&1 | grep -E 'execve\("/bin/ps"|exited with 0'
    [pid 28404] 11:47:51.611734 execve("/bin/ps", ["ps", "-e"], [/* 64 vars */]) = 0
    [pid 28404] 11:47:51.791915 +++ exited with 0 +++
    [pid 28405] 11:47:51.796736 execve("/bin/ps", ["ps", "-e"], [/* 64 vars */]) = 0
    [pid 28405] 11:47:51.966822 +++ exited with 0 +++
    
[/code]

ただし、実行順序は不定です。

**date.sh**

[code]

    #!/bin/bash
    lock=$0
    cat <(flock "$lock" date +'1 %M:%S.%N') \
        <(flock "$lock" date +'2 %M:%S.%N') \
        <(flock "$lock" date +'3 %M:%S.%N') \
        <(flock "$lock" date +'4 %M:%S.%N') \
        <(flock "$lock" date +'5 %M:%S.%N')
    
    # Process trace
    $ strace -tt -e execve -f ./date.sh 2>&1 >trace | grep -E 'execve\("/bin/date"|exited with 0'
    [pid 30031] 12:37:12.780454 execve("/bin/date", ["date", "+4 %M:%S.%N"], [/* 64 vars */]) = 0
    [pid 30031] 12:37:12.793103 +++ exited with 0 +++
    [pid 30034] 12:37:12.798596 execve("/bin/date", ["date", "+3 %M:%S.%N"], [/* 64 vars */]) = 0
    [pid 30034] 12:37:12.803944 +++ exited with 0 +++
    [pid 30035] 12:37:12.811373 execve("/bin/date", ["date", "+2 %M:%S.%N"], [/* 64 vars */]) = 0
    [pid 30035] 12:37:12.819125 +++ exited with 0 +++
    [pid 30036] 12:37:12.824015 execve("/bin/date", ["date", "+5 %M:%S.%N"], [/* 64 vars */]) = 0
    [pid 30036] 12:37:12.831424 +++ exited with 0 +++
    [pid 30037] 12:37:12.836361 execve("/bin/date", ["date", "+1 %M:%S.%N"], [/* 64 vars */]) = 0
    [pid 30037] 12:37:12.842358 +++ exited with 0 +++
    
[/code]




まぁ、Linux であれば `flock(1)` を使って `process substitution` の処理を直列に実行させる事は可能です。

**subst.sh**

[code]

    #!/bin/bash
    diff <(ps -e) <(ps -e)
    
    # Process trace
    $ strace -tt -e execve -f ./subst.sh 2>&1 | grep -E 'execve\("/bin/ps"|exited with 0'
    [pid 28373] 11:46:32.822097 execve("/bin/ps", ["ps", "-e"], [/* 64 vars */]) = 0
    [pid 28375] 11:46:32.830374 execve("/bin/ps", ["ps", "-e"], [/* 64 vars */]) = 0
    [pid 28373] 11:46:33.076616 +++ exited with 0 +++
    [pid 28375] 11:46:33.099348 +++ exited with 0 +++
    
[/code]

**subst_with_flock.sh**

[code]

    #!/bin/bash
    lock=$0
    diff <(flock "$lock" ps -e) <(flock "$lock" ps -e)
    
    # Process trace
    $ strace -tt -e execve -f ./subst_with_flock.sh 2>&1 | grep -E 'execve\("/bin/ps"|exited with 0'
    [pid 28404] 11:47:51.611734 execve("/bin/ps", ["ps", "-e"], [/* 64 vars */]) = 0
    [pid 28404] 11:47:51.791915 +++ exited with 0 +++
    [pid 28405] 11:47:51.796736 execve("/bin/ps", ["ps", "-e"], [/* 64 vars */]) = 0
    [pid 28405] 11:47:51.966822 +++ exited with 0 +++
    
[/code]

ただし、実行順序は不定です。

**date.sh**

[code]

    #!/bin/bash
    lock=$0
    cat <(flock "$lock" date +'1 %M:%S.%N') \
        <(flock "$lock" date +'2 %M:%S.%N') \
        <(flock "$lock" date +'3 %M:%S.%N') \
        <(flock "$lock" date +'4 %M:%S.%N') \
        <(flock "$lock" date +'5 %M:%S.%N')
    
    # Process trace
    $ strace -tt -e execve -f ./date.sh 2>&1 >trace | grep -E 'execve\("/bin/date"|exited with 0'
    [pid 30031] 12:37:12.780454 execve("/bin/date", ["date", "+4 %M:%S.%N"], [/* 64 vars */]) = 0
    [pid 30031] 12:37:12.793103 +++ exited with 0 +++
    [pid 30034] 12:37:12.798596 execve("/bin/date", ["date", "+3 %M:%S.%N"], [/* 64 vars */]) = 0
    [pid 30034] 12:37:12.803944 +++ exited with 0 +++
    [pid 30035] 12:37:12.811373 execve("/bin/date", ["date", "+2 %M:%S.%N"], [/* 64 vars */]) = 0
    [pid 30035] 12:37:12.819125 +++ exited with 0 +++
    [pid 30036] 12:37:12.824015 execve("/bin/date", ["date", "+5 %M:%S.%N"], [/* 64 vars */]) = 0
    [pid 30036] 12:37:12.831424 +++ exited with 0 +++
    [pid 30037] 12:37:12.836361 execve("/bin/date", ["date", "+1 %M:%S.%N"], [/* 64 vars */]) = 0
    [pid 30037] 12:37:12.842358 +++ exited with 0 +++
    
[/code]

