sed (gsed)

linux 正規表現

sed の例文を集める. ほとんどは自分で思いついたものではないので, 他人が書いたコードを勝手に解説してることになる.

リンク

  1. sed1line.txt

tac (逆順出力)

tac コマンドは行単位で逆順に出力する

   seq 5
1
2
3
4
5

   seq 5 | tac
5
4
3
2
1

これを行う sed スクリプトは [sed1line.txt] で紹介されている. このスクリプトの理解はパターンスペースとホールドスペースを理解するのに役立ちそう.

簡略化すると次のようなスクリプトで tac は再現できる.

G
h

sed は実行の際に内部にパターンスペースとホールドスペースというそれぞれ文字列型のレジスタを持つ. 入力から読まれた一行はパターンスペースに保存されてスクリプトを実行する. ホールドスペースは初めはただ空文字列が入っている. G は ホールドスペースの文字列をパターンスペースの末尾に改行を入れてから追加する. (g なら追加ではなく上書きになる.) 逆に h はパターンスペースの文字列でホールドスペースを上書きする. (H なら上書きじゃなくて改行を入れてから追加をする.) これを繰り返すと,

Command           Pattern      Hold
---------------   ---------    -------
(next cycle)      1            ""
G                 1\n          ""
h                 1\n          1\n
(next cycle)      2            1\n
G                 2\n1\n       1\n
h                 2\n1\n       2\n1\n

となってホールドスペースに tac の結果が保存されていることが分かる.

結果をきれいに出力するための処理として, 一番最初のホールドスペースは G してもしょうがないのでさせないのと, 出力は一番最後だけすればいい (デフォルトではサイクルの最後にパターンスペースにあるものを出力する) ので d で出力せずに次のサイクルに移すような処理を付け足す.

1!G
h
$!d

長さを保つ文字置換

A - WAsedAC

入力が英大文字のときに含まれる W*AAC* に置換したい. ただしここでパターンで W\(n\) 個続いたとき, これを A のあとに C\(n\) 個続いたような文字列にしたい. 例えば WWAACC にしたい.

一手ずつ変換する場合

地道に s/WA/AC/g を何度も繰り返せば良い. これは

:a
s/WA/AC/g
ta

と出来る.

一度に変換する

上のようにループを使って一手ずつやると大変遅い. 一度に変換できるならしたほうが良い.

x20 さんの方法 wupc2019/submissions/4545993 を真似る.

s/\(W*\)A/A\L\1/g

とすると, \L はそれより後ろを lowercase で出力してくれる (manual) ので, WWWAAwww になってくれる. 入力に他に w という文字がないことを仮定すれば (この問題ではそうなっている), 最後に

y/w/C

とすれば ACCC を得る.

シェル実行

gsed (GNU sed) の拡張を用いるとシェルスクリプトが実行できる. これは s コマンドの e フラグとして実装されている.

すなわち, シェルスクリプトを出力させるような s コマンドを書いて,

   echo 2 3 | sed 's/\(.*\) \(.*\)/echo $(( \1 + \2 ))/'
echo $(( 2 + 3 ))

これに e フラグを付けると実行する.

   echo 2 3 | sed 's/\(.*\) \(.*\)/echo $(( \1 + \2 ))/e'
5

中身は bash なので(?), for 文でもなんでも書ける.