Github Actionsでyesコマンドを使いたい時は代わりにecho yするといい

こんばんは、id:maku693です。

タイトルでほぼ全部説明しましたが、Github Actionsでちょっとハマりました。

Github Actionsのワークフローでは工夫しないとyesコマンドを使えないので、代わりにecho yを使うと手っ取り早いです。

これに気づいたのは、[y/N]どちらかの入力を待つことで処理を続行していいか聞いてくるプログラムをワークフロー中で使いたかったので、yesコマンドを使ってyを入力させようとしたところ、yes: standard output: Broken pipeというエラーが出て正常にワークフローが終了しなかったためです。

手元 (macOS) で実行してもエラーにならないので不思議に思って調べてみると、bashにpipefailオプションが指定されている*1のと、yesコマンドがSIGPIPEを受け取って終了する前提で使われているのが原因でした。

詳しく説明すると、例えば

$ yes | head -10

のようなコマンドを実行したとき、“y”と10行表示されyesとheadが同時に終了するように見えますが、実際には同時に終了するわけではなく

  • headが10行読み終わったので終了する(パイプを読み取るプロセスがなくなる)
  • yesがパイプに書き込もうとするが、読み取り先がないのでOSがyesにSIGPIPEを送る
  • SIGPIPEを受け取ってyesコマンドがエラー終了(exit status が0以外)する

という流れで処理が進むようです*2*3*4

ここでbashにpipefailオプションが指定されていると、yesがエラー終了することによりパイプの途中で処理が失敗したとみなされます。このため、シェルのexit statusが0以外になり、ワークフローのステップも失敗します。手元でうまく動いたのはpipefailオプションが指定されていなかったからでした。

これを回避するには、set +o pipefailなどとしてbashのオプションを上書きする手もあったのですが、今回の用途では“y”を何度も出力しなくてもよかったため、よりお手軽な対応としてecho yで一度だけ“y”を出力させることにしました。

一応yesを使っているコードがないかGithubで検索してみましたが、ざっとみた限り無理やり使っている例もあまりなさそうです。