テキスト加工ツール
前提:3-4が完了し、~/practiceの中にfruits.txt(りんご・みかん・ぶどう・Appleの4行)、copy.txt、memo.txt、vimtest.txtが存在する状態から始めます。ここまでで「探す」道具は手に入りました。次は「並べ替える」「重複をまとめる」「一部分だけ取り出す」といった加工の道具です。sort uniq cut trを体験したあと、最後はこれらをパイプでつないで、集計のワンライナー※1を完成させます。
このページではSET 1〜3、合計30行のコマンドを上から順に叩きます。手打ち推奨(コピーは確認用)です。
SET 1 ― sortで並べ替える
- $cd ~/practice
- $ls
- copy.txt fruits.txt memo.txt vimtest.txt
- $cat fruits.txt
- りんご
- みかん
- ぶどう
- Apple
- $sort fruits.txt
- $cat fruits.txt
- $printf "30\n5\n100\n" > nums.txt
- $wc -l nums.txt
- 3 nums.txt
- $sort nums.txt
- $sort -n nums.txt
- $cat nums.txt
1行目で練習用ディレクトリへ移動し、2行目のlsで、3-4までに作った4つのファイルがそろっていることを確認しておきます。
4行目のcatでfruits.txtの中身を見直したあと、5行目のsort fruits.txtは、ファイルの各行を並べ替えて表示するコマンドです。オプションなしのsortは文字コード順(アルファベットや記号が先、五十音はその次)に並べるため、Appleが先頭に来る結果になります。6行目であらためてcatすると、元のファイル自体は変更されておらず、あくまで「並べ替えた結果を表示するだけ」だったことがわかります。
7行目のprintfはechoに似たコマンドで、\nを改行として解釈しながら3つの数字を1行ずつnums.txtに書き込みます。8行目のwc -lで3行のファイルができたことを数値で確認しておきましょう。9行目のようにsort nums.txtを素直に実行すると、100・30・5のような数字も文字列として扱われるため、先頭の文字(1、3、5)だけで比較され、100が5より前に来るという直感に反した順番になってしまいます。
これを解決するのが10行目のsort -nオプションです。-n(numericの意味)を付けると、文字としてではなく数値として大小を比較するようになり、5・30・100という正しい順番で並びます。数字を扱うときは-nを付け忘れないことが重要です。11行目であらためてcat nums.txtすると、sortを何度実行しても元のnums.txt自体は「30・5・100」という並び順のまま変わっていないことも確認できます。
sortは初期状態では「文字」として比較します。数字の大小で並べたいときは必ず-nを付けましょう。付け忘れると「100が5より小さい」ような不自然な結果になります。
SET 2 ― -r と uniq、cutとtr
- $sort -rn nums.txt
- $printf "みかん\nみかん\nりんご\n" > dup.txt
- $wc -l dup.txt
- 3 dup.txt
- $uniq dup.txt
- $printf "みかん\nりんご\nみかん\n" > shuffled.txt
- $uniq shuffled.txt
- $sort shuffled.txt | uniq
- $echo "yumi,devteam,1001" > user.csv
- $cut -d, -f1 user.csv
- yumi
- $cut -d, -f2,3 user.csv
1行目のsort -rnは、-n(数値順)に-r(reverseの意味)を組み合わせたもので、数値の大きい順(降順)に並べ替えます。-r単体でもオプションを逆順にできるので、文字列を逆順に並べたいときにも使えます。
2行目でdup.txtを作り、3行目のwc -lで3行のファイルができたことを数値で確認しておきます。4行目のuniqは、隣り合う行が同じ内容のときに1行へまとめてくれるコマンドです。dup.txtは「みかん・みかん・りんご」の順で連続しているため、期待どおり「みかん・りんご」の2行にまとまります。ところが6行目のshuffled.txt(みかん・りんご・みかん)に対してuniqを使うと、重複が隣り合っていないため何も変化がありません。uniqはすでに並んでいることが前提のコマンドなのです。
そこで7行目のように、まずsortで同じ内容を隣り合わせにしてから| uniqでつなぐのが定番の使い方です。この「sortしてからuniq」という順番はセットで覚えてください。
8行目でCSV風(カンマ区切り)の1行を作り、9行目のcut -d, -f1で列を取り出します。-d(delimiterの意味)で区切り文字を指定し(ここではカンマ)、-f(fieldの意味)で何列目を取り出すかを指定します。10行目のように-f2,3とカンマで並べれば、2列目と3列目をまとめて取り出せます。

