Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
13
Help us understand the problem. What is going on with this article?
@KEINOS

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

インタラクティブな(対話型の)シェルスクリプトを、パイプで 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)を使ってみる。

ユーザーから期待する少なくとも1つ以上の必須項目が足りないため unary operator expected エラーで処理が停止しています。リモートファイルをプロセス置換によりローカルファイルのように実行します。

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シェル互換です'

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 は「期待していた」になるので、何かしらの単項演算子にデータを「渡さないといけない」、もしくは「受け取らないといけない」のに「見当たらない」という事になります。

どうやら総合的に 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:

13
Help us understand the problem. What is going on with this article?
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
KEINOS
A Japanese made in Mexico with Mexican quality ;-) Who monkey around the jungle of codes. 記事の日本語がおかしかったら遠慮なく編集リクください。また、記事に「LGTM」が付くたび、やる気に比例して見直して何かしら加筆・修正してブラッシュアップしています。基本的に変更通知はお送りしません。
qiitadon
Qiitadon(β)から生まれた Qiita ユーザー・コミュニティです。

Comments

No comments
Sign up for free and join this conversation.
Sign Up
If you already have a Qiita account Login
13
Help us understand the problem. What is going on with this article?