AWKは、PythonやRubyに比べれば古くさいイメージがあります。 しかし、ワンライナーとしてはAWKは強力(という話)です。
そこで、一度覚えておけば、きっと役立つ機会は多かろうということで、 AWKワンライナーのよくありそうなパターンを7つ調べてみました。
なお、参考にシェルスクリプト版(sedやgrepを使ったワンライナー)も併記しました。
1. 要素を取り出してフォーマットする
入力:
# 言語名 コマンド名 バージョン番号 echo -e "\ Perl\tperl\t5.14.2 Python\tpython\t2.7.3 Ruby\truby\t1.9.3p194 PHP\tphp\t5.4.6-1 AWK\tawk\t4.0.1" > /tmp/langs
# "コマンド-バージョン番号" に変換 cat /tmp/langs | awk '{ print $2 "-" $3 }'
cat /tmp/langs | sed -e 's/\([^\t]*\)\t\([^\t]*\)\t\([^\t]*\)/\2-\3/'
出力:
perl-5.14.2 python-2.7.3 ruby-1.9.3p194 php-5.4.6-1 awk-4.0.1
2. タブ以外の区切りを使う
入力:
# CSVファイル echo "\ name,price_per_100g,weight pork,99,1200 beaf,120,1400 chicken,68,2300" > /tmp/meats.csv
# 肉の種類と重さを出力 cat /tmp/meats.csv | awk -F',' '{ print $1 "," $3 }'
cat /tmp/meats.csv | cut -d , -f 1,3
出力:
name,weight pork,1200 beaf,1400 chicken,2300
3. 正規表現にマッチした行を出力する
入力:
# 言語名 コマンド名 バージョン番号 echo -e "\ Perl\tperl\t5.14.2 Python\tpython\t2.7.3 Ruby\truby\t1.9.3p194 PHP\tphp\t5.4.6-1 AWK\tawk\t4.0.1" > /tmp/langs
ワンライナー:
# 言語名にrを含む言語の行を出力 cat /tmp/langs | awk -v IGNORECASE=1 '$1 ~ /r/ { print $0 }'
cat /tmp/langs | grep --ignore-case -E "`echo -e '^[^\tr]*r[^\t]*\t'`"
出力:
Perl perl 5.14.2 Ruby ruby 1.9.3p194
4. 正規表現のマッチを置換する
入力:
echo "\ float pi(void); int floor(float x); pi() + bar(2.5); void printf(char* format, ...); printf("%s", 0);" > /tmp/code
# C言語風の宣言を、C++0x風の後置型の宣言に cat /tmp/code | awk '{ print gensub(/([a-z]+)\s+(.*);/, "auto \\2 -> \\1;", 1, $0) }'
cat /tmp/code | sed -e 's/\([a-z]\+\)[[:space:]]\+\(.*\);/auto \2 -> \1;/'
出力:
auto pi(void) -> float; auto floor(float x) -> int; pi() + bar(2.5); auto printf(char* format, ...) -> void; printf(%s, 0);
5. 整数として計算する
入力:
# 肉の種類 100gあたり価格 グラム数 echo -e "\ pork\t99\t1200 beaf\t120\t1400 chicken\t68\t2300" > /tmp/meats
cat /tmp/meats | awk '{ print $1, $2 * $3, "円"}'
# 肉の種類 金額 cat /tmp/meats | while read line; do cols=($line) echo ${cols[0]} `expr ${cols[1]} '*' ${cols[2]}` 円 done
出力:
pork 118800 円 beaf 168000 円 chicken 156400 円
6. 他のコマンドを呼び出す
入力:
# 言語名 コマンド名 バージョン番号 echo -e "\ Perl\tperl\t5.14.2 Python\tpython\t2.7.3 Ruby\truby\t1.9.3p194 PHP\tphp\t5.4.6-1 AWK\tawk\t4.0.1" > /tmp/langs
# "コマンド名 コマンドのフルパス" cat /tmp/langs | awk '{ "which " $2 | getline t; print $2, t }'
for cmd in `cat /tmp/langs | cut -f 2`; do echo -e "$cmd" `which $cmd` done
出力:
perl /usr/bin/perl python /usr/bin/python ruby /usr/bin/ruby php /usr/bin/php awk /usr/bin/awk
7. Schwartz変換ソート
入力:
# 言語名 コマンド名 バージョン番号 echo -e "\ Perl\tperl\t5.14.2 Python\tpython\t2.7.3 Ruby\truby\t1.9.3p194 PHP\tphp\t5.4.6-1 AWK\tawk\t4.0.1" > /tmp/langs
# メジャーバージョン - マイナーバージョン - リリースバージョン でソート # シェルスクリプトと代わり映えしないなぁ・・・ cat /tmp/langs \ | awk '{ print gensub(/(.*)\.(.*)\.(.*)/, "\\1\t\\2\t\\3\t", 1, $3), $0}' \ | sort --key=1,3 \ | awk '{ print $4 "\t" $5 "\t" $6 }'
cat /tmp/langs \ | sed -e "s/[^\t]*\t[^\t]*\t\(.*\)\.\(.*\)\.\(.*\)/\1\t\2\t\3\t\0/" \ | sort --key=1,3 \ | cut -f 4-
出力:
JavaScript node 0.6.19 Ruby ruby 1.9.3p194 Python python 2.7.3 Perl perl 5.14.2 PHP php 5.4.6-1