web-dev-qa-db-ja.com

標準入力Bashから1行ずつ読み取る

私は bash 言語を勉強していて、試験トラックはこれを言っています:

一度に1つの入力を(標準入力から)読み取る必要があります(各エントリは文字列であり、改行で終了します)。

私の質問は2つです。

  1. Bashの標準入力から1行ずつ読み取るにはどうすればよいですか?今までは"read string"しかし、一度に1行ずつ読み取るとは思いません。

  2. これが愚かな質問であるかどうかはわかりませんが、スクリプトを作成したら、スクリプトにさらに多くの行を入力として指定できます(もちろん、標準入力から読み取ります)。たとえば stdin から2行(helloおよびworld)を挿入します。これらの2行をbashスクリプトに与えるにはどうすればよいですか?

9
mario razzu
  1. Bashの標準入力から1行ずつ読み取るにはどうすればよいですか?今までは「文字列を読む」を使っていましたが、一度に行を読むとは思いませんでした。

readのプロトタイプは次のとおりです。

read [options] name[s ...]

readlineの入力をname name1 name2 ...に読み取り、内部フィールドセパレーターの内容に基づいて行を分割しますIFS)。 IFSのデフォルトは' \t\n'です(つまり、spacetabnewline)。 readに1つの変数のみを指定すると、行全体がその変数に読み込まれます(-dオプションを使用して新しい区切り文字をreadに設定していない場合)。複数の変数を指定した場合(read -r name name1など)、IFSの現在の値に基づいて単語分割が行われます。文字列hello worldを次のように指定した場合の意味:

read -r name

name="hello world"。一方、同じ文字列を次のように指定すると、

read -r name name1

name="hello"name1="world"。行に余分な単語があり、変数が2つしかない場合はどうなりますか?文字列が"hello big wide world"になったとしましょう。

read -r name name1

name="hello"name1="big wide world"stringの単語は順番に変数に割り当てられ、文字列内の各単語を保持するのに十分な変数がない場合、最後の変数には、以前に割り当てられていない文字列の残りのすべての単語が含まれます。

IFSを変更して、Word分割の発生方法を変更します。例として、anubhavaが提供する答えを詳しく見てみましょう。単語を分割する任意の文字を自由に指定できます。 (たとえば、csvファイルを解析してIFS=$',\n'を設定し、単語をスペースではなく','で分割するのに役立ちます)

行全体を確実に変数に読み込むには、readに1つの変数のみを提供し、IFS='$\n'を設定して、Word分割がnewlineでのみ行われるようにします。 (注:whileループの一部として変更を提供すると、IFSの変更がそのループのスコープに制限されます。 例えば:

while IFS='$\n' read -r line; do
    # do whatever with line
done

stdinの各行がlineに確実に読み込まれ、ループの外側で通常の単語分割が維持されます。ループ内では、anubhavaが答えに示すように、各行を配列に追加できます。 (すべての空白を保持するためにIFS=が使用されます)

13
David C. Rankin

あなたはこのようなことをすることができます:

# array to hold all lines read
lines=()

# read all lines in lines array
while IFS= read -r line; do
    lines+=( "$line" )
done < file

# read 3 more lines from stdin
for ((i=0; i<3; i++)); do
   read -rp "Enter a line: " line
   lines+=( "$line" )
done
4
anubhava