23501

[code]

    $ cat pseudo-yes.sh
    #!/bin/sh
    
    while true; do
      printf "y\n"
    done
    $ 
    
[/code]

上記のような、 `pseudo-yes.sh`を記述しました。これを、例えば次のように使うと、問題無く `yes` コマンドのような動きをしてくれます。

[code]

    $ ./pseudo-yes.sh | head -n 1
    y
    $ 
    
[/code]

* * *

この挙動を見る限り、 `printf` コマンドの実行に際して発生する`SIGPIPE`シグナルは、 `pseudo-
yes.sh`が受信・処理しているはずだと理解できます。(でないと、 `while`文から抜け出せるはずがない)

自分の理解ですと、`SIGPIPE` シグナルは、 `write`システムコールを行ったプロセスに対して発行されるものはずだと思っています。

質問:

  * どうして、書き込みを行う主体のプロセスは `printf` なのに、`pseudo-yes.sh` が `SIGPIPE`を正しく処理できているのでしょうか？

補足:

  * この挙動は、 ubuntu と mac-os-x の両方で観測されました。


CC BY-SA 3.0
2016-03-27T05:46:12.983
23498
2017-05-08T16:41:22.667
2016-03-27T05:58:07.553
754
754
question
sh unix
擬似 yes コマンドを書いたのですが、 SIGPIPE がどうしてよろしく処理されるのかがわからない


Ubuntu の `/bin/sh` (bash, dash または posh)、Mac OS X の `/bin/sh` (bash) どちらも
`printf` はシェル組込みコマンドです。

[code]

    $ /bin/sh -c 'type printf'
    printf is a shell builtin
    
[/code]

また `SIGPIPE` のデフォルトのシグナルハンドラーはプロセスの終了です。よって、件のコードを実行すると `/bin/sh` プロセスが
`SIGPIPE` シグナルを受け、終了します。

Ubuntu であれば次のように実行すれば `/bin/sh` が外部コマンドを起動していないこと  
(システムコール `fork`(2)、`clone`(2)、`execve`(2) を実行していない)、  
`SIGPIPE` を受け取っていることを観測できます。

[code]

    $ strace -f /bin/sh -c 'while true; do printf "y\n"; done' |head -n 1
    
[/code]

よって、想定通りの動作ですね。

`printf` が組込みでない `/bin/sh` も想定するなら、次のように `printf` の終了コードが 0
以外なら終了するようにしましょう。`printf`(1) プロセスが `SIGPIPE` を受けて終了したなら、終了コードは 128 + `SIGPIPE`
の整数値(一般的には 13) = 141 になります。

[code]

    #!/bin/sh
    
    while true; do
      printf "y\n" || exit $?
    done
    
[/code]


CC BY-SA 3.0
2016-03-27T06:29:02.640
23501
2017-05-08T16:41:22.667
2017-05-08T16:41:22.667
3061
3061
23498
answer