awkとかsedとか
AWKはUNIX上で開発されたテキスト処理スクリプト言語である.sed,grepと並んで3種の神器なんて呼ばれていたこともあるそうです.今回はawkのGNU版であるgawkを使う.
awkによる行・列の指定
-rw-r--r-- 1 hogehoge staff 21 6 27 14:55 #blog_draft# drwx------@ 39 hogehoge staff 1326 6 27 14:58 . lrwxr-xr-x 1 hogehoge staff 30 6 27 14:54 .#blog_draft -> hogehoge@Kenta.local.3847 drwxr-xr-x+ 54 hogehoge staff 1836 6 27 13:06 .. -rw-r--r-- 1 hogehoge staff 15364 6 26 12:35 .DS_Store -rw-r--r-- 1 hogehoge staff 42770 6 7 11:37 .bash_history -rw-r--r-- 1 hogehoge staff 220 4 4 2011 .bash_logout -rw-r--r-- 1 hogehoge staff 104 4 12 11:37 .bash_profile -rw-r--r-- 1 hogehoge staff 3510 5 24 10:59 .bashrc drwxr-xr-x 5 hogehoge staff 170 6 27 14:18 .dropbox.cache -rw-r--r-- 1 hogehoge staff 5041 6 25 11:57 .emacs -rw-r--r-- 1 hogehoge staff 5098 11 12 2011 .twmrc -rw-r--r-- 1 hogehoge staff 343 11 12 2011 .xinitrc -rw-r--r-- 1 hogehoge staff 3692 3 26 19:42 CF-T5_1.icm -rw-r--r--@ 1 hogehoge staff 0 4 17 17:47 Icon -rw-r--r--@ 1 hogehoge staff 524 6 25 10:46 Makefile drwxr-xr-x@ 10 hogehoge staff 340 6 5 09:44 Photos -rw-r--r--@ 1 hogehoge staff 285 6 25 10:46 README.txt -rw-r--r-- 1 hogehoge staff 238 6 25 10:46 TODO.txt drwxr-xr-x 18 hogehoge staff 612 6 25 10:46 ac-dict -rw-r--r-- 1 hogehoge staff 132 9 15 2011 account.txt -rw-r--r-- 1 hogehoge staff 0 6 27 14:54 blog_draft
これをll.datとする.このファイルから指定の行や列を指定して値を抽出,置換したりしてみようと思う.
まずll.datから指定の列だけを表示する.余談だが,列が縦並び行が横並びなのはいいとして,行列の添字のどちらが列番号なのか未だに混乱する.rと↓,cと←,というように形状から覚えるのがセオリーか.
$ gawk '{print $1}' < ll.dat total -rw-r--r-- drwx------@ lrwxr-xr-x drwxr-xr-x+ …
見て分かる通り$1を表示しますという命令をll.datに対して行なっている.列番号は左から順に$1から格納されている.つまり
$1 | $2 | $3 | $4 | $5 | $6 | $7 | $8 | $9 -rw-r--r-- | 1 | hogehoge | staff | 21 | 6 | 27 | 14:55 | #blog_draft#
というようになる.print $9などとればファイルネームだけを取り出すことができる.
一方,行は条件式という形で指定する.
$ gawk 'NR==5 {print $0}' < ll.dat Drwxr-xr-x+ 54 hogehoge staff 1836 6 27 13:06 ..
数行まとめて表示するには
$ gawk 'NR<10 && NR>20 {print $0}' < ll.dat
とすればOK.
NRは特別な変数であり行番号を指定することができる.{}の左側には条件式を書くことができ,そこで行番号を指定する.
なお,printに渡した変数$0にはすべての数字が格納されている.
これで行と列が指定できるようになったので任意の要素へアクセスすることができる.
$ gawk 'NR==5 {print $5}' < ll.dat 1836
正規表現を用いる場合は
$ gawk '$0~/.*txt/ {print $0}' < ll.dat -rw-r--r--@ 1 hogehoge staff 285 6 25 10:46 README.txt -rw-r--r-- 1 hogehoge staff 238 6 25 10:46 TODO.txt -rw-r--r-- 1 hogehoge staff 132 9 15 2011 account.txt
などとすればよい.
[追記:2012.07.08]列を指定する変数 => NR
awkやらsedやらで置換
次に文字列の置換を行う.
$ gawk '$2==1 {$2=5;print $0}' < ll.dat -rw-r--r-- 5 hogehoge staff 21 6 27 14:55 #blog_draft# lrwxr-xr-x 5 hogehoge staff 30 6 27 14:54 .#blog_draft -> hogehoge@Kenta.local.3847 -rw-r--r-- 5 hogehoge staff 15364 6 26 12:35 .DS_Store -rw-r--r-- 5 hogehoge staff 42770 6 7 11:37 .bash_history ...
「2列目の要素が1のものだけを表示して,その要素に5を代入」という処理である.かなり直感的で嬉しい.しかしまあ置換を行う場合はawkよりもsedの方がずっと簡単である.
sedの簡単な使い方は,以下のように-nオプションで行数を指定して出力するというものである
$ sed -n '5,10p' ll.dat drwxr-xr-x+ 54 hogehoge staff 1836 6 27 13:06 .. -rw-r--r-- 1 hogehoge staff 15364 6 26 12:35 .DS_Store -rw-r--r-- 1 hogehoge staff 42770 6 7 11:37 .bash_history -rw-r--r-- 1 hogehoge staff 220 4 4 2011 .bash_logout -rw-r--r-- 1 hogehoge staff 104 4 12 11:37 .bash_profile -rw-r--r-- 1 hogehoge staff 3510 5 24 10:59 .bashrc
置換を行う場合は以下のようにsとgで置換前と置換後の語を指定する.
$ sed 's,r,R,g' ll.dat total 9408 -Rw-R--R-- 1 hogehoge staff 21 6 27 14:55 #blog_dRaft# dRwx------@ 39 hogehoge staff 1326 6 27 14:58 . lRwxR-xR-x 1 hogehoge staff 30 6 27 14:54 .#blog_dRaft -> hogehoge@Kenta.local.3847 dRwxR-xR-x+ 54 hogehoge staff 1836 6 27 13:06 .. -Rw-R--R-- 1 hogehoge staff 15364 6 26 12:35 .DS_StoRe -Rw-R--R-- 1 hogehoge staff 42770 6 7 11:37 .bash_histoRy ...
Perlなどと同様の置換方法となっている.つまり's/r/R/g'でもs|r|R|g'でも実行することができる.gは一括変換を意味し,もし's,r,R,'とすれば
$ sed 's,r,R,' ll.dat total 9408 -Rw-r--r-- 1 hogehoge staff 21 6 27 14:55 #blog_draft# dRwx------@ 39 hogehoge staff 1326 6 27 14:58 . lRwxr-xr-x 1 hogehoge staff 30 6 27 14:54 .#blog_draft -> hogehoge@Kenta.local.3847 ...
のように一番初めのrがRに変換されることになる.