hack のためのネタ帳, etc,,,

基本的な設定

オプションとして -nlaF"[ ]+" を与えておくと、ほぼ awk と同じ使い方が出来る。

オプション n は awk ライクな処理をするためにプログラム全体が以下のコードで囲まれる。
while gets
  # ...
end
オプション l は行末の自動処理の指定。$\を$/と同じ値にすることでprintの末尾に改行(と言うか$\)が追加され、入力も $_.chop! として行末の空白が処理される。
オプション a はオートスプリットモードの指定。n オプションによる各ループの先頭で以下のコードが実行される。
$F = $_.split
オプション F は入力セパレーターの指定。正規表現で指定出来る。

変数等の対応

大まかな変数の対応は以下の通り。
awkruby意味
ARGV[0]$0実行中のコマンド
ARGV[1]ARGV[0]コマンドライン引数
ARGCARGV.lengthコマンドライン引数の数
$0$_入力行全体
$1$F[0]フィールド分割済入力行
NF$F.lengthフィールド数
FNRARGF.file.lineno読込済行数(現在の入力)
NRARGF.lineno読込済行数(入力全体)
FILENAME$FILENAME現在の入力のファイル名
FS$;フィールドセパレーター
RS$/レコードセパレーター

前処理、後処理用の BEGIN, END も使える。

1liner の例

1フィールド目の合計を計算する場合、例えば以下のように書ける。
$ # AWK の場合
$ awk '{sum+=$1}END{print sum}' a.txt
$ # Ruby の場合
$ ruby -nlaF"[ ]+" -e 'BEGIN{sum=0};sum+=$F[0].to_i;END{puts sum}' a.txt

スクリプトファイルの例

Ruby は環境によってインストールされているパスが異なる場合が少なくないため、Shebang に直接絶対パスで指定するとポータブルなコードにならない。
これを回避するためには /usr/bin/env を使うと便利なのだが Shebang では引数を2つ以上取れないので以下のような書き方が出来ない。
#!/usr/bin/env ruby -lnaF"[ ]+"
これを解決するには、若干面倒ではあるが /bin/sh から exec を使うことで、オプションを付きで起動させる事が出来る(公式マニュアルだと magic comment の説明のところに例がある)。

sum.rb

#!/bin/sh
exec ruby -lnaF"[ ]+" -x "$0" "$@"
#!ruby
# encoding: utf-8
BEGIN {sum = 0}
sum += $F[0].to_i
END {puts "合計 = %d" % sum}
-x オプションは #! で始まり ruby を含む行までを読み飛ばしてくれる。

上記の例では入力データが UTF-8 以外の場合、UTF-8 で不正な文字が含まれるため split の際に以下のようなエラーが発生してしまう。
$ ./sum.rb a.txt
./sum.rb:7:in `split': invalid byte sequence in UTF-8 (ArgumentError)
        from ./sum.rb:7:in `<main>'
これを回避するには、以下のようにして環境変数 LANG を一時的に変更した状態で起動させると良い。
$ LANG=sjis ./sum.rb a.txt

入力ファイルの文字コードが決め打ち出来る場合には exec 行を以下のように書き換えても良いかもしれない。
exec ruby -Esjis -lnaF"[ ]+" -x "$0" "$@"

文字コードの自動判別をさせたい場合は AWK ライクにせず普通に書いたほうが良いかも???

参考

関連

コメントをかく


「http://」を含む投稿は禁止されています。

利用規約をご確認のうえご記入下さい

Wiki内検索

フリーエリア

管理人/副管理人のみ編集できます