ファイル内の「while」ディレクティブの標準入力をどのようにリダイレクトしますか?

ファイル内の「while」ディレクティブの標準入力をどのようにリダイレクトしますか?

私はシェルスクリプトを学んでいますが、スクリプトの作成に必要な主要なコマンド構造、特に、およびwhileコマンドdodone開発を理解するのが困難です。

ファイルからディレクティブの標準入力をリダイレクトするときにファイル全体を読み込むとwhile停止することがわかります(この場合、ファイルは1行ずつ読み取られ、現在の行は使用されている変数に配置されますread)。

while read lig fich
do
...
done < fich

これは現在行全体があることを意味しますかfich

例:このスクリプトはユーザー名と文字列を引数として使用し、名前に文字列を含むユーザー名が所有するファイルを検索します。

#usage nblign nom-utilisateur chaine
find . -user $1 | grep $2 >temp
while read lig temp
do
echo $lig "nombre de ligne" `wc -l < $lig`$
done < temp
rm temp

ここの先生が前に$逃したのに太田ですか?コマンドまたは変数の結果を取得するには、それを使用して検索する必要があるためです。ligwhile$

答え1

いくつかの誤解があります。最初にwhile read ... do使用したい形式は次のとおりです。

while read var; do ...; done < file

まさか

while read var file; do ...; done < file

デフォルトでは、各行while read var; do ...; done < filefileとして読み書きされますvarreadとの間のすべての値はdo変数と見なされます。複数の変数を指定した場合、行は空白(デフォルトでは変数値と空白)に分割され、指定された変数$IFSに保存されます\t\n説明したようにhelp read

標準入力または-uオプションが指定されている場合は、ファイル記述子FDから行を読み取ります。単語分割と同様に、行は最初の単語が最初のNAMEに割り当てられ、2番目の単語が2番目のNAMEに割り当てられるなどのフィールドに分割され、残りのすべての単語は最後のNAMEに割り当てられます。

たとえば、次のようになります。

$ echo "foo bar baz zab" | while read v1 rest; do echo "v1:$v1, rest:$rest"; done
v1:foo, rest:bar baz zab
$ echo "foo bar baz zab" | while read v1 v2 rest; do echo "v1:$v1, v2:$v2, rest:$rest"; done
v1:foo, v2:bar, rest:baz zab
$ echo "foo bar baz zab" | while read v1 v2 v3 rest; do echo "v1:$v1, v2:$v2, v3:$v3, rest:$rest"; done
v1:foo, v2:bar, v3:baz, rest:zab

上記のように、入力行はユーザーが指定した数の変数に分割されます。入力に変数名が「単語」未満の場合、最後の変数は行の残りの部分を占めます。これはファイルから読み取るときとまったく同じです。

次に、var="foo"と を使って変数を設定します。読む使用$var。いいえ、先生の言葉が正しいです。$変数が定義される時間を望まないことです。だからwhile read varそれは正しいwhile read $varと正しいです。

したがって、同じロジックを使用するスクリプトの作業バージョンは次のようになります。

find . -user $1 | grep $2 >temp
while read lig 
do
    echo $lig "nombre de ligne" `wc -l < $lig`
done < temp
rm temp

行末からおよびをtemp削除しました。readそれをなぜそこに置いたのか分からないですね。$echo

変数を含むより良いバージョンのスクリプト正しい引用find、解析を試みるのではなく、不要な一時ファイルなしで関連ファイルの検索を使用することは次のとおりです。

find . -user "$1" -name "*$2*" |
## No need for a temp file, just pipe the output directly
## to the while loop
while read lig 
do
    echo "$lig nombre de ligne: $(wc -l < "$lig")"
done 

最後に、上記の方法とは異なり、スペースやその他の奇妙な文字を含む任意のファイル名を処理することができる非常に強力な方法です。

find . -user "$1" -name "*$2*" -print0 |
## No need for a temp file, just pipe the output directly
## to the while loop
while IFS= read -r -d '' lig 
do
    echo "$lig nombre de ligne: $(wc -l < "$lig")"
done 

答え2

送信者help read:「標準入力から1行を読み、それをフィールドに分割します。」つまり、行全体を読み、3つの異なる部分に分割し、各部分をユーザーが名前付き3つの変数に保存しようとします。行にセクションが1つしかない場合、他の2つの変数は設定されません。$変数の現在の値を読みたくないため、Thereを使用しません。名前変数がなければならないことがわかるように置くその価値。

関連情報