Q1while read line; do … done < fileは file をどう処理しますか?
入力を読む — 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 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 |
引数で複数ファイルを受け取る — "$@" と $(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 ファイルを順に見出し付きで表示
$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 |
対話入力とパイプ入力 — 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 さん"
while readに入力を1行ずつ渡せます。| 書き方 | 意味 | 例 |
|---|---|---|
cmd | while read v; do … | パイプの出力を1行ずつ処理 | cat data.txt | while read l; do echo "$l"; done |
<<'EOF' … EOF | here-doc でその場の入力を渡す | while read l; do echo "$l"; done <<'EOF' |
理解度チェック
まずは1問ずつ答えてみましょう。
Q2スクリプトに渡したすべての引数をまとめて表す書き方はどれですか?
Q3ファイルを作らずにコマンドの出力を1行ずつ read で処理するにはどうしますか?