sedのパターンスペース・ホールドスペースの動作を図で学ぶ

# 概要
`sed`は、入力ストリームに対して様々なテキスト変換をおこなう、ストリームエディタです。
`cut`, `grep`, `tr`といった基本的なフィルタコマンドと比較して、柔軟なテキスト処理が可能です。
この`sed`の機能の1つとして、パターンスペース・ホールドスペースがあります。
高度なテキスト処理が可能になる反面、パターンスペース・ホールドスペースは、動作が理解し辛いという難点があります。
ですが、`sed`のパターンスペース・ホールドスペースの動作を丁寧に解説した記事は、私が探した限りでは見つかりませんでした。
そこで、`sed`を深く学ぶ方への助けとして、また私自身の復習として、`sed`のパターンスペース・ホールドスペースの動作を、記事としてまとめました。
<br>

本記事では、`sed`のパターンスペース・ホールドスペースの動作を、図示して解説します。

# 実行環境

- Arch Linux 4.8.8-2-ARCH
- GNU bash 4.4.5
- GNU coreutils 8.25-2
- sed (GNU sed) 4.2.2

<br>

#### シェル芸でのみ使用

- GNU findutils 4.6.0-2
- grep (GNU grep) 2.26
- gawk 4.1.4
- nkf 2.1.4
- mecab 0.996

