きまぐれメモ

2010-12-06

Perlによるワンライナー

ワンライナーを書くときに便利なオプション

-e オプション

続く文字列ワンライナーだと認識させる。シェルによる解釈を防ぐためにシングルクォートで囲む。

$ perl -e 'print "hello world\n"'
hello world
-n オプション

プログラム全体をwhile(<>){...}で囲ったものと同じ効果が得られる。

$ perl -ne 'print "$_\n"' input.txt

while{<>}{
    print "$_\n"
}

を実行させたのと同じである

-l オプション

出力に改行文字をつける。

$ perl -ne 'print "a \n"' input.txt

$ perl -nle 'print "a "' input.txt

と同じ意味である

-a オプション

@F=split(/ /,$_)と同じ意味デフォルト変数$_をスペースで区切って@Fに格納。awkのようなカラム処理をするときに必要。

$ perl -nle '@F=split(/ /,$_); print "$F[0]"' input.txt

$ perl -nlae 'print "$F[0]"' input.txt

と同じ意味

-F オプション

デフォルトでは、-aオプションの区切り文字はスペースだが、それを変更したいときに使う。

$ cat input.txt
1,2,3
4,5,6
$ perl -F, -nlae 'print $F[0]' input.txt
1
4

ワンライナー20

プログラム言語AWKに載っている"便利 な「一行野郎」たち"をperl翻訳した。awkによる例とともに示す。

1. 入力行の総数を出力する
$ awk       'END{print NR}' input.txt
$ perl -nle 'END{print $.}' input.txt 

awkでは行番号はNRに格納されているのに対し、perlでは$.に格納されている。

2. 10行目の入力行を出力する
$ awk       'NR == 10'             input.txt
$ perl -nle 'if($. == 10){print }' input.txt

awkは'パターン{アクション}'という構文をとるのだが、アクション入力行をそのまま出力する、つまり、{print $0}の場合は省略できるので、非常にシンプルに書ける。perlではprint文の対象が$_の場合、省略ですることができる。

3. すべての入力行の最後カラムを出力する
$ awk        '{print $NF}'  input.txt
$ perl -nlae 'print $F[-1]' input.txt

awkではNFカラム数を格納する変数なので、最後カラムは$NFで参照できるのに対し、perlでは$F[-1]を使って参照している。

4. 最後の行の最後カラムを出力する
$ awk        '{f = $NF} END{print f}'     input.txt
$ perl -nlae '$f = $F[-1]; END{print $f}' input.txt
5. カラム数が4を超える行を出力する
$ awk        'NF > 4'             input.txt
$ perl -nlae 'if(@F > 4){print }' input.txt 
6. 最後カラムの値が4を超えるようなすべての行を出力する
$ awk        '$NF > 4'                input.txt  
$ perl -nlae 'if($F[-1] > 4){print }' input.txt
7. すべての入力行のカラムの総数を出力する
$ awk        '{c  += NF}END{print c}'  input.txt
$ perl -nlae '{$c += @F}END{print $c}' input.txt

perlでは配列スカラコンテキストで評価すると要素数が返ってくる。

8. Bethを含む行の総数を出力する
$ awk       '/Beth/{sum++}END{print sum}'       input.txt
$ perl -nle 'if(/Beth/){$sum++}END{print $sum}' input.txt
9. 第一カラムが最も大きな行を出力する(第一カラムのうち少なくとも1つは正の数であると仮定)
$ awk        '$1 > max{max = $1; ml = $0}END{print ml}'    input.txt
$ perl -nlae 'if($F[0] > $ml[0]){@ml = @F}END{print "@ml"}' input.txt
10. 少なくとも1つのカラムをもつ行をすべて出力する
$ awk        'NF > 0'             input.txt
$ perl -nlae 'if(@F > 0){print }' input.txt 
11. 80文字以上の長さを持つ行をすべて出力する
$ awk       'length($0) >= 80)'            input.txt
$ perl -nle 'if(length($_) >= 80){print }' input.txt
12. 行のカラム数とその行自体を出力する
$ awk        '{print NF, $0}'         input.txt
$ perl -nlae 'print scalar(@F)," $_"' input.txt 
13. すべての行の最初の2つのカラムを逆順で出力する
$ awk        '{print $2, $1}'      input.txt
$ perl -nlae 'print "$F[1] $F[0]"' input.txt 
14. すべての行の最初の2つのカラムを逆順にしてすべてのカラムを出力する
$ awk        '{t = $1; $1 = $2; $2 = t; print }'           input.txt
$ perl -nlae '($F[0], $F[1]) = ($F[1], $F[0]); print "@F"' input.txt
15. すべての行を最初カラムを行番号に置き換えて出力する
$ awk        '{$1 = NR; print }'    input.txt
$ perl -nlae '$F[0]=$.; print "@F"' input.txt
16. すべての行の2つ目のカラムを消去して出力する
$ awk        '{$2 = ""; print}'           input.txt
$ perl -nlae 'splice(@F,1,1); print "@F"' input.txt
17. すべての行のカラムを逆順で出力する
$ awk        '{for(i = NF; i > 0; i--){printf("%s ", $i)}printf("\n")}' input.txt
$ perl -nlae '@F=reverse @F; print "@F"'                                input.txt

awkの方が長くなってしまう。perlにはreverse関数があるので簡潔に書ける。

18. すべての行の各カラムの合計を出力する
$ awk        '{sum = 0; for(i = 1; i <= NF; i++){sum += $i}print sum}' input.txt
$ perl -nlae '$sum=0; for(@F){$sum += $_}print $sum'                   input.txt
19. すべての行のすべてのカラムを合計してその値を出力する
$ awk        '{for(i = 1; i <= NF; i++){sum += $i}}END{print sum}' input.txt
$ perl -nlae 'for(@F){$sum += $_}END{print $sum}'                  input.txt
20. 各カラムの値を絶対値に置き換えてからすべての行を出力する
$ awk        '{for(i = 1; i <= NF; i++){if($i<0){$i *= -1}}print }' input.txt
$ perl -nlae '@F = map{abs($_)} @F; {print "@F"}'                   input.txt

perlには絶対値を返す関数absがあるが、awkにはない。perlではmap関数を使うことにより簡潔にかける。

後半の、for文を使うようなものではperlの方が短くなった。

To Heart同人誌To Heart同人誌 2011/04/01 15:07
同意しますが、何が基礎なのか正確に知らないと、やったつもりで終わると思います。

スパム対策のためのダミーです。もし見えても何も入力しないでください
ゲスト


画像認証