20
15

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

cURL でダウンロードした対話式シェルスクリプトが bash にパイプ渡しできない

Last updated at Posted at 2018-08-27

インタラクティブな(対話型の)シェルスクリプトを、パイプで bash or sh シェルに渡してユーザに操作させたい。

yes/no といった入力を求められるスクリプトをダウンロードして無名パイプ|)で bash に渡すと、「unary operator expected」と叱られ対話できないなり。

ダウンロード&実行で失敗する
$ curl -s https://yourdomain.com/your_app/setup.sh | bash
Would you like to set up your_app now? (y/n):bash: line 10: [: =: unary operator expected

「curl ダウンロード 対話 bash スクリプト パイプ渡しできない」とググってもタイトルからわかる記事がなかったので、自分のググラビリティとして。

TL; DR (対話的シェルスクリプトのダウンロード実行)

プロセス置換の機能(Process Substitution)を使ってみる。

bash <(curl -s https://yourdomain.com/your_app/setup.sh)
応用技(bashシェルスクリプト内でshシェルにスクリプトを渡して実行する)
#!/bin/bash

echo -n '- シェル互換のテスト ...'
/bin/sh <(cat ./sample.sh) 2>/dev/null 1>/dev/null
if [ $? -ne 0 ]; then
  echo 'NG. shシェルと互換がありません'
  exit 1
fi
echo 'OK. shシェル互換です'

unary operator expected」エラーは、ユーザーから期待する少なくとも1つ以上の必須項目が足りないために発生するエラーです。リモートファイル(ダウンロードしてきたファイル)をプロセス置換によりローカルファイルのように実行します。

TS; DR

一般的に、下記フォーマットでコマンドを打つと curl でダウンロードしたスクリプトを bash コマンドにパイプで渡し、実行できます。

curl -s https://yourdomain.com/your_app/setup.sh | bash

つまり、ネットに公開されているスクリプトをダウンロードしつつシェルのスクリプトを実行する定番のパターンです。セットアップやインストールなどのスクリプトに利用している人も多いのではないでしょうか。

問題は以下のような、入力を求められる対話式のスクリプトの場合です。

setup.shをローカルで実行
$ # yes が入力値
$ ./setup.sh
Would you like to set up your_app now? (y/n): yes
...
your_app installed! Thank you!

上記を同じように、ダウンロード&実行すると、yes もしくは no を渡すことができずエラーが発生します。

$ curl -s https://yourdomain.com/your_app/setup.sh | bash
Would you like to set up your_app now? (y/n):bash: line 10: [: =: unary operator expected

[: =: unary operator expected がエラー内容で、スクリプトの 10 行目に問題があるのがわかります。

unary とは何なり

調べてみたところ、unary はラテン語の una uno などの「1つ」から来ており、「単項の」「1変数の」と言った意味があり、ここでの operator は「演算子」という意味です。

つまり unary operator とは「単項演算子」で、入力を1つ受け付けるタイプの演算子ということです。

そして、expected は「期待していた」という意味なので、何かしらの単項演算子にデータを「渡さないといけない」、もしくは「受け取らないといけない」のに「見当たらないやんけー Σ 👋 bash」っと言われているのです。

どうやら総合的に unary operator expected とエラーが出た場合は「少なくとも1つの項目が必要」という意味に捉えてよさそうです。

このエラーメッセージが出る、よくあるケースが if 文などで比較する際に「片方の型が合っていない」もしくは「未定義だった」場合などです。

今回の件は、スクリプト内の read コマンドで標準入力から yesno などのデータを受け取らずに処理を続行しているため発生しています。

そうなると回避方法として以下の方法が考えられます。

  1. 値がない場合のデフォルトを決める
  2. yesコマンドを使う
  3. 何かしらの方法で yesno を渡す

ネットには「yesコマンドyes | ./script でパイプ渡しにしろ」とあるのですが、うまく動きませんでした。

そもそも、yesno かが決め打ちになってしまうため、スクリプトによってはユーザーに選択させたいのです。

🐒   ユーザーに選択させず、決め打ちで実行したい場合は以下の記事が参考になります。

すると、StackOverflow に「curl ... | bash の形式だと read コマンドは stdin からは拾えないよん」との情報が。

With the curl ... | bash form, bash's stdin is reading the script, so stdin is not available for the read command.

そして丁寧にも解決法まで載せてくれていました。プロセス置換(Process Substitution)と言うのだそうです。

Try using a Process Substitution to invoke the remote script like a local file:

bash <( curl -s ... )

動いた!バッチリ :thumbsup: :pray:

20
15
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
20
15

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?