[sed] sedのホールドスペースの練習

2017年5月8日月曜日

awk sed unix シェルスクリプト

[awk,Ruby,C#,Java]いくつかの言語でフィボナッチ数生成でawkとかを使ってフィボナッチ数列を生成したけど、sedでこれができないかなーと思ってやってみた。

sedでフィボナッチ数列生成

sedは数値演算を直接サポートしていないので、文字列の長さを数字とみなしてみる。

$ seq 10 |
> sed -n -e '1{h;H;p;}; 1!{g;s/^\(.*\)\(\n\)\(.*\)$/\3\2\1\3/;h;P;}'
1
1
11
111
11111
11111111
1111111111111
111111111111111111111
1111111111111111111111111111111111
1111111111111111111111111111111111111111111111111111111
$

1行目をホールドスペースにコピーして、さらに追加しているので、ホールドスペースは以下になる。
"1\n1"
2行目以降はホールドスペースをパターンスペースにコピーして、改行の前後で切って、前後を入れ替えて後ろのは前後をくっつける。
例えば、ホールドスペースが "1\n2" だったら、 "2\n12" にする。
その後、hコマンドで再びホールドスペースに戻して、Pコマンドでパターンスペースの先頭から改行までをプリントする。

ただし、これだと生成される文字列の長さがすぐに大きくなってしまうし、sedも実装によってはバッファイサイズに制限があるので、注意しよう。
一応、POSIXではバッファは8192バイトはあるようにしろよってことみたい。
5. GNU sedの制限と制限されていないこと
The Open Group Base Specifications Issue 7 sed

文字列長を数字に変換

最後に文字列を文字列長に変換する。

$ seq 10 |
> sed -n -e '1{h;H;p;}; 1!{g;s/^\(.*\)\(\n\)\(.*\)$/\3\2\1\3/;h;P;}' |
> awk '{ print length($0) }'
1
1
2
3
5
8
13
21
34
55
$

sedでやるって言っておきながら、各行の文字数をawkで数えてるってのがなぁという気もするけど、各行の文字数をカウントするいい方法が他に思いつかない...

FizzBuzzもやってみる

Nコマンドを使って、FizzBuzzもやってみよう。かなり強引だけど。

$ seq 30 |
> sed -n -e 'N;p;n;s/^.*$/Fizz/;p' |
> sed -n -e 'N;N;N;p;n;s/^.*$/Buzz/;p' |
> sed -n -e 'N;N;N;N;N;N;N;N;N;N;N;N;N;p;n;s/^.*$/FizzBuzz/;p'
1
2
Fizz
4
Buzz
Fizz
7
8
Fizz
Buzz
11
Fizz
13
14
FizzBuzz
16
17
Fizz
19
Buzz
Fizz
22
23
Fizz
Buzz
26
Fizz
28
29
FizzBuzz
$