カテゴリー
【Sed活用講座】パターンスペースとホールドスペースの使い方を理解する
※ 当ページには【広告/PR】を含む場合があります。
2021/12/11
2022/09/30

皆さんは「Sedコマンド」を普段どのくらい使われていますでしょうか。
通常だと
sed -e 's/hoge/piyo/'
しかし、Sedコマンドの真髄は、
今回はこのパターンスペースとホールドスペースの概念と基礎的な使い道を解説していきます。
なお、Sedで
前回の記事の中で、Sedで「改行」をどうするかを考察した記事もポストしましたので、興味があればご覧ください。
ウェブサイト型のBashエミュレータを利用する
シェルコマンドは何かOSのターミナルソフトで動かす、というスタイルでも良いのですが、最近ではとても簡単に基礎的なシェルコマンドをオンラインかつ無償で試せるようになっています。
いくつかシェルコマンドを試せるサイトが存在しますが、例えば以下のBashオンラインエディタを利用させてもらいましょう。
このサイトではもちろんSedコマンドもオンラインで試すことが可能です。
とりあえずどのバージョンのsedが動いているかも確認しておくと、

で、
以前の
このようなウェブサイト形のプレイグラウンドはブラウザさえ有れば何処でも誰でも扱うことができるので、sedの違いを考慮せずとも、コードが同一で有れば誰がやっても同じ結果が返ってきます。
同じ開発チームで、他のエンジニアと技術的な情報共有のツールとしても便利に使えますので積極的に使ってみてください。
Sedのパターンスペースとは何かを理解しよう
では本題に移りましょう。
まずは
最初に以下のスクリプトを試してみます。
$ sed -r '' <<EOF
1行目
2行目
3行目
4行目
5行目
6行目
7行目
8行目
9行目
10行目
EOF
#👇実行結果
1行目
2行目
3行目
4行目
5行目
6行目
7行目
8行目
9行目
10行目
このsedには処理は
''
「何もしない」
ですが何もしないと言っておきながら、実際には入力したドキュメントが素通りで全て標準出力されてしまっています。
Sedの動作の大前提として、読み込んだ行ストリームごとに

ですので、先程の
何もしない
p
なので、本来の意味で
「何もしない」
それを行うのが、sedの
-n
$ sed -n -r '' <<EOF
1行目
2行目
3行目
4行目
5行目
6行目
7行目
8行目
9行目
10行目
EOF
#👇結果は何も出力されない
これで暗黙的に付けられていた
p
ここで改めて、明示にパターンスペースの内容を表示させると以下のスクリプトを使います。
$ sed -n -r 'p' <<EOF
1行目
2行目
3行目
4行目
5行目
6行目
7行目
8行目
9行目
10行目
EOF
#👇実行結果
1行目
2行目
3行目
4行目
5行目
6行目
7行目
8行目
9行目
10行目
と、なんだか同じことを回りくどく説明しましたが、パターンスペースを駆使したsedスクリプトのテクニックにはこの
-n (--quiet, --silent)
この
-n
まさに例えるならAT車にクラッチペダルが追加されて、MT車のように多彩なギアチェンジが可能になる...ような(?)ものです。
どう柔軟かというと、先程のスクリプトで、3、4、7、10行目の内容だけを表示させたい場合、
$ sed -n -r '
3p
4p
7p
10p
' <<EOF
1行目
2行目
3行目
4行目
5行目
6行目
7行目
8行目
9行目
10行目
EOF
#👇実行結果
3行目
4行目
7行目
10行目
と行数を指定してあげると良いだけになります。
裏でパターンスペースの存在を意識しながらでなければ、sedがなぜ出力できるか、という基礎的なところが理解できないことになりますので、sedを深く使いこなしたい場合にはこの
-n
sed初心者あるある〜二重に出力されてしまう
パターンスペースを理解しないまま勢いだけでsedを使ってしまうと、必ず躓いてしまうのが、
$ sed -r '
3p
4p
7p
10p
' <<EOF
1行目
2行目
3行目
4行目
5行目
6行目
7行目
8行目
9行目
10行目
EOF
#👇実行結果
1行目
2行目
3行目
3行目
4行目
4行目
5行目
6行目
7行目
7行目
8行目
9行目
10行目
10行目
と、こんな感じにちゃんと指定した行だけ
p
既に上記でその理由を示した通り、
-n
つまり「パターンスペース」とは
ということで上記の話をまとめると、パターンスペースには、
+ パターンスペースとは、入力された行の一時保存場所である
+ Sedのスクリプトが適用されるのは、
パターンスペースに置かれた行に対してである
+ パターンスペースに置かれた一行分がスクリプトに処理され、
順次各行ごとに処理が実行される、というサイクルを繰り返す
+ パターンスペースは原則一行づつ読み込まれ、
パターンスペースに置かれた古い行は上書きされる
+ 複数のSedスクリプトが指定されている場合、パターンスペースに置かれた
行でスクリプト順に逐次適用される
+ Sedの処理は、デフォルトでパターンスペースが順次標準出力される
という特徴があることが分かります。
Sedのホールドスペースとは何かを理解しよう
簡単なsedコマンドの利用程度では、ほぼ活躍する場面はないのですが、sedの隠されたもう一つのデータ保管領域である
先ほど説明していたパターンスペースは、新しい行が読み込まれるとその前に読み込まれていた行のデータは上書きされて消えてしまいます。
でも場合によっては複雑なテキスト操作をしたい場合、現在読み込んでいる行より前のデータを何処かに保管しておいて、後で上手い具合に使いたい、ということも考えなければなりません。
そんな時に使うのが、
ホールドスペースは利用者が使わないと普段は空のままで、特に何もせずにじっとしていますが、常にスタンバイ状態にあり、使おうと思うといつでも呼び出すことができます。
またホールドスペースにあるテキストは直接操作はできませんが、好きなタイミングでパターンスペースからテキストデータを盗んだり、逆に保持している内容を押し付けたりと、多彩な操作を行うことができます。

