シェルでループの中で対話処理をしたい

このQ&Aのポイント
  • unix上でシェルを書いています。ループ内で対話形式で処理をしたいのですが、入力待ちとならないままループしてしまいます。
  • test.txtの内容を読み込んで年齢を入力してもらう処理です。入力があるまで処理を待たせる方法を知りたい。
  • 実行すると、入力を待たずに未入力となる問題が発生します。1行読んでから年齢の入力を待つ方法を教えてください。
回答を見る
  • ベストアンサー

【シェル】ループの中で対話処理をしたい

unix上でシェルを書いています。 ループ内で対話形式で処理をしたいのですが、入力待ちとならないままループしてしまいます。 ループの中で、キーボードからの入力があるまで処理を待たせることは可能でしょうか。   test.txtの内容*** 花子 太郎 二郎 三郎   *************** このテキストを読み込んで年齢を入力してもらうという処理です。 読んだ後の処理はここでは省略します。 while read line; do    echo $line "この人の年齢を入力して下さい。"    read ymd            if [ "$ymd" = "" ]; then      echo "未入力です!"      exit 0        fi done < test.txt これを実行すると、入力をまたずに未入力、未入力、未入力…と標準出力されます。 1行読んだら、年齢を聞いて、入力があるまでは"read ymd"の処理を行わない、という ようにする方法をどうかご教授願います。

質問者が選んだベストアンサー

  • ベストアンサー
回答No.1

良いかどうか別にして、対策案です。 read ymd < /dev/console と、する。

w_horse
質問者

お礼

ike-2000 様 ご回答誠にありがとうございます。 返信が遅れ、大変失礼いたしました。 出力されたものを変数に読み込ませるのですね! 思いつきませんでした、試してみます!

その他の回答 (3)

回答No.4

一応、bash での例を書いてみます。 #!/bin/bash -ex typeset -ag NAME=($(cat test.txt)) typeset -ag YMD typeset -i i for (( i = 0; i < ${#NAME[@]}; i++)); do echo "${NAME[i]} この人の年齢を入力して下さい。" typeset -i ymd read ymd YMD[i]=${ymd} done for ((i = 0; i < ${#NAME[@]}; i++)); do echo ${NAME[i]} ${YMD[i]} done

w_horse
質問者

お礼

MillenniuM様 ご回答ありがとうございます。 回答が遅れ、大変申し訳ありません。 サンプルプログラムありがとうございます!! まさに私がやりたかったことです。 typesetを使う方法は全く思いつきませんでした。 大変勉強になりました。 誠にありがとうございました。

  • kmee
  • ベストアンサー率55% (1857/3366)
回答No.3

原因は < test.txt によって、標準入力が test.txt に切り替わっているために read ymd が、標準入力(= test.txt)から読みこもうとしてしまうからです。 よって、対策は #1のようにread ymd の入力として端末を直接指定するか、 while read line とread ymd とで入力を切り替えるか、 となります。 後者の方法は「ファイル ディスクリプタ while read」あたりで検索すると見付かります。

w_horse
質問者

お礼

kmee 様 ご回答誠にありがとうございます。 返信が遅れ、大変失礼いたしました。 ご丁寧なご説明、ありがとうございます。 モヤモヤがきれいに解消いたしました。 readはキーボードからの入力ではなくて、ファイルから読み込もうとしていたのですね! なるほど……。 一番目の方に教えて頂いた方法で実装をしてみます。 また、もう一つの後者のやり方についても、後学のため、調べてみます。「while read」という検索キーで検索していたのですが、どうも希望のものが見つからなかったのですが、今実際に検索してみたところ、これだ!と思うものにヒットしました。 これからよく読んでみます。 どうもありがとうございました。

回答No.2

bash スクリプトで良ければ、 read にオプション -n が使えるので、 簡単です。 read -n3 ymd とすれば、最大3文字まで、入力を待ちます。 bash なら、ポータビリティもそれほど失われないと思うので、 bash スクリプトにするのが良いと思います。

w_horse
質問者

お礼

MillenniuM 様 ご回答誠にありがとうございます。 返信が遅れ、申し訳ありません。 readのオプションがあるのは知りませんでした。 bashスクリプトですので、こちらも試してみます。