<!---
<br>
* usp Personal Tukubai (20161107、 [Open usp Tukubai](https://github.com/usp-engineers-community/Open-usp-Tukubai)で代用可能)
--->

# 解説

## 前提知識の解説

まず、本記事を読むにあたり、前提知識となる`sed`の動作を、ホールドスペース抜きで解説します。

`sed`は、各レコードをパターンスペースに取り込み、パターンスペース(またはホールドスペース)に対して各コマンドを順次実行します。
この際、後に実行するコマンドは、先に実行したコマンドの処理結果の影響を受けます。
正確には、前述の通り、 **パターン(ホールド)スペースの内容に対して、各コマンドの処理が順次実行** されます。
以下、一例を示します。

※本記事は、`sed`の基本的な使い方を知っている方を、対象としています。
したがって、`sed`の各コマンドの意味や、ホールド・パターンスペースとは何かについては、本記事では解説しません。
必要に応じて、`man sed`や、書籍『sed & awkプログラミング 改訂版』を参照してください。

```sh
$ cat poem
Hey Siri, show me the magic!
I'm afraid I cannot do it.
$ cat poem | sed 's/Siri/Ketu/; /not/s/.*/Sure./; /Sure/aただし魔法は尻から出る'
Hey Ketu, show me the magic!
Sure.
ただし魔法は尻から出る
```

上記の処理を、各レコード・各コマンドについて、それぞれ説明します。

まず、1レコード目の入力、`Hey Siri, show me the magic!`を、`sed`はパターンスペースに取り込みます。

![fig1-1-1.jpg](https://qiita-image-store.s3.amazonaws.com/0/102349/a7aa0c60-b13d-8763-080f-9121e9bebf91.jpeg)

レコードをパターンスペースに取り込んだ後、パターンスペースに対してコマンドを順次実行していきます。
初めに、1番目の`s`コマンドを実行します。
その結果、パターンスペースの`Siri`という文字列が、`Ketu`に置換されます。

![fig1-1-2.jpg](https://qiita-image-store.s3.amazonaws.com/0/102349/d5dde3ef-a659-8a6c-01f9-45144b29c8bc.jpeg)


次に、2番目の`s`コマンド、最後の`a`コマンドが適用されます。
ただし、それぞれアドレスに正規表現`/not/`、`/Sure/`が指定されているため、現在のパターンスペースにはマッチせず、今回はどちらも実行されません。

![fig1-1-3.jpg](https://qiita-image-store.s3.amazonaws.com/0/102349/2b0c93d0-3933-25be-341d-cb01828f1268.jpeg)

全コマンドの適用が終わった後は、`sed`のデフォルトの動作として、パターンスペースの内容が自動的に出力されます。
今回の場合、`s/Siri/Ketu/`が実行された結果が、出力されます。

![fig1-1-4.jpg](https://qiita-image-store.s3.amazonaws.com/0/102349/92943fc6-342a-53c9-5d36-4c9298827076.jpeg)

----

次に、2レコード目の入力、`I'm afraid I cannot do it.`を、パターンスペースに取り込みます。

![fig1-2-1.jpg](https://qiita-image-store.s3.amazonaws.com/0/102349/3c8e1afa-c00b-ca04-4d53-f0e6bbd030f5.jpeg)

レコードをパターンスペースに取り込んだ後は、1レコード目と同様に、コマンドを順次実行していきます。
まず、1番目の`s`コマンドを実行します。
ただし、現在のパターンスペースは正規表現`/Siri/`にマッチしないため、結果的に何も処理がおこなわれません。

![fig1-2-2.jpg](https://qiita-image-store.s3.amazonaws.com/0/102349/4228a2c2-7f63-a343-0dfc-b5a37bb76dc9.jpeg)

次に、2番目の`s`コマンドを実行します。
今回、パターンスペースに文字列`not`が含まれているため、2番目の`s`コマンドは実行され、パターンスペースの内容は`Sure.`に置換されます。

![fig1-2-3.jpg](https://qiita-image-store.s3.amazonaws.com/0/102349/122b16fb-d1c0-46d5-eb4c-2335caeddf69.jpeg)

そして、3番目のコマンド`a`のアドレス、正規表現`/Sure/`にマッチするかどうかを判定します。
ここで、判別対象は、 **2番目の`s`コマンドが実行された後のパターンスペース** が用いられます。
したがって、パターンスペース`Sure.`に正規表現`/Sure/`にマッチし、3番目の`a`コマンドが実行されます。
その結果、パターンスペースに`ただし魔法は尻から出る`が追記されます。

![fig1-2-4.jpg](https://qiita-image-store.s3.amazonaws.com/0/102349/10a82024-438f-006c-c35b-cd6469269d8f.jpeg)

そして最後に、1レコード目と同様に、全コマンド実行後のパターンスペースが出力されます。

![fig1-2-5.jpg](https://qiita-image-store.s3.amazonaws.com/0/102349/38bf577c-cdd2-2e00-ab54-3e01235252de.jpeg)

----

上記の処理過程の結果、次の内容が出力されます。

```
Hey Ketu, show me the magic!
Sure.
ただし魔法は尻から出る
```

以上が、前提知識となる`sed`の基本動作になります。

----

ここで、繰り返しになりますが、 **`sed`の各コマンドは、パターンスペースに対して順次実行される** 事に、留意してください。

次に、2つの実用的な`sed`スクリプトを用いて、ホールドスペースを含めた動作を解説します。


## 例題1

Linuxの`tac`や、BSDの`tail -r`のように、入力レコードを反転して出力するスクリプトを用いて、パターンスペース・ホールドスペースの動作を解説します。
以下、入力データとスクリプトの実行例を示します。

```sh
$ cat shells
シェル変態
シェル戦隊
シェル軟体
シェル倦怠
$ cat shells | sed '1!G; $!h; $!d'
シェル倦怠
シェル軟体
シェル戦隊
シェル変態
```

上記の処理を、各レコード・各コマンドについて、それぞれ説明します。

まず、前セクションの例と同様に、1行目の入力レコード`シェル変態`を、パターンスペースへと取り込みます。

![fig2-1-1.jpg](https://qiita-image-store.s3.amazonaws.com/0/102349/f4ea08f2-3092-559a-4ed4-8e10d195075e.jpeg)

次に、1番目の`G`コマンドを適用し、ホールドスペースの内容を、パターンスペースへと追記します。
ただし、`G`コマンドのアドレスは1行目以外`1!`に指定されているため、今回は実行しません。
(アドレス`1!`を指定せずに実行した場合、パターンスペースに空行が追記されます。)

![fig2-1-2.jpg](https://qiita-image-store.s3.amazonaws.com/0/102349/ceb2ac92-c651-136b-9915-a02fdf405dff.jpeg)

その後、2番目の`h`コマンドを実行し、現在のパターンスペースの内容`シェル変態`を、ホールドスペースへとコピーします。

![fig2-1-3.jpg](https://qiita-image-store.s3.amazonaws.com/0/102349/0b39287d-37c3-1f85-96d1-40f73e03e905.jpeg)

そして、3番目の`d`コマンドを実行し、パターンスペースの内容を削除します。
ここで、ホールドスペースの内容は削除されない事に、着目してください。

![fig2-1-4.jpg](https://qiita-image-store.s3.amazonaws.com/0/102349/70394e52-b61e-bf4d-7ed2-e1682a930909.jpeg)

最後に、全コマンドを実行した状態のパターンスペースが、`sed`の自動出力機能によって出力されます。
ただし、 **3番目の`d`コマンドによってパターンスペースの内容は削除されているため、ここでは何も出力されません** 。

![fig2-1-5.jpg](https://qiita-image-store.s3.amazonaws.com/0/102349/0bce71b2-cf1d-0e79-bac6-fd7f42c23ea7.jpeg)

----

次に、2行目の入力レコード`シェル戦隊`を、処理していきます。
1行目と同様に、まず入力レコードをパターンスペースへと取り込みます。

![fig2-2-1.jpg](https://qiita-image-store.s3.amazonaws.com/0/102349/3ced96ca-7aa1-6cc3-c19c-a1b52f215b77.jpeg)

次に、1番目の`G`コマンドを実行し、ホールドスペースの内容`シェル変態`を、パターンスペースへと追記します。
今回は、2行目であるため、アドレス`1!`に該当し、`G`コマンドは実行されます。
その結果、パターンスペースの内容は、`シェル戦隊\nシェル変態`になります。

![fig2-2-2.jpg](https://qiita-image-store.s3.amazonaws.com/0/102349/06ab901a-29c9-0aa3-9ed3-3a31aa2a99e0.jpeg)

その後、2番目の`h`コマンドを実行し、現在のパターンスペースの内容`シェル戦隊\nシェル変態`を、ホールドスペースへとコピーします。
ここで、 **直前の`G`コマンドの処理によって変化したパターンスペースを用いる** ことに、留意してください。
また、1行目の処理でホールドスペースにコピーした内容`シェル変態`は、上書きされます。
(`h`の代わりに`H`コマンドを使うと、上書きコピーではなく追記になります。)

![fig2-2-3.jpg](https://qiita-image-store.s3.amazonaws.com/0/102349/895bfe2f-0fca-65ef-0b64-b5b8bb63dea1.jpeg)

そして、3番目の`d`コマンドを実行し、パターンスペースの内容を削除します。

![fig2-2-4.jpg](https://qiita-image-store.s3.amazonaws.com/0/102349/8437e3cd-ddf5-6ec7-a561-7fe368946ba4.jpeg)

最後に、全コマンドを実行した状態のパターンスペースが、`sed`の自動出力機能によって出力されます。
ただし、3番目の`d`コマンドによってパターンスペースの内容は削除されているため、今回も何も出力されません。

![fig2-2-5.jpg](https://qiita-image-store.s3.amazonaws.com/0/102349/03c4da46-c75b-32b1-5dda-4f310c1c8d78.jpeg)

----

そして、3レコード目の`シェル軟体`の処理をおこないます。
この3レコード目の動作は、2レコード目の動作と同様であるため、詳細な解説は省きます。

![fig2-3-1.jpg](https://qiita-image-store.s3.amazonaws.com/0/102349/d3c77040-3cfd-a8ea-ef5c-430bfcde592d.jpeg)

----

最後に、末尾行である4レコード目を処理します。

まず、入力レコード`シェル倦怠`を、パターンスペースへと取り込みます。

![fig2-4-1.jpg](https://qiita-image-store.s3.amazonaws.com/0/102349/e1513fb2-0c8d-8036-9b95-05f51b85b482.jpeg)

次に、1番目の`G`コマンドを実行し、ホールドスペースの内容`シェル倦怠\nシェル軟体\nシェル戦隊`を、パターンスペースへと追記します。

![fig2-4-2.jpg](https://qiita-image-store.s3.amazonaws.com/0/102349/04a6717b-7148-7eb8-bad4-e9b21c2fcc92.jpeg)

そして、2・3番目の`h`と`d`コマンドを適用します。
ただし、両方共アドレスが末尾行以外`$!`に指定されているため、今回は実行しません。

![fig2-4-3.jpg](https://qiita-image-store.s3.amazonaws.com/0/102349/dc020ddf-614c-0d72-860d-0750954631e9.jpeg)

最後に、全コマンドを実行した状態のパターンスペース`シェル倦怠\nシェル軟体\nシェル戦隊\nシェル変態`が、`sed`の自動出力機能によって出力されます。

![fig2-4-4.jpg](https://qiita-image-store.s3.amazonaws.com/0/102349/b703caaa-08ee-0a5f-25e2-9fccdb19a8f6.jpeg)


以上が、`tac`や`tail -r`と同等の動作、`sed`を用いた入力レコードの反転処理になります。


## 例題2

今度は、入力レコードを縦方向に対称に出力するスクリプトを用いて、パターンスペース・ホールドスペースの動作を再度解説します。
以下、入力データとスクリプトの実行例を示します。

```sh
$ cat saga
よいかジェラール
われわれはインペリアルクロス
という陣形で戦う
$ cat saga | sed '$!p; 1!G; $!h; $!d'
よいかジェラール
われわれはインペリアルクロス
という陣形で戦う
われわれはインペリアルクロス
よいかジェラール
```

上記の処理を、各レコード・各コマンドについて、それぞれ説明します。

まず、これまでの例と同様に、1行目の入力レコード`よいかジェラール`を、パターンスペースへと取り込みます。

![fig3-1-1.jpg](https://qiita-image-store.s3.amazonaws.com/0/102349/9a5f64b2-e3c4-c2bc-d663-cc9e9afa95af.jpeg)

次に、1番目の`p`コマンドを実行し、現在のパターンスペースの内容`よいかジェラール`を出力します。

![fig3-1-2.jpg](https://qiita-image-store.s3.amazonaws.com/0/102349/92f438b1-60c9-3770-0b31-e15c9541b8ba.jpeg)

その後、2番目の`G`コマンドを適用します。
ただし、アドレスに1行目以外`1!`が指定されているため、今回は`G`コマンドは実行されません。

![fig3-1-3.jpg](https://qiita-image-store.s3.amazonaws.com/0/102349/ee3a48cf-1731-053b-f6e8-8ce95a1dc667.jpeg)

そして、3番目の`h`コマンドを実行し、パターンスペースの内容`よいかジェラール`を、ホールドスペースへとコピーします。

![fig3-1-4.jpg](https://qiita-image-store.s3.amazonaws.com/0/102349/9c11f68c-a2d4-3f4a-d497-7eceec1a5cc7.jpeg)

また、4番目の`d`コマンドを実行し、パターンスペースの内容を削除します。

![fig3-1-5.jpg](https://qiita-image-store.s3.amazonaws.com/0/102349/f5184ac3-b733-dfb3-0f23-161609482bc8.jpeg)

最後に、全コマンドを実行した状態のパターンスペースが、`sed`の自動出力機能によって出力されます。
ただし、直前の`d`コマンドによってパターンスペースの内容は削除されているため、ここでは何も出力されません。

![fig3-1-6.jpg](https://qiita-image-store.s3.amazonaws.com/0/102349/c6ff3096-2d0c-1492-b3b4-31283389f327.jpeg)


----

次に、2行目の入力レコード`われわれはインペリアルクロス`を、処理していきます。
まず、1行目と同様に、入力レコードをパターンスペースへと取り込みます。

![fig3-2-1.jpg](https://qiita-image-store.s3.amazonaws.com/0/102349/84a7a468-4702-afe9-421a-41e2261afc9b.jpeg)

次に、1番目の`p`コマンドを実行し、現在のパターンスペースの内容`われわれはインペリアルクロス`を出力します。

![fig3-2-2.jpg](https://qiita-image-store.s3.amazonaws.com/0/102349/714a0028-2dd1-49ee-6ba7-88034440ae04.jpeg)

その後、2番目の`G`コマンドを実行します。
1行目では実行されませんでしたが、今回はアドレス`1!`にマッチするため、ホールドスペースの内容`よいかジェラール`が、パターンスペースに追記されます。
その結果、パターンスペースの内容は、`われわれはインペリアルクロス\nよいかジェラール`になります。

![fig3-2-3.jpg](https://qiita-image-store.s3.amazonaws.com/0/102349/526fa0c0-697b-7dc0-c07a-08384d55a329.jpeg)

そして、3番目の`h`コマンドを実行し、現在のパターンスペースの内容`われわれはインペリアルクロス\nよいかジェラール`を、ホールドスペースへとコピーします。

![fig3-2-4.jpg](https://qiita-image-store.s3.amazonaws.com/0/102349/76e80818-f260-589b-9bc6-072c95cb2736.jpeg)

また、4番目の`d`コマンドを実行し、パターンスペースの内容を削除します。

![fig3-2-5.jpg](https://qiita-image-store.s3.amazonaws.com/0/102349/9d5b9c2a-dab5-7ea0-33a3-ef2a16f92da4.jpeg)

最後に、全コマンドを実行した状態のパターンスペースが、`sed`の自動出力機能によって出力されます。
ただし、1行目と同様に、直前の`d`コマンドによってパターンスペースの内容は削除されているため、ここでは何も出力されません。

![fig3-2-6.jpg](https://qiita-image-store.s3.amazonaws.com/0/102349/fba32112-35d6-b9f3-3bd2-1d4f18c28176.jpeg)

----

最後に、末尾行の入力レコード`という陣形で戦う`を処理します。
まず、これまでと同じく、入力レコードをパターンスペースへと取り込みます。

![fig3-3-1.jpg](https://qiita-image-store.s3.amazonaws.com/0/102349/8d98499a-08e8-7f63-d038-26cfccc09d12.jpeg)

次に、1番目の`p`コマンドを適用します。
ただし、今回は末尾行であるため、アドレス`$!`にマッチせず、`p`コマンドは実行されません。

![fig3-3-2.jpg](https://qiita-image-store.s3.amazonaws.com/0/102349/5e71f25c-3977-da4b-2dd7-18079a917a31.jpeg)

その後、2番目の`G`コマンドを実行します。
現在のホールドスペースの内容`われわれはインペリアルクロス\nよいかジェラール`を、パターンスペース`という陣形で戦う`に追記します。
その結果、パターンスペースの内容は、`という陣形で戦う\nわれわれはインペリアルクロス\nよいかジェラール`になります。

![fig3-3-3.jpg](https://qiita-image-store.s3.amazonaws.com/0/102349/9c313d84-a38e-9bd8-c78f-0ffd92880b8a.jpeg)

そして、3・4番目の`h`と`d`コマンドを適用します。
しかし、1番目`p`コマンドと同様に、アドレス`$!`にマッチしないため、コマンドはどちらも実行されません。

![fig3-3-4.jpg](https://qiita-image-store.s3.amazonaws.com/0/102349/4a9d46d5-12df-dada-b3b3-34ad1be5de6a.jpeg)

最後に、全コマンドを実行した状態のパターンスペースが、`sed`の自動出力機能によって出力されます。
今回は、直前の`d`コマンドが実行されなかったため、パターンスペースの内容は空ではありません。
その為、現在のパターンスペースの内容、`という陣形で戦う\nわれわれはインペリアルクロス\nよいかジェラール`が、出力されます。

![fig3-3-5.jpg](https://qiita-image-store.s3.amazonaws.com/0/102349/75495a7d-8f13-7da4-41a4-15661fc60e1b.jpeg)


以上が、入力レコードを縦方向に対称に出力する動作になります。
1文で簡単に書き表すと、「入力`n`レコードに対し、`n-1`レコード目までを`p`コマンドで出力しつつ、入力を行単位で反転しながらホールドスペースにて保持、`n`行目でホールドスペースを出力する」という処理になります。



# まとめ

以下、例示で強調したポイントをまとめます。

* `sed`の各コマンドは、先頭から順次実行される。
* `sed`の各コマンドは、前に実行したコマンドの処理結果の影響を受ける。
    - 正確には、前コマンドの処理が適用されたパターン・ホールドスペースを用いて、処理をおこなう。
    - `sed`のデフォルトの動作であるパターンスペースの自動出力も、同様に影響を受ける。

これらの点に留意すれば、パターン・ホールドスペースを用いた複雑な`sed`スクリプトでも、理解しやすくなると思います。


# 補足事項

(2017-02-13追記)

`sed` は、入力をレコード単位で処理しますが、パターン・ホールドスペース内では、レコードの概念はありません。
言い換えると、改行文字は、出力するまで文字 `\n` として扱われます。
つまり、パターンスペース内に含まれる改行文字を、 `s` コマンドで置換する事が可能です。
以下に例を示します。

```sh
$ seq 1 4
1
2
3
4
$ seq 1 4 | sed '1!G; $!h; s/\n/ /g; $!d' # 入力を逆順にしつつ、各行をスペース区切りの1行として出力する
4 3 2 1
```


(図解部分では、可読性を優先したため、改行した状態で記載しました。)

----

# 参考にしたもの

- `$ man sed`
- `$ info sed`
- 『sed & awkプログラミング 改訂版』、Dale Dougherty, Arnold Robbins 著、福崎 俊博 訳、オライリー・ジャパン

# 雑記

* `sed`のパターンスペース・ホールドスペースの概念は、動作を把握しづらくて、なかなか難しい。
    - とはいえ、本記事のように、1レコード毎、1コマンド毎に動作を書いてみると、理解しやすいと思う。
    - **紙やホワイトボードに書いてみて、実際に手を動かしてみる事が大切**。
* ホールドスペースは、Windowsのクリップボードの仕組みに似ているかも？
    - Windows環境にてメモ帳を起動して、メモ帳をパターンスペース、クリップボードをホールドスペースに見立てて、動作を確認してみるのも、良い勉強法かもしれない。
    - `H`コマンドのような、ホールドスペースに追記する処理は、残念ながら再現できないけれど...
* 実は、例1と例2のスクリプトは、コード自体は殆ど同じだったりする。
    - 少しコマンドを弄っただけで、動作が大きく変化する所が、`sed`の面白い部分であり、難しい所でもあると思う。

<br>

* 今回、`sed`の動作を、表形式にして書き表してみたけれど...
    - ホールドスペースの初期値は何か、パターンスペースの内容はどの段階で上書きされるのかといった詳細な動作は、実はきちんと理解していなかったり。
    - パターンスペースが自動出力される処理に関しては、今回記事を書くにあたり必要になったので、`info sed`やGNU `sed`のソースを読んで何とか把握した。
    - `sed`の内部動作に詳しい方がいらっしゃいましたら、本記事の些細な間違い等を指摘していただけますと、幸いです`m(_ _)m`

----

* 例題2の`sed`スクリプトを使えば、シェル上で回文を作れます。

```sh
01 #!/bin/sh
02 
03 echo たけやぶ                | # 原文の出力
04 grep -o .                    | # 縦にする
05 sed '$!p; 1!G; $!h; $!d'     | # 入力レコードを鏡合わせで出力
06 xargs                        | # 横にする
07 tr -d ' '                      # 余分なスペースの除去
```

以下、コピペ用のワンライナー版。

```sh
$ echo たけやぶ | grep -o . | sed '$!p; 1!G; $!h; $!d' | xargs | tr -d ' '
```

* 漢字が含まれていても、いい感じに出来ます♥

```sh
01 #!/bin/sh
02 
03 echo 酢で漬けた                | # 原文の出力
04 mecab                          | # 入力を単語単位に分解
05 awk -F, '!/EOS/ && $0=$NF'     | # 余分なレコード・フィールドの除去
06 grep -o .                      | # 1文字1レコードに変換
07 sed '$!p; 1!G; $!h; $!d'       | # 入力レコードを鏡合わせで出力
08 xargs                          | # 1レコードn文字に変換
09 tr -d ' '                      | # 余分なスペースの除去
10 nkf --hiragana                   # カタカナをひらがなに変換
```

以下、コピペ用のワンライナー版と、その出力結果。

```sh
$ echo 酢で漬けた | mecab | awk -F, '!/EOS/ && $0=$NF' | grep -o . | sed '$!p; 1!G; $!h; $!d' | xargs | tr -d ' ' | nkf --hiragana
すでつけたけつです
$ !! | mecab
echo 酢で漬けた | mecab | awk -F, '!/EOS/ && $0=$NF' | grep -o . | sed '$!p; 1!G; $!h; $!d' | xargs | tr -d ' ' | nkf --hiragana | mecab
す	名詞,一般,*,*,*,*,す,ス,ス
で	助詞,格助詞,一般,*,*,*,で,デ,デ
つけ	動詞,自立,*,*,一段,連用形,つける,ツケ,ツケ
た	助動詞,*,*,*,特殊・タ,基本形,た,タ,タ
けつ	名詞,一般,*,*,*,*,けつ,ケツ,ケツ
です	助動詞,*,*,*,特殊・デス,基本形,です,デス,デス
```

* (CLI(パイプライン)上でかな漢字変換をする方法は、さすがに分からなかった...)
    - `uim-fep`のあたりを使って、上手いこと出来ないのかな？
    - ご存知の方がいらっしゃいましたら、ご教授くださいますとありがたいです。

<br>

* スッゲーどうでもいい話。
    - 尻だのケツだの書いていたら、半ケツ状態になりました。

<blockquote class="twitter-tweet" data-lang="ja"><p lang="ja" dir="ltr">うっ... 電源ケーブルをコンセントに挿そうとしゃがんだら、スーツの股間のあたりから、ブチッっていう音がした...... もしかしたら、また半ケツ状態かも(｀；ω；´)</p>&mdash; ginjiro (@gin_135) <a href="https://twitter.com/gin_135/status/803039002236305408">2016年11月28日</a></blockquote>
<script async src="//platform.twitter.com/widgets.js" charset="utf-8"></script>
<blockquote class="twitter-tweet" data-lang="ja"><p lang="ja" dir="ltr">駅のホームでやたらと尻がスースーすると思ったら、案の定半ケツになってた(T_T) やっぱり、朝のあれが原因だよなぁ... てか、客先にいる間はずっと、パンツ見えている状態だったのかorz このスーツもうダメだ...</p>&mdash; ginjiro (@gin_135) <a href="https://twitter.com/gin_135/status/803158784197541888">2016年11月28日</a></blockquote>
<script async src="//platform.twitter.com/widgets.js" charset="utf-8"></script>