この操作はあくまでもパターンスペースとホールドスペースの間のデータのやり取りを制御に限られますが、以下のSedスクリプトコマンドが使えます。
この5つの操作が基本となりホールドスペースを一時的なテキストの避難場所として、複雑なテキスト操作が行えるようになります。
ホールドスペースを使った事例
ホールドスペースを利用した例を挙げると、ベタなところでテキストの行を逆順にすることが簡単にできます。
$ sed -n -r '
1!G # 1行目以外ならホールドスペース > パターンスペースへ末尾追加
h # 全ての行でパターンスペース > ホールドスペースで置換
$p # 最後の行ならパターンスペースを標準出力
' <<EOF
1行目
2行目
3行目
4行目
5行目
6行目
7行目
8行目
9行目
10行目
EOF
#👇実行結果
10行目
9行目
8行目
7行目
6行目
5行目
4行目
3行目
2行目
1行目
もう少し実用的な例として、最近著者がホールドスペースを使った手頃な例で、jsコードの関数の中身の書き換えもsedスクリプトで行うといざという時、処理を自動化できるようにできます。
$ func_name='getAssetGetConfig \(asset\)'
$ sed -n -r '
#👇書き換える関数をループ処理で修正
/'"$func_name"'/ {
:loop
/\}$/! {
N
#👇出力される文字列で要らない部分を削除
s-internalapi/asset/--
s-/get/--
b loop
}
p
}
#👇書き換える関数以外は通常の標準出力
/'"$func_name"'/!p
' <<EOF
setAssetHost (assetHost) {
this.assetHost = assetHost;
}
getAssetGetConfig (asset) {
return \`\${this.assetHost}/internalapi/asset/\${asset.assetId}.\${asset.dataFormat}/get/\`;
}
EOF
#👇出力結果
#👇関数の中身を期待通りに書き換えることが出来る
setAssetHost (assetHost) {
this.assetHost = assetHost;
}
getAssetGetConfig (asset) {
return `${this.assetHost}/${asset.assetId}.${asset.dataFormat}`;
}
ここではもっと高度なテクニックの
つまり「ホールドスペース」とは
では最後にホールドスペースの要点だけをまとめてみます。
+ パターンスペースに対して独立した保存領域を持っている
+ 反復処理を伴うような複雑な処理に利用できる
+ パターンスペースの行の読込みサイクルにも関係なく、
Sed処理中はずっとテキストの内容を保持できる
+ パターンスペースとの間でデータを柔軟にやり取りできる
+ 巨大なテキストも丸ごと保持はできるが、
すべての入力してしまうとメモリを圧迫し、
処理パフォーマンスが低下する恐れがあることに注意
実際にはもっと細かいルールもありますが、全部挙げると切がないですので、後はご自分でスクリプトを打ち込みながら慣れていってください。
まとめ
今回は、Sedをよりデープに使いこなすための
この2つをしっかり理解していることで、Sedの応用は無限大に広がります。
是非とも自分の手でカタカタとスクリプトを書いて実行してみながら、Sedがどうテキストを処理しているのか確認してみてください。
参考サイト
記事を書いた人
ナンデモ系エンジニア
主にAngularでフロントエンド開発することが多いです。 開発環境はLinuxメインで進めているので、シェルコマンドも多用しております。 コツコツとプログラミングするのが好きな人間です。
カテゴリー