Linux 講座 / テキスト検索と加工 - grep, sort, uniq, cut, wc

テキストで必要な行を探すには grep、行を並べ替えるには sort、隣接する重複行をまとめるには uniq、区切られたフィールドを抽出するには cut、行・単語・バイト数を数えるには wc を使います。これらのコマンドはファイルを直接編集するのではなく、結果を標準出力に送るので、順番に接続すると小さなテキスト処理作業を作れます。

コマンド間でデータを渡すパイプの接続の原理は シェル変数とコマンド実行の流れ で説明します。この記事では準備した入力と予想される集計値を比較することに焦点を当てます。

例データ作成

この講座は Bash と GNU ツールを基準にしています。~/linux-course-12-practice が既にある場合は別の名前を付けてください。新しいディレクトリの作成に失敗した場合は、その後のファイル作成コマンドを続行しないでください。> は既存のファイルを上書きします。

mkdir ~/linux-course-12-practice
cd ~/linux-course-12-practice
pwd

現在の位置を確認した後、名前と状態をコロンで分けた5行のファイルを作ります。

printf 'alpha:ready\nbeta:waiting\nalpha:done\ngamma:ready\nbeta:ready\n' > records.txt
cat records.txt

cat の出力は入力した5行と同じです。以降の例はすべてこのファイルを対象とします。

grepで一致する行を探す

grepは、パターンと一致する行を出力します。-nを付けると、元のファイルの行番号も表示されます。

grep -n 'ready' records.txt

このファイルでは次の三行が出ます。waitingはreadyを含みません。

1:alpha:ready
4:gamma:ready
5:beta:ready

grepの基本パターンは正規表現なので、特殊文字を検索する際には意味を確認する必要があります。文字通りの文字列を探したい場合はgrep -Fを使用できます。一致する行がない場合は通常終了状態1、コマンド自体に問題がある場合は2が返されるため、“出力なし”をすべて同じエラーとして扱わないでください。

cutでフィールドを分割してwcで数を数える

cut -d: -f1はコロンを区切り文字として使い、最初のフィールドのみを出力します。以下の例では名前だけが残ります。

cut -d: -f1 records.txt
alpha
beta
alpha
gamma
beta

cutは単純な区切り文字ベースのツールです。引用符内のコロンや改行まで解釈する必要がある複雑なCSVファイルには、この例をそのまま適用しないでください。wc -lでファイルの行数を確認すると、次のようにファイル名と共に5が表示されます。正確にはwc -lは改行文字を数えるため、最後に改行のない行は数に含まれません。この実習データは各行の末尾に改行があります。

wc -l records.txt

wc -wは単語数を、wc -cはバイト数を数えます。特に日本語のようなマルチバイト文字では、バイト数と文字数が異なる場合があります。GNU wc -mは文字数を求める時に使用します。

sortとuniqを順番に接続する

sortは行をソートします。uniqは連続して現れる同じ行だけを一つにまとめるので、離れている同じ名前を一緒に数えるには、まずソートする必要があります。パイプ|は、前のコマンドの標準出力を次のコマンドの標準入力に渡します。

cut -d: -f1 records.txt | sort | uniq -c

出力で名前ごとの回数はalpha 2回、beta 2回、gamma 1回です。数字の前の空白やソート順はロケールや実装によって異なる場合があります。

      2 alpha
      2 beta
      1 gamma

元のファイルの行全体にsort | uniqを適用すると、alpha:readyとalpha:doneは別々の行として残ります。「どの単位を重複と見なすか」をまず決めた後、必要なフィールドだけを切り出してください。ソート結果はロケールの文字比較規則に影響される場合があるため、他のシステムと結果を比較する際にはロケールも確認してください。

どのコマンドを先に使うでしょうか?

目標 ツール 核心条件
条件に合う行 grep パターンが正規表現か文字通りかの区別
行の順序整理 sort ロケールと並び順の確認
重複のグループ化・数を数える uniq 同じ値が隣接していなければならない
単純な区切りフィールドの抽出 cut 区切り文字とフィールド番号を指定
行・単語・バイト数 wc 何を数えるかオプションで指定

結果が空であったり予想と異なる場合は、まず cat records.txt で元の内容を確認し、長いパイプを各コマンドの段階ごとに分けて実行してみてください。そうすると、パターン、区切り文字、ソートのどの段階で結果が変わったかがわかりやすくなります。

入力の1つだけを変更して結果を比較してみてください。同じ演習フォルダの元の5行データに beta の1行を追加して集計すると、beta が 2 から 3 に増え、全体の行数は 6 になります。最後に、この演習の元の内容に戻して再度集計します。

printf 'beta:ready\n' >> records.txt
cut -d: -f1 records.txt | sort | uniq -c
wc -l records.txt
printf 'alpha:ready\nbeta:waiting\nalpha:done\ngamma:ready\nbeta:ready\n' > records.txt
cut -d: -f1 records.txt | sort | uniq -c
wc -l records.txt

復元後は alpha 2、beta 2、gamma 1 と全体5行が再び出力される必要があります。上書きはこの講座で作成した演習用 records.txt のみに適用されます。

公式ドキュメント

GNU grep マニュアルはパターンと終了ステータスを、GNU Coreutils マニュアルはsort·uniq·cut·wcを説明します。