第27回sedこわいシェル芸勉強会

かなーり参加したかったのですが体力的に断念しました（目覚めが16時
LTも盛り上がったようなので後で Youtube 見てみます。。。

# 自分用メモ

## togetter
[第27回sedこわいシェル芸勉強会 - Togetterまとめ](https://togetter.com/li/1080314)

## youtube
[第27回シェル芸勉強会（午前／鳥海） - YouTube](https://www.youtube.com/watch?v=oeNFq5t_frc)
[第27回シェル芸勉強会（午前２／石井） - YouTube](https://www.youtube.com/watch?v=cDt2Olr0x84)
[第27回シェル芸勉強会 - YouTube](https://www.youtube.com/watch?v=BXM4pmvxrq4)
[シェル芸 のライブ ストリーム - YouTube](https://www.youtube.com/watch?v=JBax4En3EeM)

# 問題

[【問題のみ】第27回sedこわいシェル芸勉強会 – 上田ブログ](https://blog.ueda.asia/?p=9309)

# 環境

- OS: Windows10 64bit
- Shell: cmd.exe
- sed: [自作](http://qiita.com/asterisk9101/items/60ed8b0d83192d3a3503)

その他、`puts`, `seq` も自作です。

# 解答

## Q1

~~早速ですが sed.js は内部で JScript の String.replace を使って置換しているので、大文字小文字変換はできません。~~

できました。

```console:Q1
C:\> puts abcdefghijklmn | sed /e "s/(.)/$1\n/g" | sed /e "1~2y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/" | sed /ne "H;$G;$s/\r\n//gp"
AbCdEfGhIjKlMn
```

## Q2
実装間違い(後述)のため解答例よりも長いです。

```console:Q2
C:\>seq 1 100 | sed /e "1i hoge" | sed /e "1~3s/(.*)/$& fizz/;1~5s/(.*)/$& buzz/" | tail /n +1
1
2
3 fizz
4
5 buzz
6 fizz
7
8
9 fizz
10 buzz
11
12 fizz
13
14
15 fizz buzz
16
17
18 fizz
19
20 buzz
21 fizz
22
23
24 fizz
25 buzz
26
27 fizz
28
29
30 fizz buzz
31
32
33 fizz
34
35 buzz
36 fizz
37
38
39 fizz
40 buzz
41
42 fizz
43
44
45 fizz buzz
46
47
48 fizz
49
50 buzz
51 fizz
52
53
54 fizz
55 buzz
56
57 fizz
58
59
60 fizz buzz
61
62
63 fizz
64
65 buzz
66 fizz
67
68
69 fizz
70 buzz
71
72 fizz
73
74
75 fizz buzz
76
77
78 fizz
79
80 buzz
81 fizz
82
83
84 fizz
85 buzz
86
87 fizz
88
89
90 fizz buzz
91
92
93 fizz
94
95 buzz
96 fizz
97
98
99 fizz
100 buzz
```

## Q3
簡単ですね。

```console:Q3
C:\>seq 1 10 | sed /e "3h;3d;7G"
1
2
4
5
6
7
3
8
9
10
```

## Q4
後述のバグにハマったのでかなり難しかったです。方針はすぐに思いついたのに悔しい。

```console:Q4
C:\>type aho.cc | sed /e "/int main/,/}/H;/int main/,/}/d;$G"
#include <iostream>
using namespace std;


void aho(void)
{
    cout << "aho" << endl;
}
int main(int argc, char const* argv[])
{
    aho();
    return 0;
}
```

## Q5
初回に `x` すると空白行ができるの不便ですよね。

```console:Q5
C:\>seq 1 10 | sed /ne "1~2x;$G;/./p"
2
1
4
3
6
5
8
7
10
9
```

## Q6
ループですね。わかりました。

```console:Q6
C:\>puts 1 | sed /e ":a;p;s/./$&$&/;/.{5}/b;ba"
1
11
111
1111
11111
```

## Q7
この e コマンド知りませんでした。当然実装してません。

```console:Q7
C:\>echo "自作sedにeが無いので諦めました"
自作sedにeが無いので諦めました
```

## Q8
自力解答できませんでした。`tac` の動作は sed.js でも再現できていたので解答できなかったのは残念。

```console:Q8
C:\>puts 1 | sed /e ":LOOP; p;s/./$&$&/;/.{5}/b;b LOOP" | sed /e "p;1!G;h;$!d"
1
11
111
1111
11111
11111
1111
111
11
1
```

# バグ及び実装間違いについて(**全て解消済みです - 2017/8/9追記**)

## tial の n オプション
Linux 上だと `tail -n +N` すると先頭 `N-1` 行スキップになりますが、自作コマンドだと `tail /n +N` で先頭 `N` 行スキップになります。実装間違いです。

## Q2 について
Q2 では[解答例](https://blog.ueda.asia/?p=9283)よりも長々と記述していますが、これは sed がアドレス指定の `0~N` に対応していなかったからです。単純に未実装です。

```:解答例
seq 1 100 | sed '0~3s/.*/& fizz/;0~5s/.*/& buzz/'
```
```:解答
seq 1 100 | sed /e "1i hoge" | sed /e "1~3s/(.*)/$& fizz/;1~5s/(.*)/$& buzz/" | tail /n +1
```

## Q4 について
`Q4` では、sed の範囲アドレスの指定 `/int main/,/}/` を2回記述していますが、これは sed のグループ化 `{H;d}` が上手く動作しなかった（適用されるアドレスがずれた）からです。バグです。

```:解答
type temp\aho.cc | sed /e "/int main/,/}/H;/int main/,/}/d;$G"
```

```:理想
cat aho.cc | sed '/int main/,/}/{H;d};$G'
```

## Q5について

いじり回していたら GNU sed では以下のように書けるのに、 sed.js では上手く動作しませんでした。

```console:GNU_sedだと上手く動作する
seq 1 10 | sed '1h;1d;1~2x;$G'
```

Q4 と同じく、やはりアドレスの扱いに誤りがある様子。。。

# 終わりに

今回も独力で解答できたものは少なかったのですが、自作 sed はシェル芸にもそこそこ耐えうることが分かったので良かったです（小並感
~~バグと実装間違いは早めに直したいです。~~ 直しました。