順番に読み進めながら学べます

入力を読む — while read で 1 行ずつ処理

この記事は、基礎コマンドからシェルスクリプトまでLinuxの実践的なスキルを1からマスターする「Linux入門講座の一部」です。
while read name ageでdata.txtを1行ずつ列に分けて整形し、for f in "$@" で引数の複数ファイルを順に処理し、パイプやhere-docでreadに入力を渡す書き方を、図解と端末で実習します。

ファイルを1行ずつ読む — while read

名簿や設定ファイルを行ごとに処理したいことはよくあります。

while read line; do … done < fileと書くと、fileを上から1行ずつ読み、その行を変数lineに入れてdo … doneの中を繰り返します。

ファイルが何行あっても、最後の行まで自動でループします

readは受け取った1行を空白で区切り、複数の変数に分けて入れられます。

while read name age; do …と書くと、各行の最初の語がname、次の語がageに入ります。

名簿のように「名前 値」が並ぶデータを、列ごとに取り出して整形できます

printf 'web running\ndb stopped\n' > services.txt   # 素材を作成
while read svc state; do                              # 1 行ずつ svc と state へ
  echo "サービス $svc$state"
done < services.txt                                   # services.txt を入力に
# 出力: サービス web は running / サービス db は stopped
ファイルを while read で1行ずつ処理する
data.txtwhile read name agename = aliceage = 301 行ずつ1 語目2 語目行が尽きるまで繰り返す
while read name ageはファイルを1行ずつ読み、空白区切りで先頭をname、次をageに入れます。
書き方意味
while read v; do … done < fファイル f を1行ずつ変数 v で処理while read l; do echo "$l"; done < data.txt
while read a b; do …1行を空白で区切り複数変数へwhile read name age; do echo "$name"; done < data.txt

名簿ファイルをwhile readで1行ずつ読み、「名前 は 年齢 歳」の形に整形して出力するスクリプトを作ります。

printf 'alice 30\nbob 25\ncarol 41\n' > data.txtで「名前 年齢」が並ぶ素材ファイルを作成してください。

vi roster.shroster.shを開き、iで挿入モードに入って、while read name ageで1行ずつ読み、echoで「$name は $age 歳」と出力するスクリプトを書いてください(先頭に#!/bin/sh)。書けたらEsc:wqで保存します。

chmod +x roster.shで実行権限を付け、./roster.shを実行して3行が整形されて出ることを確認してください。

④ 書く内容に迷ったら、解答パネルの本文をコピーしてviの挿入モードに貼り付けられます。

(正しく実行できれば解説が表示されます)

Linux console
0 / 4 実行済み
Loading Linux Terminal...

引数で複数ファイルを受け取る — "$@" と $(cat f)

処理するファイル名をスクリプトの中に固定すると、別のファイルに使えません

./show.sh a.txt b.txtのように実行時に渡すと、$1が1個目、$2が2個目の引数になります。

すべての引数はまとめて"$@"で受け取れます。

for f in "$@"; do … doneと書くと、渡されたファイルを1個ずつfに入れて順に処理できます。

ファイル全体を文字列としてまとめて使いたいときはtext=$(cat "$f")で変数に取り込みます。

引数の数は$#で分かり、0 個なら使い方を表示するといった作りにできます

printf 'line A1\nline A2\n' > a.txt              # 素材1
printf 'line B1\n' > b.txt                       # 素材2
vi show.sh   # エディタで開き、次の内容を書いて :wq で保存
#   #!/bin/sh
#   for f in "$@"; do
#     echo "--- $f ---"
#     cat "$f"
#   done
chmod +x show.sh
./show.sh a.txt b.txt                            # 2 ファイルを順に見出し付きで表示
引数で渡した複数ファイルを順に処理する
./view.sh a.txt b.txt$1 = a.txt$2 = b.txtfor f in "$@" で順処理1 個目2 個目"$@" でまとめて受け取り順処理
実行時のファイルが$1 $2に入り、"$@"でまとめてforで1個ずつ処理できます。
書き方意味
for f in "$@"; do …引数の各ファイルを順に処理for f in "$@"; do cat "$f"; done
$(cat f)ファイル全体を1つの文字列に取り込むtext=$(cat data.txt)
$#引数の個数(0 なら使い方を表示)[ "$#" -eq 0 ] && echo usage

受け取ったファイル名を引数で1個ずつ処理し、見出しと中身を順に表示するスクリプトを作ります。

printf 'apple\nbanana\n' > fruit.txtprintf 'red\nblue\n' > color.txtで2つの素材ファイルを作成してください。

vi view.shview.shを開き、iで挿入モードに入って、for f in "$@"で引数を1個ずつ受け取り、echoで見出しを出してから、ファイル全体を変数に取り込んで中身を表示するスクリプトを書いてください(先頭に#!/bin/sh)。書けたらEsc:wqで保存します。

chmod +x view.shで実行権限を付け、./view.sh fruit.txt color.txtを実行して2ファイルが順に表示されることを確認してください。

④ 書く内容に迷ったら、解答パネルの本文をコピーしてviの挿入モードに貼り付けられます。

Linux console
0 / 5 実行済み
Loading Linux Terminal...

対話入力とパイプ入力 — read と here-doc

readはファイルだけでなく、人が打ち込んだ入力やパイプで渡された入力も読めます。

echo hi | read vのようにパイプでつなぐ、<<'EOF' … EOFの here-doc でその場の入力をまとめて渡す、といった形があります。

スクリプトを他のコマンドと組み合わせるときの基本になります

# パイプの出力を1行ずつ読む
printf 'one\ntwo\n' | while read v; do echo "行: $v"; done
# here-doc でその場の入力を渡す
while read v; do echo "値: $v"; done <<'EOF'
x
y
EOF
# 人手入力を1回だけ(name を打って Enter)
# 実行すると入力待ちになります
read name; echo "こんにちは $name さん"
ファイル無しで read に入力を渡す
printf 'cat\ndog'| while read v1 行ずつ処理<<'EOF' … EOFwhile read v1 行ずつ処理パイプで渡すhere-doc で渡す
ファイルが無くても、パイプや here-doc でwhile readに入力を1行ずつ渡せます。
書き方意味
cmd | while read v; do …パイプの出力を1行ずつ処理cat data.txt | while read l; do echo "$l"; done
<<'EOF' … EOFhere-doc でその場の入力を渡すwhile read l; do echo "$l"; done <<'EOF'

ファイルを介さず、パイプと here-doc でwhile readに入力を渡すスクリプトを作ります。

vi pipe.shpipe.shを開き、iで挿入モードに入って、printf 'cat\ndog\n'の出力をパイプでwhile read v; do echo "動物: $v"; doneに渡すスクリプトを書いてください(先頭に#!/bin/sh)。書けたらEsc:wqで保存します。

chmod +x pipe.shで実行権限を付け、./pipe.shを実行して2行が出ることを確認してください。

③ 出力が動物: cat動物: dogになり、ファイルを作らなくても入力を1行ずつ処理できたことを確認してください。

④ 書く内容に迷ったら、解答パネルの本文をコピーしてviの挿入モードに貼り付けられます。

Linux console
0 / 3 実行済み
Loading Linux Terminal...
QUIZ

理解度チェック

まずは1問ずつ答えてみましょう。

Q1while read line; do … done < fileは file をどう処理しますか?

Q2スクリプトに渡したすべての引数をまとめて表す書き方はどれですか?

Q3ファイルを作らずにコマンドの出力を1行ずつ read で処理するにはどうしますか?