UNIXコマンド テキスト処理を色々試してみた1

下記書籍に感化されて、UNIXのテキスト処理を色々試してみた。(環境は「Fedora環境をHyper-V上で構築&Telnetで接続まで メモ - oknknicの日記」で構築したFedora

UNIXという考え方―その設計思想と哲学

UNIXという考え方―その設計思想と哲学

確かに、いくつかの単機能コマンドの組み合わせで、たいていのテキスト処理はできそうな気がしてきた。
今回のトピックは以下の通り。

  • 行の絞り込み - grep
  • 行の絞り込み(行番号指定も可能) - sed
  • 列の選択 - cut
  • カウント - wc
  • ソート - sort
  • 重複 - uniq
  • 【総まとめ】SQLとの対応

行の絞り込み - grep

#CSVの第3フィールドが「c」である行のみ表示
printf "a,b,c,d,e\nf,g,h,i,j" | grep -E '^([^,]*,){2}c[,]*'
#CSVの第3フィールドに「Hoge」が含まれる行のみ表示
printf 'a,b,c,d,e\nf,g,IAmHoge!,i,j' | grep -E '^([^,]*,){2}[^,]*Hoge[^,]*'
#ディレクトリの特定の種類のものを一覧表示
#ディレクトリのみ
ls -la | grep ^d
#ファイルのみ
ls -la | grep ^-
使いそうなオプション
  • -E : 拡張正規表現(メタ文字 "+"、"?"、"|"の追加や、()等のメタ文字化)
  • -v : マッチしない行のみ表示(inverse)
  • -i : 大文字小文字を区別しない(ignore case)
  • -B {行数} : マッチした行の前について、指定行数分表示
  • -A {行数} : マッチした行の後について、指定行数分表示
  • -c : ファイルごとにカウント(ただし、wcコマンドを使えば実現可能)
正規表現メモ

行頭:^
行末:$
任意の1文字:.
集合:[]
否定集合:[^]
1つのリテラルとして扱う:()
量化子:? * + {,}

行の絞り込み(行番号指定も可能) - sed

#5行目のみ表示
seq 1 1 10 | sed -n '5p'
#2〜5行目のみ表示
seq 1 1 10 | sed -n '2,5p'
#2行目以降のみ表示
seq 1 1 10 | sed -n '2,$p'

なお、 sed は多機能なコマンドであるため、後日別日記で取り上げることにする。

列の選択 - cut

#文字番号(1以上)で指定
printf "01   02   03\n04   05   06" | cut -c 6-7
#区切り文字指定で、フィールド番号(1以上)指定
printf "item1,item2,item3\nitem4,item5,item6" | cut -d ',' -f 2

カウント - wc

# telnetを含むログの行数
cat /var/log/messages | grep telnet | wc -l
使いそうなオプション
  • -l : 行数のみ表示

ソート - sort

#ソートされているかのチェックのみ実施。未ソートの場合はエラー表示+ステータス1
printf "01   02   03\n04   05   06" | cut -c 6-7 | sort -c

#降順ソート
printf "01   02   03\n04   05   06" | cut -c 6-7 | sort -r

#区切り文字指定で、ソートキーのフィールド番号(1以上)指定(ただし、そのフィールドから行末までの文字列をソートキーとする)
printf "item1,item4,item5,a\nitem2,item3,item5,b" | sort -t "," -k 2

#ファイル一覧を更新日時でソート(副次的に、更にファイル名でソート。なので ls -lrt とは異なる結果)
ls -l | sort -t ' ' -k 6
その他 使いそうなオプション
  • -f : 大文字小文字を区別しない
参考:ファイルリストのソート

とはいえ、ls結果のソートはlsのオプションでするのが楽でいいかもしれない。

#更新日時の降順
ls -lt
#更新日時の昇順
ls -ltr

重複 - uniq

※あらかじめソート済みである必要がある

printf 'a hoge1 a\nb hoge2 b\nc hoge1 c\n' | sort -t ' ' -k 2 | uniq -f 1 -w 6 -c
使いそうなオプション
  • -c : 各行の出現回数も表示
  • -d : 重複行だけを表示

<キー指定>

  • -f : 前から何フィールド目までをスキップした後をキーとするか(区切りは空白とタブ)
  • -s : 前から何文字目までをスキップした後をキーとするか。fも指定した場合は、fの後
  • -w : キー文字列の長さ(デフォルトは行末まですべて)(フィールドの前の区切り文字の長さも含む?)

【総まとめ】SQLとの対応

SQL
SELECT col01 FROM data_table WHERE col03 LIKE '%商事%' ORDER BY col04;
UNIXコマンド
cat data.csv | grep -E '^([^,]*,){2}[^,]*商事.*' | sort -t ',' -k 4 | cut -d ',' -f 1

data.csv

00001,山田太郎,ABC商事株式会社,2012/11/17
00002,山田太郎,ABCかつお株式会社,2012/11/17
00003,山田太郎,商事株式会社,2012/11/1
00004,山田太郎,ABC株式会社,2012/11/17
00005,山田太郎,ABC商事,2012/11/2