ネストされた読み取りステートメントのため、Bash で無限ループが発生します。

ネストされた読み取りステートメントのため、Bash で無限ループが発生します。

コマンドからファイルのリストを読み取り、ユーザーに各ファイルの入力を要求しようとします。 1つはファイル名を読み取るのに使用されread、もう1つはユーザー入力を取得するために使用されていますが、このスクリプトは無限ループに陥るようです。

foo () {
echo "a\nb\nc" | while read conflicted_file;
do
    echo $conflicted_file
    while true; do
        read -e -p ">  " yn
        case $yn in
            [nN]* ) echo "success"; break;;
            [yY]* ) echo "fail"; break;;
            * ) echo "invalid input";;
        esac
    done
done;
}

foo

外部レイヤーを削除するとwhile readトリックを実行しているようです。どんなアイデアがありますか?

答え1

read標準入力から読み取るので、両方ともread標準入力で開いた同じパイプを介して出力から読み取られます。echo

readパイプの外側の stdin からループ内を読み取るには、次のようにします。

foo () {
  printf 'a\nb\nc\n' |
    while IFS= read -r conflicted_file; do
      printf '%s\n' "$conflicted_file"
      while true; do
        IFS= read <&3 -re -p ">  " yn
        case $yn in
            [nN]* ) echo "success"; break;;
            [yY]* ) echo "fail"; break;;
            * ) echo "invalid input";;
        esac
      done
    done
} 3<&0

つまり、foo関数本体全体のfd 3にコピーします。

答え2

「読み取り」操作は、ttyの代わりにパイプから読み取りを試みます。これにはいくつかの解決策があります。

  1. ランニングread ... </dev/tty。これは、foo()関数が入力リダイレクトを期待しない限り機能します。
  2. パイプを別のファイル記述子にリダイレクトし、そのファイル記述子を繰り返して、内部読み取り呼び出しが影響を受けないようにします。

    それは次のとおりです。

    exec 3< <(echo "a\nb\nc")
    
    while read -u 3 conflicted_file; do
       ...
       read -e -p  ">  " yn
       ...
    done
    
    exec 3>&-
    

関連情報