本文へスキップ
BecomeCoder

シェルスクリプトコース · 第5章 繰り返し · レッスン24

まとめて処理する ― 繰り返しの実践

ブラウザで完結

導入

ここまでの道具を組み合わせて、「ディレクトリの中のファイルを一括処理する」という、実務そのものの作業を書いてみましょう。ループ条件分岐変数が同時に動く感覚をつかみます。

説明

やることは「files の中の .txt ファイルを1つずつ見て、行数を数え、合計を出す」です。

#!/bin/bash

TARGET_DIR=files
total=0

echo "=== $TARGET_DIR の .txt を集計します ==="

for file in "$TARGET_DIR"/*.txt; do
  # ファイルが無い場合、パターンがそのまま残るので確認する
  if [ ! -f "$file" ]; then
    continue
  fi

  lines=$(wc -l < "$file")
  echo "$file: $lines 行"
  total=$((total + lines))
done

echo "合計: $total 行"

新しい要素はありません。第2章の変数と $( )、第4章の if、この章の for を組み合わせただけです。スクリプトは、小さな道具の組み合わせでできている——これがシェルの世界観です。

注意点を2つ。

  • "$TARGET_DIR"/*.txt のように、変数は囲み、* は囲まない。囲んでしまうと展開されず、files/*.txt という名前のファイルを探しに行きます。
  • 一致するファイルが1つも無いとき、for はパターンの文字列そのもの(files/*.txt)で1回だけ回ります。だから中で [ -f "$file" ] を確認するのが安全です。
flowchart LR
    A["files/*.txt を展開"] --> B["a.txt / b.txt / c.txt"]
    B --> C["1つずつ wc -l で行数"]
    C --> D["total に足し込む"]
    D --> E["合計を表示"]

やってみよう

スクリプトを実行して、3つのファイルの行数と合計が出ることを確かめましょう。次に *.txt* に変えると memo.md も対象になり、合計が変わります。さらに TARGET_DIR=logs にすれば、まったく別のディレクトリを同じスクリプトで集計できます——変数にしておいた甲斐がここに出ます。

演習

TARGET_DIRlogs に変え、*.txt*.log にして実行し、ログファイルの行数を集計してください(合計は18行になります)。

ヒント1を見る

TARGET_DIR=logsfor file in "$TARGET_DIR"/*.log の2か所を直します。

ヒント2を見る

logs には access.log(10行)と app.log(8行)があります。

実際に動かしてみよう

本文のサンプルや演習のコードは、コードブロック右上の「コピー」ボタンでコピーして、下のエディタに貼り付ければそのまま実行できます。

シェルスクリプト(シミュレート)

スクリプトを書くエディタと、それを動かす仮想シェルを読み込みます(本物のbashではなく、動きを再現した学習用の環境です)。
スクロールして表示された時点でも自動で読み込まれます。