「uniqだけ使ったのに重複が消えない!」ってハマる人、すごく多いんだよ。uniqは隣同士しか見てくれないから、バラバラに並んでるデータには必ず先にsortをかけてあげてね。「sortしてuniq」で1セットって覚えちゃおう!
SET 3 ― trとパイプ連結で集計する
- $echo "yumi,devteam,1001" | tr , " "
- yumi devteam 1001
- $echo "HELLO" | tr A-Z a-z
- hello
- $echo "hello" | tr a-z A-Z
- HELLO
- $printf "みかん\nりんご\nみかん\nぶどう\nみかん\nりんご\n" > order.txt
- $cat order.txt
- $wc -l order.txt
- 6 order.txt
- $sort order.txt | uniq
- $sort order.txt | uniq -c
- 3 みかん
- 2 りんご
- 1 ぶどう
- $sort order.txt | uniq -c | sort -rn
- 3 みかん
- 2 りんご
- 1 ぶどう
- $sort order.txt | uniq -c | sort -rn | head -n1
1行目のtr(translateの略)は、1文字目の集合を2文字目の集合に置き換えるコマンドです。tr , " "はカンマをスペースに変換し、出力例のとおりCSVをスペース区切りに変えています。2行目のtr A-Z a-zのように範囲指定もでき、大文字アルファベットをすべて小文字に変換しています。3行目のようにtr a-z A-Zと前後を入れ替えれば、逆に小文字から大文字への変換もできます。trはファイル名を指定せず、パイプで渡された文字列にだけ効く点がsortやcutと違うところです。
4行目で、果物の注文履歴のようなバラバラなデータorder.txtを作ります。5行目のcatで中身を確認し、6行目のwc -lで6行のデータであることも数値で確認しておきましょう。7行目のように、まず-cなしのsort | uniqを試すと、件数はわからないものの「みかん・りんご・ぶどう」の3種類に重複整理されることが確認できます。
8行目のsort order.txt | uniq -cが、このページの集大成となる集計ワンライナーです。まずsortで同じ果物を隣り合わせにし、続くuniqに-cオプション(countの意味)を付けることで、行をまとめるだけでなくその行が何回出てきたかまで数えてくれます。出力例のとおり、件数と果物名が並んだ集計結果が一発で得られます。
9行目ではさらに| sort -rnをつなぎ、件数の多い順に並べ替えています。cat file | sort | uniq -c | sort -rnという形は「ファイルの中身を集計して多い順に並べる」という、現場で非常によく使われる定番のワンライナーです。10行目のように、さらに第1章で学んだhead -n1をつなげば、一番売れている(件数が多い)果物だけをピンポイントで取り出せます。ここまでのSET 1〜3で覚えたコマンドがすべて1本の水道管につながったことになります。
sort | uniq -c | sort -rnは「集計して多い順に並べる」の黄金パターンです。アクセスログの人気ページ集計から、注文履歴の売れ筋商品集計まで、応用範囲は非常に広いので、まずはこの形をそのまま覚えてしまいましょう。
まとめ
3-5では、並べ替え・重複整理・列の抜き出し・文字変換という加工の基本を体験し、最後はパイプでつないで集計ワンライナーを完成させました。このページで叩けるようになったコマンドを一覧にまとめます。
| コマンド | 何をするか | 覚え方 |
|---|---|---|
sort | 行を文字コード順に並べ替える | 並べ替えの基本形 |
sort -n | 行を数値として並べ替える | numeric(数値) |
sort -r | 並び順を逆にする(降順) | reverse(逆) |
uniq | 隣り合う重複行を1行にまとめる | 事前にsortが必須 |
uniq -c | まとめながら件数も数える | count(数える) |
cut -d区切り -f列番号 | 指定した区切り文字で列を取り出す | delimiter + field |
tr 文字1 文字2 | 文字を別の文字に置き換える | translate(変換) |
sort | uniq -c | sort -rn | 集計して多い順に並べる定番ワンライナー | 集計の黄金パターン |
次のページ「3-6. sedとawkでミニ集計」では、売上データ風のファイルを作り、sedで文字列を置換し、awkで列の合計を計算するところまで進みます。第3章の締めくくりです。
- ワンライナー … 複数のコマンドをパイプなどでつなぎ、1行で完結させた処理のこと。Linuxではよく使われる書き方。↩