フィルタコマンド

実用的なプログラムを作成する場合,すべてをゼロから自分で作るのではなく 典型的な処理は既存のプログラムを活用すると圧倒的に早く目的を達成できる 場合がある。

以下に示すコマンドは、いずれも標準入力(または指定したファイル)から テキストデータを読み込み、決められた処理をしたあとその結果を 標準出力に書き出すフィルタコマンドである。これらをうまくパイプで 繋いで利用することで、複雑な処理を一瞬で完了させることができる。

以下の説明では、省略できるものを大括弧 [ ] で括って表記する。また、 記法説明で、[ファイル群] とあるものは、ファイルを指定すると そのファイルを処理対象とし、ファイル指定を省略すると標準入力を処理対象とする。

nkf - 漢字コードの変換

日本語を含むテキストの文字コードを変換する。 変換する文字コードはオプションで指定する。主なオプションを示す。

-jJISコードに変換(デフォルト)
-e日本語EUCコードに変換
-sShift-JISコードに変換
-w8UTF-8コードに変換
-wUTF-8コード(BOM無)に変換
--in-place 変換対象ファイルを直接上書きして変換
-g ファイルの文字コードの自動判別結果を出力する

いくつか例を示す。

# ファイル foo をJISコードに変えたものを bar に保存
nkf -j foo > bar

# ファイル hoge をEUCコードに変換したものを happy プログラムに渡す
nkf -e hoge | ./happy

# ファイル bar をUTF-8コードに変換しそのまま上書きする
nkf -w --in-place bar
egrep - 検索パターンにマッチする行を抽出

指定したパターンにマッチする語を含む行を抽出して出力する。

egrep [オプション] パターン [ファイル群]

パターンには正規表現を利用する。ファイル群 を省略すると標準入力を読んでパターン検索する。

よく使うオプションには以下のものがある。

実行例:

# カレントディレクトリにあるファイルすべてから hoge というパターンを
# 含む行を探して表示
egrep 'hoge' *

# カレントディレクトリにあるすべてのC言語ソースから printf を探す
egrep 'printf' *.c

# カレントディレクトリにあるすべてのC言語ソースから printf を探す
# ただし fprintf にはマッチしないように単語単位で探す
egrep -w 'printf' *.c

# カレントディレクトリより下にあるすべてのディレクトリにある
# C言語ソースから fgets というパターンを含むものを検索し、
# そのファイル名のみ表示
egrep -l 'fgets' **/*.c
(**/*.c はカレントディレクトリ以下すべてにある *.c ファイル、
という意味でzshのみで利用できる)
wc - 行数・単語数・文字数の表示

入力の行数・単語数・文字数を数えて表示する。

wc [オプション] [ファイル群]

の書式で起動する。オプションは以下のとおり。

複数のオプションを組み合わせることもでき、wc -lc とすると、行数と文字数を表示する。
実行例:

# ~yuuji/zip_jp.txt から「山形県」を含むパターンを検索し、
# マッチした件数を数える
nkf -e ~yuuji/zip_jp.txt | egrep '山形県' | wc -l
sed - ストリームエディタ

入力を加工したものを出力する。多くの処理ができるが、 置換機能の使い方を覚えておけば十分だろう。

sed [オプション] 命令 [ファイル群]

よく使うオプションには以下のものがある。

「命令」の部分は多くのものが使えるが s 命令と p 命令 だけ覚えておこう。s命令は文字列の置換を行なう。

sed 's/置換前パターン/置換後文字列/'

とすると、入力行に「置換前パターン」に一致する部分があれば それを「置換後文字列」に置き換える。ただし、置き換えは1行につき 1回のみしか行なわれない。1行に現れる「置換パターン」をすべて 置き換えて欲しいときは、

sed 's/置換前パターン/置換後文字列/g'

のように g フラグを追加する(globalのg)。
実行例:

# score.csv に現れる 太郎 を たろう に置き換えたものを出力
cat score.csv | sed 's/太郎/たろう/'

# CSV形式のファイルをタブ区切りに変換する
cat score.csv | sed 's/,/	/g'
(広い空白の部分はTAB文字で、コマンドラインでは C-v TAB で
 入力する)

p命令は、-n オプションと組み合わせて、 特定の行だけ出力したい場合に利用する。

