パイプからユーザー入力を読み取るには?

パイプからユーザー入力を読み取るには?

次のファイルがあるとしますconfirmation.sh

#!/bin/bash
echo -n "Are you sure [Y/n]? "
read line
case "$line" in
    n|N) echo "smth"
        ;;
    y|Y) echo "smth"
        ;;
esac

次のようにスクリプトを実行したいと思います。

cat confirmation.sh | sh

わかりましたAre you sure [Y/n]?。スクリプトが中断されました。問題は何ですか?

答え1

他の人が言ったように、これはパイプから読み取るようにリダイレクトされたため、通常どおり端末に接続されていないためstdinです。shこの問題を解決するためにできることの1つは、/dev/tty強制スクリプトを使用して端末から読むことです。たとえば、

#!/bin/sh

read -p "Are you sure [Y/n]?" line </dev/tty
case "$line" in
  y|Y) echo "confirmed"
    ;;
  *) echo "not confirmed"
    ;;
esac

一般に、人々が入力スクリプトを書くのを特に避けたい場合にのみこれを行います。たとえば、次のようになります。

echo Y | sh confirmation.sh

ユーザーがメッセージが表示されたときに自動的に入力したい場合でも、Y端末から読みます。これは、これを行うためにパスワードが必要なプログラムで一般的です。

答え2

sh 3<<CONFIRM /dev/fd/3
    $(cat ./confirmation.sh)
CONFIRM

sh 3<./confirmation.sh /dev/fd/3

メモ:上記の2つの例を修正してくれた@Graemeに感謝します...

着実にするとはるかに簡単です。stdin明らかです。

2<./confirmation.sh . /dev/stderr

または、ターミナル0 1 2はすべて同じファイルであるため、以下を追加するだけです。

read line <&2

そしてあなたのもの

cat ./confirmation.sh | sh

良い結果。

答え3

これは私のスクリプトにパイプされた単一のパラメータに対して機能します。

if [ -p /dev/stdin ]; then set -- "$( cat )"; fi

$1その後、他のスクリプト操作と互換性のある位置パラメータ()のパイプデータにアクセスできます。


からinfo test

[ -p /dev/stdin ]-p FILEFILEが存在し、名前付きパイプであれば真です。

答え4

短い答えはできないということです。パイプはstdoutをstdinにリダイレクトするため、パイプステートメントの最初のコマンドの出力を2番目のコマンドの入力にリダイレクトしたため、対話型スクリプトを実行できません。

次のようにしたい場合があります。

cat confirmation.sh > ask.sh && sh ask.sh

関連情報