関連するQ&A

  • シェルのwhile文を使ってexpect処理

    環境:CentsOS 5 expectを使ってリスト行文、処理を行わせたい。 while文を使用してシェル内に記述しているexpect構文を リスト文処理をしたいのですがどうもうまく実行できません。 以下のようにsuを行い、Passwordプロンプトが返ってきたときに interactで標準入力モードに戻し、手入力後、引き続き、while文で 後続の処理(echo test;)を実行し、また、expect構文にループするというものです。 以下の構文を実行すると、Passwordプロンプトが返ってきた後 通常プロンプトが返ってきて終了になってしまいます。 因みに、以下の処理ならexpectは必要ないのでは?とおもわれるとおもうのですが 実際にやりたいことは、su処理ではなく他の処理で特定の個所のみプロンプトが返ってきた場合に 手入力したいといったことがあるためです。 どなたかわかる方教えて頂けますと助かります。 ■test.sh #!/bin/sh LISTFILE=/tmp/test.list; while read LINE; do expect -c " set timeout -1 spawn su - root expect \"Password\" interact " echo "test"; done < $LISTFILE

  • unixのシェルでファイル内容を読み込む

    ど初心者です。わかりづらいかもしれませんが宜しくお願いします。 以下のような処理を行いたいと考えています。 (1) aaa.sh(シェルスクリプト)にてバッチプログラムを起動 (2)バッチでエラーの場合、結果ファイル(bbb.txt)に「1」を出力する。 (3)aaa.sh(シェルスクリプト)にて結果ファイルの内容を読み取り「1」の場合は、再度バッチプログラムを起動する。 このうち(3)の処理にて、結果ファイルの読み込み方法がわかりません。 調べた結果、以下のような処理で可能なようですが・・ while read LINE; do echo $line done < aaa.txt 読み込むのは1行なので、ループ処理にはしたくないのですが、例えば「read LINE aaa.txt」のような簡単なコマンドで、ファイルの中身を読み込むことはできないのでしょうか? 実はUNIXが初めてで、しかもスケジュールに余裕がないため焦っております。 なにぶん知識不足な故、ちんぷんかんぷんな質問かも知れませんが、よろしくお願いいたします。

  • シェルスクリプトのYes、Noの入力ロジックに関する質問

    こんにちは。 よろしくお願いします。 Linux(RHEL5)にて、以下のようなシェルスクリプトを作成しました。 ユーザにアンインストールを問い合わせるもので、 yesの時は処理が進み、noの時は処理が中断、 それ以外を入力した場合、再入力を促すようにしています。 echo "" echo "*** アンインストールを実行しますか? ***" read -p "  >>> 実行する場合「yes」、しない場合は「no」を入力してください <<< " YESNO while (test $YESNO != yes) && (test $YESNO != no) do echo "" read -p "  >>> 「yes」もしくは「no」を入力してください <<<  " YESNO done if (test $YESNO == yes) then continue else echo "****** アンインストールをキャンセルしました ******" && exit fi しかし、 何も入力せずに「Enter」を押した場合、 本来なら、再入力を促すように表示したいのですが、 以下のようにエラーが出て、終了してしまいます。 XXX.sh: line YYY: test; !=; unary operator expected XXX.sh: line ZZZ: test; ==; unary operator expected ****** アンインストールをキャンセルしました ****** 恐らくロジックのどこかに見落としがあると思うのですが、 原因がよく分かりません。 よろしくお願いします。

  • シェルスクリプトのYes、Noの入力ロジックに関する質問

    こんにちは。 よろしくお願いします。 Linux(RHEL5)にて、以下のようなシェルスクリプトを作成しました。 ユーザにアンインストールを問い合わせるもので、 yesの時は処理が進み、noの時は処理が中断、 それ以外を入力した場合、再入力を促すようにしています。 echo \"\" echo \"*** アンインストールを実行しますか? ***\" read -p \"  >>> 実行する場合「yes」、しない場合は「no」を入力してください <<< \" YESNO while (test $YESNO != yes) && (test $YESNO != no) do echo \"\" read -p \"  >>> 「yes」もしくは「no」を入力してください <<<  \" YESNO done if (test $YESNO == yes) then continue else echo \"****** アンインストールをキャンセルしました ******\" && exit fi しかし、 何も入力せずに「Enter」を押した場合、 本来なら、再入力を促すように表示したいのですが、 以下のようにエラーが出て、終了してしまいます。 XXX.sh: line YYY: test; !=; unary operator expected XXX.sh: line ZZZ: test; ==; unary operator expected ****** アンインストールをキャンセルしました ****** 恐らくロジックのどこかに見落としがあると思うのですが、 原因がよく分かりません。 よろしくお願いします。

  • シェルスクリプト

    2月14日頃質問のあった”UNIXのシェルスクリプトを使用してテキストファイルのある列にある特定の文字列を条件としてその行を出力するということをやりたい”を下記のように作ってみました。問題ないか逆質問の形で投稿します。(ルール違反かもしれませんが質問が締め切られているので・・・) #!/bin/bash CAT=YAHOO while read LINE do echo $LINE > tmp.txt DOG=`cut -d" " -f2 tmp.txt` if [ "$CAT" = "$DOG" ] then echo "$LINE" fi done < catalog.file

  • シェルスクリプトでwhileを用いてrshを繰り返し使う場合

    Bシェルスクリプトでリモートシェル(rsh)を使う場合の質問です。 現在、以下のような状態です。 有識者の方、アドバイスをお願いします。 ・Aでは、ループされずhostAの場合のみ処理がされます。 (while文が効いていない) ・Bでは、ループされて問題なくhostA,hostB,hostCが処理されます。 (while文が効いている) なぜなのでしょうか。。。(r系コマンドの特性?) ちなみり、リモート側のサーバには.rhostsが設定してあり 問題なくコマンドが通ることは確認済みです。 スクリプトA---------------------------------------------- #!/bin/sh while read line ; do rsh $line hostname done <<END hostA hostB hostC END スクリプトA---------------------------------------------- スクリプトB---------------------------------------------- #!/bin/sh while read line ; do echo " HOST=$line" done <<END hostA hostB hostC END スクリプトB----------------------------------------------

  • シェルスクリプト:while文のリダイレクトはサブシェルで実行されますか

    日頃Linuxを使用している者です。手元にSolaris環境がなく検証できないためSolaris使いの方にお伺いさせてください。 お聞かせいただきたいことは次の一点です。 Q. Solaris8,9,10 のBourneShellは従来どおり、while文でリダイレクトを使ったときは、サブシェルでまわりますか? 上記質問に至った簡単な経緯を申し上げます。 実は、Linuxの/bin/ash(BourneShell相当)スクリプトで while文でリダイレクトしたところ、ループ内の変数がwhileの外でも参照できました。本来BourneShellの場合、当ケースでのループはサブシェルで回るはずですよね。 最近のGNU BASHを始め、ASHもfor,whileのりダイレクトを使ったループもカレントシェルで動作するということでしょうか? そこで、SolarisのSHはどうなのかと思った次第です。以上宜しくお願いします。 p.s. HP-UX, AIXのSHについても情報があればありがたいです。 参考までに、Linux上の実例を記します。 ■test.ash #!/bin/ash n=0 while read line do i=`expr $i + 1` echo "$i: $line" done < $0 echo "total line= $i" ■実験してみる > ./test.ash 1: #!/bin/ash 2: 3: i=0 4: while read line 5: do 6: i=`expr $i + 1` 7: echo "$i: $line" 8: done < $0 9: echo "total line= $i" total line= 9 ← しっかりインクリメントされた変数見れてるし。最近の仕様?

  • シェルスクリプト trap処理の流れにつきまして

    シェルスクリプト作成しておりますが、 trap処理について質問がありますので、ご教授お願い致します。 以下、テストしたいと思っているスクリプトを記載いたします。 #!/bin/sh trap "echo 'stopped'" 1 2 3 15 echo start > test1.txt sleep 100 echo end > test1.txt 上記スクリプトを実行し、Ctrl+cもしくは、 kill -15 でスクリプトを削除した場合、 sleep中にスクリプト中断していると思うのですが、 end文字列がtest1.txtに書き込まれてしまいます。 trapが処理される流れというのは、どのような流れなのでしょうか。 また途中で中断しているのであれば、途中で以下処理を 行なわないようにするにはどうすればよろしいでしょうか。 宜しくお願いいたします。

  • While 二重ループ処理について

    Bashのシェルスクリプトでwhileを使いループの処理を行いたい。 現状以下のようにファイルAの中に値”1”とイコールの場合に$awkを表示しています。 これを値”1”部分へファイルBの中の値を順にチェックできるようにしたいのです。 while IFS="$LF" read $READ_R record; do IFS='; ' set -- $record for awk in $3; do if [ "$awk" == "1" ]; then for awk in $4; do echo "$awk" done fi done done < "$1" 初心者のため分かり難い質問かもしれませんがよろしくお願いします。

  • BShell 動的配列のループ処理について

    動的に変数名を作成した配列について、ループ処理を行う場合、どうしたらいいでしょうか 以下のような処理を書いたのですが、駄目でした。 a=0 while [ ${a} -ne 10 ] do     eval $(printf TEST%02d $a)=(aaa bbb ccc) #TEST00 - TEST10の配列が作られる。     # TEST00 - TEST10の配列の中身にたいして処理を行いたい。。。     for (( I=0; I < ${#`eval $(printf TEST%02d $a)[@]`}; ++I )) # エラー     do         // ここで処理したい・・・     done done いいアイディアがありましたらご教授よろしくお願いいたします。

専門家に質問してみよう