sed -n '行位置指定p'

のようにして、入力データが「行位置指定」にマッチする行のみ 出力する。行位置指定には、/正規表現/ または 行番号 が書ける。行位置指定をカンマで区切って列挙すると 範囲指定になる。

# hoge.txt の中で Hello または hello にマッチする行のみ出力
cat hoge.txt | sed -n '/[Hh]ello/p'
# でもこれなら grep '[Hh]ello' hoge.txt とやればいいので普通使わない
# ↓sedのp命令は行番号で使うと便利

# ~yuuji/zip_jp.txt のうち、50行目のみを表示
cat ~yuuji/zip_jp.txt | sed -n 50p

# 本当に50行目というのがあってるか、cat -n で確認
cat -n ~yuuji/zip_jp.txt | sed -n 50p

# ~yuuji/zip_jp.txt のうち、10〜14行目のみを表示
cat ~yuuji/zip_jp.txt | sed -n 10,14p

# ~/Mail/inbox/1 のうち、先頭から空行までを表示する
cat ~/Mail/inbox/1 | sed -n '1,/^$/p'
(正規表現の先頭に来る ^ は行頭を意味し、
 正規表現の末尾に来る$は行末を意味する。
 よって /^$/という正規表現は、行頭のすぐ後ろに行末、つまり
 空行にマッチする)

awk - パターンマッチと処理を行なう専用言語

awkは、入力を「空白で区切られたフィールドの集まり」と見なして フィールドごとに分解した処理を簡単に書くことができる。

awk [オプション] awkプログラム文 [ファイル群]

awkプログラム」は ' ' で括る。ここにはawk言語の任意の プログラムを書けるが、 print, printf だけ覚えておけば良い。 「awkプログラム」の部分では、入力行の各フィールドが $1, $2, $3,..., $NFで取り出せる。以下の例を見よ。

処理の元となるファイル sakata.txt:

998	9980032 サカタシ	アイオイチョウ
998	9980828 サカタシ	アキホチョウ
998	9980862 サカタシ	アケボノチョウ
998	9980021 サカタシ	アサヒシンマチ
998	9980875 サカタシ	アズマチョウ
998	9980055 サカタシ	イイモリヤマ
998	9980018 サカタシ	イズミチョウ
99977	9997774 サカタシ	イタド
998	9980046 サカタシ	イチバンチョウ
998	9980836 サカタシ	イリフネチョウ

awkにこのデータを与えると、第1フィールドが $1、 第2フィールドが $2 のように自動的に変数に代入される。 この入力から、第2フィールドと第4フィールドだけを表示したいときは 以下のようにする。

cat sakata.txt | awk '{print $2, $4}'
9980032 アイオイチョウ
9980828 アキホチョウ
9980862 アケボノチョウ
9980021 アサヒシンマチ
9980875 アズマチョウ
9980055 イイモリヤマ
9980018 イズミチョウ
9997774 イタド
9980046 イチバンチョウ
9980836 イリフネチョウ

-F オプションを使うとフィールドの区切り文字を 変えることができる。

cat score.csv | awk -F, '{print $2, $4}'

とすると、区切り文字を , (カンマ)として フィールド分割を行なう。単純なCSVファイルを処理するときは awk -F, によって特定のフィールドのみを対象とした 処理が簡単に書ける。

sort - 入力レコードのソート

1行1レコードとして入力行をソートした結果を出力する。 標準では行頭にあるフィールドを文字コード順にソートする。 sortでよく使うオプションは以下のとおり。

元となるデータ score.txt:

山田太郎	50	70	20
公益太郎	90	80	70
飯森花子	91	79	72
鶴岡一人	60	60	40
酒田三吉	52	70	80
三川一二三	12	34	99

この構成は以下のようになっている。

第1フィールド氏名(文字列)
第2フィールド数学得点(数値)
第3フィールド英語得点(数値)
第4フィールド国語得点(数値)

sortコマンドによる並べ換えは以下のようになる。

# 漢字氏名でソート
cat score.txt | sort

# 数学得点でソート
cat score.txt | sort -n -k 2

# 英語得点でソート
cat score.txt | sort -n -k 3

# 国語得点の高い順にソート
cat score.txt | sort -nr -k 4

元となるデータがCSV形式だった場合はsortの -t オプションで区切り文字をカンマに変えれば良い。

