bashでifステートメントをループするにはどうすればよいですか?

ユーザーに質問を求めてから回答を入力してもらいたいのですが、これはiという名前の変数の下に格納され、回答があれば(はファイルです)が存在し、書き込み可能であり、それを読み取り、ファイル内の物をつかみ、それらを新しいものに書き込みます。ファイルが存在しないか、ユーザーがそのファイルに対する十分な権限を持っていない場合、警告が表示され、プログラムは3秒間スリープし、ループが再開されます。なぜ機能しないのですか?警告は消えず、ループも続きません。

echo "$(tput setaf 4) Tell me where the file is:" printf "\n" a=false while [ $a=true ]; do read i if [ -w $i ] then cat $i | grep stuff > i2 else a=true printf "Oh something is wrong, try again!" sleep 3 fi done 

回答

構文エラーと論理エラーがあります。

$a=trueは単なる文字列であり、比較操作ではありません。比較が行われるようにスペースで区切ります:"$a" = true

これが機能していると、

事前に

最終的にループに入る必要があります。aは決して終了しないため、終了することはできません。 true以外に設定し、別の終了メカニズム(breakなど)も提供していません。

回答

他の人が指摘しているように、コードに論理エラーと構文エラーがあります。 ShellCheckサイトは、構文エラーを取り除くのに適しています。

これについての私の見解です。コードには2つのバージョンがあります。 。最初のもの(私が好む)はユーザー操作がありませんが、コマンドラインでパス名を取ります。2番目のものはインタラクティブにパス名を要求します。

最初のものがインタラクティブにプロンプトを表示しない理由パス名は、スクリプトのユーザーがコマンドラインまたはスクリプトのプロンプトでパス名を書き込んでもほとんど違いがないことです。パス名のスクリプトプロンプトがあると、パス名は使用できなくなります。 cronジョブまたは端末が接続されていない可能性のあるその他の場所。

#!/bin/sh pathname=$1 if ! grep "pattern" <$pathname >i2; then echo "Something is wrong" >&2 fi 

上記のecho

  • $pathname内のファイルが「読み取れない」場合、または
  • ファイルに書き込めない、または
  • パターンが$pathnameで見つかりませんでした(これはコードとは異なりますが、以下を参照してください) 。

エラーメッセージは、一般的な診断メッセージのカスタムと同様に、標準エラーに書き込まれます。

インタラクティブなプロンプトと遅延を使用:

#!/bin/bash while true; do read -r -p "Pathname: " pathname if grep "pattern" <$pathname >i2; then break fi echo "Something is wrong" >&2 sleep 3 done 

ここでは、ユーザーから読み取られ、grep呼び出しが正常に行われた場合にループから抜け出す無限ループがあります。 grepが何らかの理由(上記の3つの理由のいずれか)で失敗した場合、パス名の入力を再度求められます。


両方のコードに個別の読み取り可能なファイルのテスト(grepは、何も見つからないか、出力ファイルに書き込めないために失敗する可能性があります。

最初に非対話型バージョン:

#!/bin/sh pathname=$1 if [ ! -r "$pathname" ]; then echo "Something is wrong" >&2 fi grep "pattern" <$pathname >i2 

次にインタラクティブバージョン:

#!/bin/bash while true; do read -r -p "Pathname: " pathname if [ -r "$pathname" ]; then grep "pattern" <$pathname >i2 break fi echo "Something is wrong" >&2 sleep 3 done 

または、インタラクティブバージョンここで、ループはユーザー入力と検証のみを扱います:

#!/bin/bash while true; do read -r -p "Pathname: " pathname [ -r "$pathname" ] && break echo "Something is wrong" >&2 sleep 3 done grep "pattern" <$pathname >i2 

回答

次のように、単にブレークを使用して無限ループを停止してみてください。

echo "$(tput setaf 4) Tell me where the file is:" echo # This prints empty line like printf "\n" while true; do # "while true" or "while :" is infinite loop read i if [ -r $i ] # You probably mean -r (readable) and not -w (writable) then cat $i | grep stuff > i2 break # "break" ends loop else echo -n "Oh something is wrong, try again!" # "echo -n" means print without newline character sleep 3 fi done 

変更された場所には説明付きのコメントがあります。

コメント

< catではなく、ul class = “comments”>

  • grep <$i >i2。また、テストのように、必要に応じて変数展開を引用します。 。
  • コメントを残す

    メールアドレスが公開されることはありません。 * が付いている欄は必須項目です