2025年4月入社予定の竹田有真です!今は毎週30分入社前の研修*1を受けています。red-data-tools/red-datastockを題材にRubyGemsの仕組みを学ぶという研修です。クリアコードの須藤さんに説明をしてもらいながら実際に手を動かして学んでいます!
はじめに
今回は研修の中で学んだsedコマンドについて説明します。UNIXの時代から、テキスト処理のための強力なツールとして sed(stream editor)は広く使われています。何十年も前に作られたコマンドですが、今でも役に立つケースがあるので学びました。例えば、CIでテキスト変更処理を自動化するときなどに使えます。自動化は開発効率向上につながります!(使用頻度が少ない、使用期間が短いものの自動化に開発時間をかけすぎるのは本末転倒。)
本記事では、sed 誕生の歴史や sed の置換機能、ファイルのバックアップ作成時のBSD版とGNU版の違いなど、研修で学んだことを中心にまとめます!
もくじ
- はじめに
- sed とは
- sed の誕生
- 変更内容をファイルに保存する際の注意点
- -i オプションでファイルを直接編集する
- -i オプションではバックアップを取るべき
- 可読性と拡張性のために -e オプションを使う
- まとめと感想
- 参考文献
sed とは
sedは "stream editor" の略で、コマンドライン上でテキストデータを自動かつ非対話的に編集するツールです。 sedはファイル全体を一度に読み込むのではなく、入力されたテキストを1行またはブロック単位で逐次処理するため、メモリ効率がよく、大規模なファイルの編集にも適しています。 この特性を活かして、sedは以下のような用途に広く使われています。
大量のテキストファイルの一括編集:ルールに従って文字列の置換、削除、挿入を自動で行う。
シェルスクリプトとの連携:パイプライン処理の一部として、他のコマンドと組み合わせてデータを柔軟に加工する。
例えば、以下のコマンドは file.txt
内のすべての「old」という文字列を「new」に置換します。
$ sed 's/old/new/g' file.txt
s は substitute(置換)の略であり、g は global の略です。各行において、該当するすべての文字列に対して置換を適用することを意味します。g を省略すると、各行で最初にマッチした部分だけが置換されます。
sed の誕生
sed was based on the scripting features of the interactive editor ed ("editor", 1971) and the earlier qed ("quick editor", 1965–66). - Wikipedia
sedの設計は、1960年後半のQEDや1970年代初頭の対話型エディタであるed(editor)を基盤としています。当時のコンピュータはメモリやディスプレイの制約が厳しかったため、ユーザーが直接画面上で編集するのではなく、ストリームとして流れるテキストをルールに従って効率的に処理する方法が求められていました。
そのため、ユーザーはコマンドを入力しながらテキストを編集する「ラインエディタ」である ed を使っていました。ed では、対話的にテキストを編集するために s/old/new/g
のようなコマンドが使われていました。sed はこの ed のコマンドをもとに、「非対話的に編集を行うストリームエディタ」として進化しました。開発したのはベル研究所の Lee E. McMahon らでした。
(メモリもディスプレイも十分に使える時代しか知らない私にとっては、一行ずつ読み込んで編集するという考えが逆に新鮮です!)
また、grep も ed のコマンドに由来しています。grep という名前は、ed のコマンド g/re/p
(global/regular expression/print)から来ています。これはファイル全体に対して、正規表現で検索し、マッチした行を出力するというコマンドです。
UNIX の開発者のひとりである Douglas McIlroy は、grep の発展について以下のように説明しています。
A while later a demand arose for another special-purpose program, gres, for substitution: g/re/s. Lee McMahon undertook to write it, and soon foresaw that there would be no end to the family: g/re/d, g/re/a, etc. As his concept developed it became sed,... - On the Early History and Impact of Unix Tools to Build the Tools for a New Millenium
grep の登場後、テキスト検索だけでなく、置換を行う gres(g/re/s
)という特別なプログラムが求められるようになりました。Lee McMahon はこの開発に着手しましたが、やがて g/re/d
(削除)や g/re/a
(追加)など、より多機能なツールが必要であると考え、最終的に sed を開発しました。
変更内容をファイルに保存する際の注意点
sedの代表的な機能は、正規表現を用いたパターンマッチングと置換です。研修では red-datastock.gemspec というファイルに対して少し変更を加えました。
$ sed 's/development/runtime/g' red-datastock.gemspec
このコマンドは、red-datastock.gemspec
ファイル内のすべての「development」という文字列を「runtime」に置換します。しかし、sed はオプションなしでは結果を標準出力に出力するだけで、元のファイル自体は変更しません。これは sed がフィルタコマンドであるためです。標準入力を加工し、標準出力することが主な目的です。フィルタコマンドは他のコマンドと組み合わせて柔軟にデータ処理することを目的とします。sed はその基本機能に加え、ファイルを入力として与えること、出力をファイルに書き込むこともできます。
出力をファイルに保存する際の失敗例を示します。
$ sed 's/development/runtime/g' red-datastock.gemspec > red-datastock.gemspec
上のコマンドでは、変更内容を red-datastock.gemspec
に上書き保存しようとしていますが、実際にはファイルが空になってしまいます。これは、出力リダイレクト(>
)が先に実行されるため、red-datastock.gemspec
が最初に空になります。当然、空ファイルに文字列の置換を行っても出力は空です。このような失敗を避けるために、リダイレクトを使う際はファイル名を変更すると良いです。
$ sed 's/development/runtime/g' red-datastock.gemspec > red-datastock.gemspec.new
-i オプションでファイルを直接編集する
先に述べたように、sed はデフォルトではファイルを直接編集しません。しかし、-i
オプション(in-place オプション)をつけると、sed はファイルを直接編集し、変更内容を保存します。また、-i
オプションはバックアップの作成にも利用できます。次に、GNU版とBSD版での -i
オプションの使い方の違いについて説明します。
GNU sed の場合(Linuxなど)
例えば、-i.bak
と指定すると、元のファイルのバックアップを <filename>.bak
として作成し、編集結果を元のファイルに上書き保存します。バックアップを作成せずに直接編集したい場合は、単に -i とだけ記述すればよいです。
BSD sed の場合(macOSなど)
BSD sedでは、-i
オプションを使用する際、バックアップなしで直接編集する場合でも必ず空文字列を指定する必要があります。つまり、バックアップを取らずに直接編集するには、-i ''
と記述する必要があります。つまり、スクリプトを書く際、異なる環境で動作するようにするためには、GNU版とBSD版の両方に対応するように書く必要があり、このような細かい違いに気をつける必要があります。
# GNU sedの場合 $ sed -i 's/development/runtime/g' red-datastock.gemspec # BSD sedの場合(macOSなど) $ sed -i '' 's/development/runtime/g' red-datastock.gemspec
-i オプションではバックアップを取るべき
さらに、BSD sed のドキュメントの in-place オプションの説明を見てみると、
It is not recommended to give a zero-length extension when in-place editing files, as you risk corruption or partial content in situations where disk space is exhausted, etc.
とあり、バックアップを取らずに直接編集する場合、空文字列を指定することは推奨されていません。ディスク容量が不足するなどの状況で、ファイルの内容が壊れる可能性があるためです。
この点について、GNU sed のドキュメントでは、
This option specifies that files are to be edited in-place. GNU sed does this by creating a temporary file and sending output to this file rather than to the standard output. ... When the end of the file is reached, the temporary file is renamed to the output file's original name.
と説明されています。つまり、GNU sed は一時ファイルにバックアップを取り、編集が完了してから元のファイルにリネームするため、ファイルの内容が壊れるリスクは低いです。
どちらの環境でも問題なく動作するようにするためには、バックアップファイルを作成する方が良いです。また、変更が期待したものとなっていれば、バックアップファイルは削除しても問題ありません。
$ sed -i.bak 's/development/runtime/g' red-datastock.gemspec $ rm -f red-datastock.gemspec.bak
可読性と拡張性のために -e オプションを使う
sed は複数のコマンドを連続して実行することができます。例えば、以下のコマンドは、red-datastock.gemspec
ファイル内のすべての「development」という文字列を「runtime」に置換し、その後「test」を「production」に置換します。
$ sed -i.bak -e 's/development/runtime/g' -e 's/test/production/g' red-datastock.gemspec
コマンドが一つだけの場合は -e
オプションを省略できますが、-e
の後にコマンドを書くことで、コマンドの区切りを明示できます。また、コマンドの追加や削除が容易になり、可読性と拡張性が向上します。
まとめと感想
本記事では、sed 誕生の背景や置換機能、BSD版とGNU版の相違点について説明しました。誕生背景を知ることで、sed の設計思想や使い方がより理解できると思います。また、細かい相違点を知って初めて異なる環境に適した開発ができるのだと感じました。より良い開発ができるよう、少し深く調べる癖をつけようと思います!
最後に
Speeeでは一緒にサービス開発を推進してくれる仲間を大募集しています!
新卒の方はこちらより本選考に申し込みが可能です!
キャリア採用の方はこちらのFormよりカジュアル面談も気軽にお申し込みいただけます!
Speeeでは様々なポジションで募集中なので「どんなポジションがあるの?」と気になってくれてた方は、こちらをチェックしてみてください!もちろんオープンポジション的に上記に限らず積極採用中です!!!
参考文献
- sed - Wikipedia
- QED - Wikipedia
- ed - Wikipedia
- ベル研究所 - Wikipedia
- Lee E. McMahon - Wikipedia
- Douglas McIlroy - Wikipedia
- On the Early History and Impact of Unix Tools to Build the Tools for a New Millenium
- sed(1) - FreeBSD
- GNU sed Manual
*1:Speeeでは内定してから入社するまでの間に内定者研修を実施しています。内定者研修は入社後にスムーズに業務に取り組むための基礎を身につけるために実施しています。プログラミング・データベース・チームでの開発方法などを網羅的にカバーしています。内定者の本業である学業がおろそかにならないようにバランスをとりながら実施しています。この記事で紹介している研修はあまり時間がない内定者向けの内容で、週に30分程度、より実践的な内容を手を動かしながら身につける研修です。