score.csv

山田太郎,50,70,20
公益太郎,90,80,70
飯森花子,91,79,72
鶴岡一人,60,60,40
酒田三吉,52,70,80
三川一二三,12,34,99
# 数学得点でソート
cat score.csv | sort -n -t , -k 2


# 国語得点の高い順にソート
cat score.csv | sort -nr -t , -k 4

# 国語得点の高い順にソートしたものをTAB区切りに変換して出力
cat score.csv | sort -nr -t , -k 4 | sed 's/,/	/g'
(sed命令にある広い空白の部分は C-v TAB とタイプして入力する)

# 数学得点の高い順にソートしたものを、氏名幅20桁にきれいに揃えて出力
cat score.csv | sort -nr -t , -k 4 | \
	awk -F, '{printf "%-20s\t%d %d %d\n", $1, $2, $3, $4}'
uniq - 重複行の削除と重複数数え上げ

標準入力(または指定したファイル)で連続して同じ行が あった場合にそれを1行のみにする。有用な -c-u オプションは覚えておくとよい。

tr - 文字種変換

標準入力の中に登場する各文字を指定した文字にすべて変換する。 大文字を小文字にしたり,改行文字と空白を相互に変換するときに 用いる。

大文字から小文字へ

cat srcfile | tr '[A-Z]' '[a-z]' > destfile

空白を改行に全置換

cat srcfile | tr ' ' '\n' > destfile

-d オプションに続けて文字(または文字範囲) を指定すると,入力側からその文字を削除する。 次の例はMS-DOS改行(CR+LF)をUnix改行(LF)に 変換する。

cat dosfile | tr -d '\r' > unixfile
paste - 行ごとの連結(列ペースト)

2つ以上のファイルを指定し、各ファイルの同じ行を指定した順番で 横につなげたものを出力する。たとえば

file1.txt

秋の田のかりほの庵の苫をあらみ
春過ぎて夏来にけらし白妙の
あしびきの山鳥の尾のしだり尾の

file2.txt

わが衣手は露にぬれつつ
衣干すてふ天の香具山
ながながし夜をひとりかも寝む

という2つのファイルがあったときに、paste コマンドを使用した例を示す。

paste file1.txt file2.txt
秋の田のかりほの庵の苫をあらみ	わが衣手は露にぬれつつ
春過ぎて夏来にけらし白妙の	衣干すてふ天の香具山
あしびきの山鳥の尾のしだり尾の	ながながし夜をひとりかも寝む

同じ行どうしが連結された結果となる。標準の区切りとしてTAB文字が 利用されるが、これを変えるには -d オプションを指定する。

paste -d, file1.txt file2.txt
秋の田のかりほの庵の苫をあらみ,わが衣手は露にぬれつつ
春過ぎて夏来にけらし白妙の,衣干すてふ天の香具山
あしびきの山鳥の尾のしだり尾の,ながながし夜をひとりかも寝む

-d オプションの後ろには区切りに利用する文字を指定する。 通常の文字以外に以下の指定ができる。

'\n'改行文字
'\t'タブ文字(デフォルト)
'\\'バックスラッシュ文字
'\0'空文字列(くっつける)

-d ,:/ のように、複数文字を指定すると1つめの区切りが , 2つめが : で、3つめが / で、さらにもしあれば , : / を順番に使う。

2つのCSVファイルを同じ行どうしで結合するには以下のようにする。

paste -d, file1.csv file2.csv > new.csv

標準入力(または指定したファイル)の先頭10行を出力する。 -数字 オプションで出力する行数を変えることができる。

# foo.txtの先頭10行を表示
head foo.txt

# カレントディレクトリにある *.c ファイルすべての
# 先頭を表示してlessで読む
head *.c | less
# less は、SPCで進んでbで戻る。qで終了

# score.csvを数学得点でソートした結果の先頭3行を表示
cat score.csv | sort -n -t, -k2 | head -3
tail - 末尾表示

標準入力(または指定したファイル)の末尾10行を出力する。 headの逆。

tail コマンドは増えゆくファイルの末尾をつねに監視し続ける ときに利用する。これには -f オプションを指定する。

tail -f filename

Webサーバやメイルサーバプログラムのログファイルを監視するときに 有用である。


本日の目次

目次