くんすとの備忘録

IT系技術メモ

移転しました。

15秒後に自動的にリダイレクトします。

BSD環境での制御コードの置換について

昨日のシェル芸ヴェンキョウカイ(問2)で話題になった、BSD系環境で制御コードを置換するはなしです。
sedではやれないけどtrなら……という話です。

内容

概要

問2の模範解答は

comm <(sort a) <(sort b) | sed 's/^/\t/' |
sed 's/\t\t\t/c /' | sed 's/\t\t/b /' | sed 's/\t/a /' | sort

となっています。
これは「先頭にtabを突っ込んで、タブの連続を置換していく」という解き方で、GNU sedの利用を前提としています。

今回は解説のため、まずはBSDsedとtrを使った別解を書いてみます。
tabの代わりにカンマ(,)を使用するという発想です。

% comm <(sort a) <(sort b) | tr '\011' ',' |  sed 's/^/,/' | sed 's/,,,/c /' | sed 's/,,/b /' | sed 's/,/a /' | sort
a 川崎
a 鹿島田
b 南多摩
b 登戸
c 分倍河原
c 谷保

trの部分の解説

trの前で止めるとこうなっていて

% comm <(sort a) <(sort b)
                分倍河原
        南多摩
川崎
        登戸
                谷保
鹿島田

※commコマンドの話は後でしますが、データがタブ区切りになっています

trの後で止めるとこうなっています。

% comm <(sort a) <(sort b) | tr '\011' ','
,,分倍河原
,南多摩
川崎
,登戸
,,谷保
鹿島田


さて、manによると

\octal
バックスラッシュに続き、1〜3 桁の 8 進数が続いたものは、その値 を符号化した文字を表現します。この 8 進数の並びに続いて数字を 文字として指定したい場合には、8 進数の並びが 3 桁となるよう に、8 進数の上位桁 (左) に 0 を埋めてください

とのことです。

つまり

tr '\011' ','

は、ASCIIコードでtab(16進数で09、8進数で11)をカンマ(,)に置換する、ということになります。




どんでん返しその1

さっきの、sedのmanの続きです……

\character
バックスラッシュに続く、特定の特殊な文字は、特殊な値に対応しています。

\a <ベル文字>
\b <バックスペース>
\f <フォームフィード>
\n <改行>
\r <復帰>
\t <水平タブ>
\v <垂直タブ>

trは普通にバックスラッシュ文字が使えました……そういえばそうだった……
つまり

% comm <(sort a) <(sort b) | tr '\t' ',' | sed 's/^/,/' | sed 's/,,,/c /' | sed 's/,,/b /' | sed 's/,/a /' | sort

でいいってことですよ奥さん!!

 

どんでん返しその2

……ここまで書いといて何ですが、printf使えばsedでもやれますqiita.com

comm <(sort a) <(sort b) | sed "s/^/`printf '\t'`/" | sed "s/`printf '\t\t\t'`/c /" | sed "s/`printf '\t\t'`/b /" | sed "s/`printf '\t'`/a /" | sort

 


以上!