sed
スクリプト
sed
の高度な話題: サイクルとバッファ
bash
の環境変数をプリントsed
の制限と、GNU sed
で撤廃された制限sed
を習得するためのこの文書以外の資料
sed
This file documents version 4.7 of
GNU sed
, a stream editor.
Copyright © 1998-2018 Free Software Foundation, Inc.
Permission is granted to copy, distribute and/or modify this document under the terms of the GNU Free Documentation License, Version 1.3 or any later version published by the Free Software Foundation; with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts. A copy of the license is included in the section entitled “GNU Free Documentation License”.
• はじめに: | はじめに | |
• sedの起動: | 起動 | |
• sedスクリプト: | sed スクリプト
| |
• sedアドレス: | アドレス:行を選択する | |
• sed正規表現: | 正規表現:テキストを選択する。 | |
• sedの高度な話題: | sed の高度な話題:サイクルとバッファ
| |
• 例: | サンプルスクリプト達 | |
• 制限: | GNU sed の制限と、GNU sed で撤廃された制限
| |
• この文書以外の資料: | sed を習得するためのこの文書以外の資料
| |
• 報告済のバグ: | 報告済のバグ | |
• GNU Free Documentation License: | このマニュアルのコピーと共有について | |
• 概念索引: | このマニュアルの全てのトピックを含むメニュー。 | |
• sedコマンドとコマンドラインオプションの索引: | 全てのsed コマンドとコマンドラインオプション。
|
sed
はストリームエディタです。ストリームエディタは入力ストリーム(ファイルやパイプラインからの入力)に対して基本的なテキスト変換を実行します。(ed
のような)スクリプトの編集を許可するエディタに似ていますが、sed
は入力を1passで処理するので、より効率的です。しかしsed
がパイプラインでテキストをフィルタ処理できる点は、他のタイプのエディタとの明確な違いです。
この章ではsed
の実行方法について説明します。sed
スクリプトの詳細や、独特なsed
コマンド達については次章で取り扱います。
• 概要: | ||
• コマンドラインオプション: | ||
• sed終了ステータス: |
通常sed
は次のように起動します。
sed SCRIPT INPUTFILE...
例えばinput.txtファイル内にある全ての‘hello’ を‘world’ に置き換えるには次のようにします。
sed 's/hello/world/' input.txt > output.txt
INPUTFILE(入力ファイル)が指定されないか、または, '-'と指定されたときはsed
は標準入力より入力します。次の3つは等価です。
sed 's/hello/world/' input.txt > output.txt sed 's/hello/world/' < input.txt > output.txt cat input.txt | sed 's/hello/world/' - > output.txt
通常sed
は標準出力に出力します。-iコマンドラインオプションを指定すると、標準出力の代わりに、コマンドラインで指定した入力ファイル自身を編集します。そして、'W
'コマンドや's///w
'コマンド(wフラグ付き)は指定の他のファイルに書き出します。次のコマンドはfile.txtを書き換え、そして一切(標準出力に)出力しません。
sed -i 's/hello/world/' file.txt
デフォルトではsed
は( ' d
'コマンド等によって変更・削除されない限り)、入力処理した全てをプリントします。-n コマンドラインオプションは出力を抑制し、'p
'コマンドは指定の行をプリントします。次のコマンドは入力の45行目だけをプリントします。
sed -n '45p' file.txt
sed
は複数の入力ファイルを1つの長いストリームとして扱います。次の例は最初のファイル(one.txt)の最初の行をプリントし、そして最後のファイル(three.txt)の最後の行をプリントします。-s、--separate コマンドラインオプションを使うと逆にファイル単位で扱います。
sed -n '1p ; $p' one.txt two.txt three.txt
'-e'や'-f'コマンドオプション無しだとsed
は最初のコマンドラインオプションでない('-','--'で始まっていない)コマンドラインパラメータをスクリプトとして使い、それ以降のコマンドラインオプションでないコマンドラインパラメーター達を入力ファイル達として使います。'-e'や'-f'コマンドラインオプションがスクリプト指定の為に使われると、全てのコマンドオプションでないコマンドラインパラメータが入力ファイル群として使われます。'-e'や'-f'コマンドラインオプションは混在かつ複数回記述することができ、実行されるスクリプトはそれぞれのスクリプトをそのコマンドラインオプションの順番どおりに連結したものになります。
以下の3つは等価です。
sed 's/hello/world/' input.txt > output.txt sed -e 's/hello/world/' input.txt > output.txt sed --expression='s/hello/world/' input.txt > output.txt echo 's/hello/world/' > myscript.sed sed -f myscript.sed input.txt > output.txt sed --file=myscript.sed input.txt > output.txt
sed
を起動する完全な書式は次の通りです。
sed OPTIONS... [SCRIPT] [INPUTFILE...]
sed
は以下のコマンドラインオプション達とともに起動することができます。
--version
起動したsed
自身のバージョンと著作権表示をプリント次第終了します。
--help
これらコマンドラインオプション達の短く要約した使い方とバグ報告先をプリント次第終了します。
-n
--quiet
--silent
デフォルトではsed
はスクリプトを実行し、各サイクルが終わるとパターンスペースの内容をプリントします(「sed
はどのように動くか 」参照)。これらのコマンドラインオプションは各サイクル終了時の自動プリントを無効にし、その際sed
は'p
'コマンドで明示的に指示された場合のみプリントします。
--debug
(v 4.6)入力されたプログラムを標準形式でプリントし、注釈付きで実行します。
$ echo 1 | sed '\%1%s21232' 3 $ echo 1 | sed --debug '\%1%s21232' SED PROGRAM: /1/ s/1/3/ INPUT: 'STDIN' line 1 PATTERN: 1 COMMAND: /1/ s/1/3/ PATTERN: 3 END-OF-CYCLE: 3
-e script
--expression=script
指定のスクリプトを実行(予定の)コマンドに追加します。
-f script-file
--file=script-file
スクリプトファイルで指定されるファイルの内容を実行(予定の)コマンドに追加します。
-i[SUFFIX]
--in-place[=SUFFIX],
このコマンドラインオプションはコマンドラインパラメータで指定した入力ファイルを直接書き換えます。そのために、GNU sed
はテンポラリファイルを作り、標準出力ではなくこのテンポラリファイルに出力します。1
このオプションは'-s'、--separate コマンドラインオプションの動作もします。
ファイルのEOFに到達すると、テンポラリファイルは入力ファイルに上書きされます。もしこのコマンドラインオプションのパラメータとして拡張子が与えられていれば、テンポラリファイルを入力ファイル名にリネームする前に、入力ファイル名を変更します。これによりバックアップコピー2)が作成されます。
拡張子が'*
'(アスタリスク)を含んでない場合は、拡張子を現在のファイル名の末尾に接尾辞(サフィックス)として追加します。拡張子が1つ以上の'*
'(アスタリスク)を含んでいる場合は、拡張子の中の各'*
'を現在のファイル名に置換したものをバックアップファイル名とします。これにより、接尾辞(サフィックス)の代わりに(またはそれに加えて)バックアップファイルに接頭辞(プレフィックス)を追加したり、元のファイルのバックアップコピーを別のディレクトリに配置することができます(ディレクトリが既に存在する場合)。
拡張子が与えられない時はバックアップを作ること無しに入力ファイルは上書きされます。
注意:短いオプションである'-i'コマンドラインオプションは引数を取るので、これに他の短いコマンドラインオプション文字を続けて書いてはいけません。
sed -Ei '...' FILE
これは -E -i と同じです。拡張子の指定が無いのでバックアップファイルは作成されず、FILEが直接書き換えられます。
sed -iE '...' FILE
これは --in-place=E と等価です。入力ファイル FILE のバックアップとして FILEE が作られます。
警告:-n と -i を一緒に使用すると、前者は行の自動プリントを無効にし、そして、後者はバックアップ無しにファイルの内容を変更します。よって不用意に(明示的な'p
’コマンドを無しで)使われると、ファイルの中身を空にしてしまいます。
# 間違った使用法: 'FILE'は切り捨てられます。 sed -ni 's/foo/bar/' FILE
-l N
--line-length=N
'l
' sedコマンドで行を折り返すデフォルトの長さを指定します。長さに 0 (ゼロ)を指定すると折り返ししなくなります。指定が無い場合は70です。
--posix
GNU sed
はPOSIX sedに数々の拡張を加えています。移植性のあるスクリプトの作成を簡単にする為に、このオプションはGNU sedで追加されたコマンド含めこの文書に述べられている全てのGNU sed拡張を無効にします。ほとんどの拡張機能はPOSIXで強制される文法外のsed
プログラムを受け付けますが、それらのいくつかは(バグレポートで説明している'N
'コマンドのような振る舞いは)実際には規格を破っています。GNU 拡張を無効にしたい場合は環境変数 POSIXLY_CORRECT
に空で無い値をセットして下さい。
-b
--binary
このコマンドラインオプションは全てのプラットフォームで有効ですが、効果があるのはテキストファイルとバイナリファイルを区別するオペレーティングシステムだけです。そのように区別される—MS-DOS、Windows、Cygwinのような—オペレーティングシステムではテキストファイルはキャリッジリターン(CR;\x0d)とラインフィード(LF;\x0a)で区切られた行で構成され、sed
は終わりのCRを通常の1文字扱いするのではなく無視するという特殊動作をします。このオプションが指定されるとsed
は入力ファイルをバイナリモードで開きます。 つまり、sedはこの特殊動作をせず、単純に行はラインフィード(LF;\x0a)で終了するとして動作します。
--follow-symlinks
このコマンドラインオプションが有効なのプラットフォームがシンボリックリンクをサポートしていて、かつ、'-i'コマンドラインオプションが指定された時だけです。この場合、コマンドラインで指定したファイルがシンボリックリンクだったら、sed
はリンクを辿り、リンク最終先(大元)のファイルを編集します。デフォルトの動作はシンボリックリンクを解除することで、リンク先は変更されません。
-E
-r
--regexp-extended
基本正規表現ではなく拡張正規表現を使います。拡張正規表現とはegrep
が受け付けるものです。バックスラッシュの嵐を減らせるので正規表現がより分かりやすくなります。これは歴史的にはGNU拡張でしたが、 '-E'拡張はPOSIX標準に取り込まれた(http://austingroupbugs.net/view.php?id=528)ので、移植性の為に'-E'を使います。GNU sedは何年も前から文書化されていないオプションとして -E を受け入れていますし、*BSD sedsは何年もの間' -E 'を受け入れていますが、' -E 'を使うスクリプトは他の古いシステムに移植できないかもしれません。「拡張正規表現」参照。
-s
--separate
デフォルトではsed
はコマンドラインで指定されたファイル群を1つの長いストリームとして扱います。 このGNU sed
拡張はファイルをそれぞれに分けて処理することを可能にします。(‘/abc/,/def/’のような)範囲アドレスが複数のファイルに渡らないようにしたり、行番号をファイルごとにリセットしたり、'$
'が各ファイルの最終行にマッチするようにしたり、'R
'コマンドで読み込むファイルからの読み込み位置をファイルごとに巻き戻したりします。
--sandbox
サンドボックスモードでは 'e
'、'w
'、'r
'コマンドは弾かれます。それらを含むプログラムは実行されずにアボートします。サンドボックスモードでは、 sed
はコマンドラインで指定された入力ファイルに対してのみ機能し、外部プログラムを実行することはできません。
-u
--unbuffered
入出力でのバッファリングをできるかぎり少なくします(これは入力が ' tail -f 'のようなものから来ていて、変換された出力をできるだけ早く見たい場合に特に便利です)。
-z
--null-data
--zero-terminated
入力されるデータの区切りが改行コードではなくASCIIの ‘NUL’ 文字(\x00)文字で終わっているものとして扱います。このオプションは ' sort -z 'や ' find -print0 'のようなコマンドと共に使用して任意のファイル名を処理することができます。
コマンドラインに -e や -f や --expression や --file オプションが指定されていない場合は、コマンドラインの最初のオプションではない引数が、実行されるスクリプトになります。
上記の処理後にコマンドラインパラメータが残っている場合、これらのパラメータは処理対象の入力ファイルの名前として解釈されます。 ファイル名に ‘-’ を指定した場合は標準入力からの入力となります。ファイル名が与えられなかった場合も標準入力として処理されます。
0の終了ステータスは成功を表し、0以外の値は失敗を表します。GNU sed
は以下の終了ステータス値を返します。
完璧に成功。
不正なコマンドまたは不正な文法または不正な正規表現または、--posixコマンドラインオプションが指定されているのにGNU sed
拡張が使われている。
コマンドラインで指定した1つまたはそれ以上ファイルがオープンできなかった(例えばファイルが存在しなかった、また読み取り許可権限が無かった)。但し、オープンできた他のファイルに付いては処理が続行されます。
I/Oエラーや実行中の深刻なエラー。GNU sed
は即座にアボートします。
加えてsedコマンド'q
'や'Q
'はsed
を指定の終了コード値で終了させることが出来ます(これはGNU sed
拡張です)。
$ echo | sed 'Q42' ; echo $? 42
sed
スクリプト• sedスクリプト概要: | sed スクリプト概要
| |
• sedコマンド一覧: | sed コマンド要約です。
| |
• "s"コマンド: | sed ’s Swiss Army Knife
| |
• 一般コマンド達: | よく使われるコマンド達 | |
• 他のコマンド達: | あんまり使われないコマンド達 | |
• プログラミングコマンド達: | sed 導師のためのコマンド群
| |
• 拡張コマンド: | GNU sed 固有のコマンド達
| |
• 複数コマンド文法: | スクリプトを書きやすくする拡張です。 |
sed
スクリプト概要sed
プログラムは1つ以上のsed
コマンドで構成され、1つまたはそれ以上(混在もOK)の'-e'、'-f'、'--expression'、'--file'コマンドラインオプションで渡されるか、あるいはこれらのコマンドラインオプションが全く無いときはコマンドラインオプションで無い最初の引数がsed
プログラムとして扱われます。この文書で言うsed
スクリプトとは通常、スクリプトまたはスクリプトファイルとして渡されたものを順に連結したものを意味しています。「概要」参照。
sed
コマンド文法は次の通り。
[addr]X[options]
Xは(英語)1文字のsed
コマンドです。[addr]
は省略可能な行アドレスです。[addr]
が指定されると、sedコマンド X はそのアドレスにマッチした行でのみ実行されます。[addr]
は行番号一つ、または正規表現、または行範囲を指定する事ができます(「sedアドレス」参照)。追加の[options]
はいくつかのsed
コマンドにあります。
次の例は入力の30行目から35行目を削除します。30,35
はアドレス範囲です。d
は削除コマンドです。
sed '30,35d' input.txt > output.txt
次の例は行頭に‘foo’がある行が見つかるまで全てプリントします。そして行頭に‘foo’がある行を見つかると、sed
自身を終了させ、終了ステータス 42を返します。行頭に‘foo’がある行が見つからなかった時(そして他のエラーが発生しなかった時)は、sed
終了時に終了ステータス 0 を返します。/^foo/
は正規表現アドレスです。q
はsed終了コマンドです。42
はこのsedコマンドのオプションです。
sed '/^foo/q42' input.txt > output.txt
スクリプト内やスクリプトファイル内のコマンド達はセミコロン(;
)や改行(ASCII \x0a)で区切る事ができます。'-e'や'-f'コマンドラインオプションで複数のスクリプトを指定することができます。
以下の例は全て等価です。以下の例はふたつのsed
操作を実行します。正規表現 /^foo/
にマッチする行を削除します。そして‘hello’が現れると全て‘world’に置換します。
sed '/^foo/d ; s/hello/world/' input.txt > output.txt sed -e '/^foo/d' -e 's/hello/world/' input.txt > output.txt echo '/^foo/d' > script.sed echo 's/hello/world/' >> script.sed sed -f script.sed input.txt > output.txt echo 's/hello/world/' > script2.sed sed -e '/^foo/d' -f script2.sed input.txt > output.txt
sedコマンド'a
'、'c
'、'i
'は文法上、続くコマンドとの区切り文字としてセミコロンを使うことはできません。よって改行で終了せるか、またはスクリプトやスクリプトファイルの最後に置く必要があります。コマンドの前には(何もしない)空白文字達を書く事もできます。「複数コマンド文法」参照。
sed
コマンド要約以下のコマンド群はGNU sed
でサポートされています。POSIX標準コマンドもあれば、GNU拡張もあります。各コマンドの詳細と例は次の節をご覧ください。括弧内はコマンドの覚え方(mnemonic)です。(訳注:説明の都合上、コマンドとオプションの間に空白が開いていますが、空白無しで続けても構いません)。
a\
text
(append)行のうしろに text を追加する。
a text
(append)行の後ろに text を追加する(代替文法)。
b label
(branch)指定の label へ無条件ジャンプ。ラベルを省略したときは次のサイクルを開始します。
c\
text
(change)行をtext で置き換える。
c text
(change)行を text で置き換える(代替文法)。
d
(delete)パターンスペースの内容を全削除し、以降のコマンドの実行をスキップして直ちに次のサイクルを開始する。
D
(delete)パターンスペースが改行を含んでいれば、パターンスペースの最初の改行までを削除し、次の入力行を読み込まずに、削除後のままのパターンスペースに対して次のサイクルを開始します。
パターンスペースが改行を含んでいない場合はdコマンドと同じ動作で、次の入力行を読み込み次のサイクルを開始します。
e
(execute)パターンスペース内に見つけたシェルコマンドを実行し、パターンスペースの内容をそのシェルコマンドの出力で置き換えます(末尾の改行は抑制されます)。
e command
(execute)シェルコマンドcommandを実行し、その出力を出力ストリームへ送ります。コマンドは複数行に渡って書くことができ、コマンドの最後以外の各行の末尾にはバックスラッシュ'\'を書きます。
F
(filename)現在の入力ファイル名を(末尾に改行を伴って)出力します(標準入力の場合は'-'を出力))。
g
パターンスペースの内容をホールドスペースの内容で置き換えます(cp hold-space pattern-space)。
G
パターンスペースの内容末尾に改行を追加し、更にホールドスペースの内容を追加します。
h
(hold)ホールドスペースの内容をパターンスペースの内容で置き換えます(cp pattern-space hold-space)。
H
(hold)ホールドスペースの内容末尾に改行を追加し、更にパターンスペースの内容を追加します。
i\
text
(insert)行の前に text を挿入する。
i text
(insert)行の前に text を挿入する(代替文法)。
l
パターンスペースの内容を非表示文字も目に見えるようにプリントする。
n
(next)自動プリントが無効で無い場合はパターンスペースの内容をプリントしてから、パターンスペースの内容を次の入力行で置き換えます。それ以上入力が無い時、sed
はそれ以上コマンドを処理することなく終了します。
N
(next)パターンスペースの内容の末尾に改行を追加し、更に次に読み込んだ一行を追加します。それ以上入力が無い時、sed
はそれ以上コマンドを処理することなく終了します。
p
(print)パターンスペースの内容をプリントする。
P
(print)パターンスペースの最初の改行(改行含む)までの1行をプリントする。
q[exit-code]
(quit)以降のコマンドや入力処理をせずにsed
を終了させる。
Q[exit-code]
(quit)このコマンドはq
コマンドと同じですが、パターンスペースの内容をプリントしません。q
コマンドと同様にsed呼び出し元へexit codeを返す事ができます。
r filename
(read)filenameというファイル名のファイルを読み込む。
R filename
(read)filenameで指定したファイルからたかだか1行読み込み現在のサイクルの最後または次の入力行が読まれる時に出力ストリームに挿入する。
s/regexp/replacement/[flags]
(substitute) パターンスペース内で正規表現にマッチさせます。マッチしたらマッチした文字列をreplacementで置き換えます。
t label
(test) s
コマンドによる置換が成功した後で、かつ最後の入力行が読み込まれてないか他の条件分岐が実行されてない場合、指定のラベルへジャンプします。ラベルを省略したときは次のサイクルを開始します。
T label
(test) s
コマンドによる置換が失敗した後で、かつ最後の入力行が読み込まれてないか他の条件分岐が実行されてない場合、指定のラベルへジャンプします。ラベルを省略したときは次のサイクルを開始します。
v [version]
(version)このコマンドはGNU sedでは何もしません(が、コマンドとして有効)。しかしGNU sed
拡張がサポートされていない時や、要求したしたversionが存在しない時は失敗します。
w filename
(write)パターンスペースの内容をfilenameで指定したファイルに書き込む。
W filename
(write)与えられたfilenameのファイル名のファイルに、パターンスペースの先頭から最初の改行まで部分を書き出す。
x
(exchange)パターンスペースの内容とホールドスペースの内容を交換する(swap pattern-space hold-space)。
y/src/dst/
パターンスペース内のsource-charsにある文字を対応するdest-charsの文字で置き換える。
z
(zap)パターンスペースの内容を全削除する。
#
次の改行までをコメントとする。
{ cmd ; cmd ... }
いくつかのコマンドをまとめて1つのグループにする。
=
現在の入力行番号を(末尾に改行付けて)プリントします。
: label
分岐コマンド達('b
'、't
'、'T
')の為の飛び先ラベルを配置します。
s
コマンドsed
でたぶん最も重要なコマンドが s
コマンドですが、様々なオプションを持っています。s
コマンドの文法は ‘s/regexp/replacement/flags’です。
基本的な概念はシンプルです。s
コマンドは与えられた正規表現 regexp でパターンスペースの中から一致する部分を探します。もし一致する部分があればそれを replacement で置き換えます。
正規表現文法について詳しくは「正規表現アドレス」参照。
replacement は \n
(n は1から9の数字)を含むことができ、それはマッチしたregexp 内の n番目の\(
と \)
に囲まれた部分で置き換えられます。また replacement はエスケープされていない &
を含む事ができ、これは正規表現regexp全体とマッチしたものと置き換えられます。
s
コマンドの区切りの'/'文字は任意の1文字に置き換える事ができます。(区切りの)'/
'文字(または別の文字を使ったのならその文字)がregexpやreplacementに現れるのなら、その前に1つの'\
'文字を置きます。
最後に、GNU sed
拡張として、'\L
'、'\l
'(訳注:小文字のエル)、'\U
'、'\u
'、'\E
な特殊なつづりを含む事ができます。その意味は以下のとおり。
\L
置換したテキストで、'\U
'または'\E
'が見つかるまで小文字にする。
\l
(小文字のエル)次の1文字を小文字にする。
\U
置換したテキストで、'\L
'または'\E
'が出現するまで大文字にする。
\u
次の1文字を大文字にする。
\E
'\L
'や'\U
'によって始まった文字変換を終了する。
g
フラグが指定されていた場合、大文字小文字変換は正規表現の各マッチの範囲内だけで行われ別のマッチまで伝播することはありません。例えば、パターンスペースの内容が‘a-b-’であるとき、次のコマンドを実行すると、
s/\(b\?\)-/x\u\1/g
その出力は‘axxB’となります。最初のマッチは2文字目‘-’で、このとき'\(b\?\)'の中身は空なので、‘\1’は空に置き換えられ、'\u'の次は空になるので何もしません。'b-
'を'xB
'に置き換える時は、パターンスペースで既に置き換えられた'x
'には影響を与えません。
一方、'\l
'や'\u
'はそれに続く置換が空の場合はその後に続く置換テキストに影響を与えます。パターンスペースに‘a-b-’があるとき、次のコマンド、
s/\(b\?\)-/\u\1x/g
これは‘-’を‘X’にし、‘b-’ を‘Bx’にします。。これが望みの動作で無い場合は、この場合、‘\1’の後ろに‘\E’を置く事で防ぐ事ができます。
'\
'文字や'&
'文字、改行を含めるには、replacement内においたそれぞれの前に'\
'を置いて下さい。
s
コマンドはフラグ無しか、1つ以上のフラグを後に続ける事ができます。
g
最初にマッチしたものだけでなくその後もにマッチしたの全てで置換を適用します。
number
number番目のマッチだけ置換します。
s
コマンドフラグの相互作用に注意: POSIX規格ではg
フラグとnumberフラグを混在させた時に何が起こるかは規定されていません。 sed
の各実装の間でわりと普通の動作などというようなものもありません。実装依存です。なおGNU sed
では、この相互作用を定義しています。指定のnumber以前のマッチを無視し、number番目とそれ以降全てのマッチに適用します。
p
置換した場合は、その結果を含むパターンスペースをプリントします。
注意:p
フラグとe
フラグの両方を使った時は、その指定の順番により全然違う結果をもたらします。 普通は'ep
'(evaluate してから print)が望みのものですが、逆順で動いてくれるとデバッグに便利です。このために、s
コマンドのフラグは一般には1度しか評価されませんが、デバッグに便利なようにGNU sed
の現在の版は'e
'の前後に’p
'を置くことができます。そうするとeval前のパターンスペースの内容とeval後のパターンスペースの内容をプリントします。この動作は公式文書に掲載されているけれども、将来のバージョンでは変更される可能性があります。(訳注:手元のGNU sed 4.7では動作確認できず)
w filename
置換できたら、指定のファイル名のファイルに結果を書き出します。GNU sed
拡張では、ファイル名として標準エラー出力の'/dev/stderr'と、標準出力の'/dev/stdout'をサポートしています。3
e
このフラグはシェルコマンドからの入力をパターンスペースにパイプラインできます。置換が成功すると、パターンスペースの内容をシェルコマンドとみなして実行し、そのパターンスペースの内容をその出力で置き換えます。末尾の改行は抑制されシェルコマンドには含まれません。また、実行されるコマンドにNUL文字(ASCII \x00)が含まれていた場合の動作は未定義です。これはGNU sed
拡張です。
I
i
GNU拡張の'I
'フラグはsed
にregexpの英大文字小文字を区別せずにマッチングするよう指示します。
M
m
GNU sed
拡張の'M
'フラグは正規表現が複数行マッチモードで動くように指示します。このフラグは'^
'と'$
'をそれぞれ(通常の振る舞いに加えて)改行の後の空の文字列と改行の前の空の文字列に一致させます。常にバッファの先頭または末尾に一致する特殊文字つづり('\`
'と'\'
')があります。さらに、複数行モードではピリオド('.')は改行文字とマッチしません。
sed
を使った事があれば、あなたはこれらのコマンド全部を知りたいはずです。
#
[アドレス指定不可]
'#
'はコメントのはじまりです。次の改行まで続きます。
移植性を気にする場合、(POSIXに準拠していない) sed
の実装によっては、スクリプト全体でたった1行のコメントしかサポートされないことがあります。 この場合、スクリプトの最初の文字は'#
'です。
警告:sed
スクリプトの最初が'#n
'のとき、'-n'(no-autoprint)オプションを指定したのと同じ効果があります(訳注: seq 3 | sed -e '#n' -e '2p' は、seq 3 | sed -n '2p' と等価です)。スクリプトの最初にコメント'#'を書き、それに通常のコメントとしての文字'n'を続ける時は必ず大文字'N'にしてください。または'n'の前に1つ以上の空白を入れて下さい。
q [exit-code]
以降のコマンドや入力を処理せずにsed
を終了させる。
例:2行目でプリントを停止する。
$ seq 3 | sed 2q 1 2
このコマンドは単一のアドレスのみ受け入れます(アドレス範囲不可)。注意:'-n'オプションによってサイクル間の自動プリントが抑止されていない場合はパターンスペースの内容をプリントします。sed
が返す終了コード値を指定できるのはGNU sed
拡張です。
GNU sed
拡張の'Q
'コマンドはパターンスペースの内容をプリントせずにsedを終了します。
d
(delete)パターンスペースの内容を全削除し、以降のコマンドの実行をスキップして直ちに次のサイクルを開始する。
例:入力行の2行目を削除。
$ seq 3 | sed 2d 1 3
p
パターンスペースの内容を(標準出力に)プリントする。このコマンドは通常'-n'コマンドラインオプションとの組み合わせでのみ使用されます。
例:入力行の2行目だけをプリントする。
$ seq 3 | sed -n 2p 2
n
自動プリントが無効になって無い時は、パターンスペースの内容をプリントし、プリントの有無にかかわらず入力から読み込んだ次の行でパターンスペースの内容を置き換えます。それ以上入力が無い時、sed
はそれ以上コマンドを処理することなく終了します。
このコマンドは行をスキップするのに便利です(例えばN行ごとに処理するなど)。
例:3行おきに置換します(すなわち、2つの'n
'コマンドが行を2つスキップする)。
$ seq 6 | sed 'n;n;s/./x/' 1 2 x 4 5 x
GNU sed
はこれと同様の結果を得る'first~step'というアドレス文法の拡張を提供しています。
$ seq 6 | sed '0~3s/./x/' 1 2 x 4 5 x
{ commands }
'{
'から'}
'の間のコマンド達をグループ化します。これは、単一アドレス(またはアドレス範囲)へのマッチによってコマンド群をトリガーしたいときに重宝します。
例:入力行の2行目を置換してプリントします。
$ seq 3 | sed -n '2{s/2/X/ ; p}' X
前の節で使用されているものよりも、おそらく使用頻度は低いですが、これらのコマンドを使えば非常に小さくて便利な sed
スクリプトを作成することができます。
y/source-chars/dest-chars/
パターンスペース内のsource-charsにある文字を対応するdest-charsの文字で置き換える。
例:a-jの文字をそれぞれ0-9の文字で置き換える。
$ echo hello world | sed 'y/abcdefghij/0123456789/' 74llo worl3
('/
'は、任意の y
コマンド内で、他の任意の1文字に一律に置き換えることができます)。
'/
'(またはその代わりに使用されるその他の文字)、'\
'、改行は、'\
'でエスケープすることで、source-charsリストやdest-charsリストに記入できます。source-charsとdest-charsは正確に同じ文字数でなければなりません。
同じ機能を持つ、GNU coreutils の tr
コマンド参照。
a text
行の後ろに text を追加する。これは標準の a
コマンドに対するGNU拡張です。詳細は以下を参照。
例:2行目の後ろに‘hello’を追加する。
$ seq 3 | sed '2a hello' 1 2 hello 3
a
コマンドは先行する空白('a'と'hello'の間にある空白)を無視します。'a'コマンドの、行末までのテキストを読み取り、行の後ろに追加します。
a\
text
行の後ろに text を追加する。
例:2行目の後ろに‘hello’を追加します(-| で始まる行はsedの出力です)。
$ seq 3 | sed '2a\ hello' -|1 -|2 -|hello -|3
a
コマンドは、このコマンドに続くテキスト(最後以外は'\
'で終わり、出力から削除されます)を現在のサイクルの終わりまたは次の入力行が読み込まれたときに出力されるようにキューに入れます。
GNU拡張では、このコマンドはアドレス範囲を受け付けます。
text のエスケープシーケンスは処理されるので、 text に'\'を文字として入れるには'\\
'と記述する必要があります。
最後の行(‘world’)の末尾に'\
‘が付いてないことで、そこで a コマンドの終了とみなされ、次の行は次のコマンドの処理を続行します。
$ seq 3 | sed '2a\ hello\ world 3s/./X/' -|1 -|2 -|hello -|world -|X
GNU拡張として、 a
コマンドと text を2つの -e
パラメータに分割して、スクリプトを簡単にすることができます。
$ seq 3 | sed -e '2a\' -e hello 1 2 hello 3 $ sed -e '2a\' -e "$VAR"
i text
(insert)行の前に text を挿入する。これは、標準の i
コマンドに対するGNU拡張です。詳細は以下を参照。
例:2行目の前に‘hello’を挿入する。
$ seq 3 | sed '2i hello' 1 hello 2 3
i
コマンドの後の先頭の空白は無視されます。'a'コマンドの、行末までのテキストを読み取り、行の後ろに追加します。
i\
text
このコマンドに続くテキスト行を直ちに出力します。
例: ‘hello’を2行目の前に挿入する(-| はsedの出力)。
$ seq 3 | sed '2i\ hello' -|1 -|hello -|2 -|3
GNU拡張では、このコマンドはアドレス範囲を受け付けます。
text のエスケープシーケンスは処理されるので、 text に'\'を文字として入れるには'\\
'と記述する必要があります。
最後の行(‘world’)の末尾に'\
‘が付いてないことで、そこで a コマンドの終了とみなされ、次の行は次のコマンドの処理を続行します。
$ seq 3 | sed '2i\ hello\ world s/./X/' -|X -|hello -|world -|X -|X
GNU拡張として、 a
コマンドと text を2つの -e
パラメータに分割して、スクリプトを簡単にすることができます。
$ seq 3 | sed -e '2i\' -e hello 1 hello 2 3 $ sed -e '2i\' -e "$VAR"
c text
対象行を text で置き換えるこれは、標準の c
コマンドに対するGNU拡張です。詳細は以下を参照。
例:2行目から9行目までの行の内容を‘hello’で置き換える。
$ seq 10 | sed '2,9c hello' 1 hello 10
c
コマンド直後の空白('c'と'hello'の間の空白)は無視されます。'a'コマンドの、行末までのテキストを読み取り、行の後ろに追加します。
c\
text
addressまたはaddress-rangeに一致する行を削除して、このコマンドに続くテキスト行を出力します。
例:2行目から4行目までを‘hello’と‘world’に置換します(-| はsedの出力)。
$ seq 5 | sed '2,4c\ hello\ world' -|1 -|hello -|world -|5
アドレスを指定しない場合、全ての行の内容を置換します。
パターンスペースは削除されているので、このコマンドの実行後に新しいサイクルが開始されます。次の例では、 c
は次のサイクルを開始してしまうので、cコマンドで置換されたテキストに対して's/./X/'置換コマンドは実行されません。
$ seq 3 | sed '2c\ hello s/./X/' -|X -|hello -|X
GNU拡張として、 c
コマンドと text を2つの -e
パラメータに分割して、スクリプトを簡単にすることができます。
$ seq 3 | sed -e '2c\' -e hello 1 hello 3 $ sed -e '2c\' -e "$VAR"
=
入力行の行番号を(末尾に改行を付けて)プリントします。
$ printf '%s\n' aaa bbb ccc | sed = 1 aaa 2 bbb 3 ccc
GNU拡張では、このコマンドはアドレス範囲を受け付けます。
l line-length
(小文字のエル)パターンスペースを明確な(unambiguous)形式でプリントします。表示不能文字(および'\
')はC言語スタイルのエスケープ形式でプリントします。。 長い行は分割され、分割を示す末尾の'\
'文字が付きます。 各行の終わりは’$
'でマークされています。
line-length は行折り返しの長さを指定します。0が指定された時は行の折り返しをしません。line-lengthを省略すると、コマンドラインで指定したデフォルト値が使われます。line-length パラメータはGNU sed
拡張です。
r filename
(read)filenameというファイル名のファイルを読み込む。例:
$ seq 3 | sed '2r/etc/hostname' 1 2 fencepost.gnu.org 3
filenameの内容をキューに入れ、現在のサイクルの最後または次の入力行が読まれる時に出力ストリームに挿入する。注意:filenameで指定したファイルから読み込みできなかったら、そのファイルは空のファイルであったかのように扱われます。その際何のエラーも出しません。
GNU sed
拡張として、 /dev/stdinをファイル名として与えた時は標準入力から読み込みます。
GNU拡張では、このコマンドはアドレス範囲を受け付けます。アドレス指定された各行で、ファイルは再度読み込まれ挿入されます。
w filename
(write)パターンスペースの内容をfilenameで指定したファイルに書き込む。GNU sed
拡張では、ファイル名として標準エラー出力の'/dev/stderr'と、標準出力の'/dev/stdout'をサポートしています。4
最初の入力行が読み取られる前に出力ファイルが作成(または既存ファイルの内容切り捨て(trancate))されます。 同じ filename を参照するすべての w
コマンド(成功した s
コマンドの w
フラグ指定分含む)のファイルへ、ファイルを閉じて再度開くことなく出力します。
D
パターンスペースが改行を含んでいない場合はdコマンドと同じ動作で、次の入力行を読み込み次のサイクルを開始します。逆にパターンスペースが改行を含んでいれば、パターンスペースの最初の改行までを削除し、次の入力行を読み込まずに、削除後のままのパターンスペースに対して次のサイクルを開始します。
N
(next)パターンスペースの内容の末尾に改行を追加し、更に次に読み込んだ一行を追加します。それ以上入力が無い時、sed
はそれ以上コマンドを処理することなく終了します。
-z コマンドラインオプションを指定した時は、行と行の間の区切りには、改行(\x0a)の代わりにASCII ‘NUL’(\x00)を追加します。
デフォルトでは sed
は次の入力行がなければ終了しません。これはGNUの拡張機能で、 --posix で無効にすることができます。「最終行でのNコマンド」参照。
P
パターンスペースの最初の改行(改行含む)までの1行をプリントする。
h
ホールドスペースの内容をパターンスペースの内容で置き換えます(cp pattern-space hold-space)。
H
(hold)ホールドスペースの内容末尾に改行を追加し、更にパターンスペースの内容を追加します。
g
パターンスペースの内容をホールドスペースの内容で置き換えます(cp hold-space pattern-space)。
G
パターンスペースの内容末尾に改行を追加し、更にホールドスペースの内容を追加します。
x
(exchange)パターンスペースの内容とホールドスペースの内容を交換する(swap pattern-space hold-space)。
sed
導師のためのコマンド群ほとんどの場合、これらのコマンドを使用するより、おそらく awk
またはPerlのようなものでプログラミングする方が得策であることを示しています。しかし時折、 sed
にこだわることに専念している人もいますし、これらのコマンドでかなり複雑なスクリプトを書くことができる可能性があります。
: label
[アドレス指定不可]
分岐コマンドの飛び先ラベル label を配置します。他の事は何もしません。
b label
指定の label へ無条件ジャンプします。ラベルを省略したときは次のサイクルを開始します。
t label
s
コマンドによる置換が成功した後で、かつ最後の入力行が読み込まれてないか他の条件分岐が実行されてない場合、指定のラベルへジャンプします。ラベルを省略したときは次のサイクルを開始します。
sed
固有のコマンドこれらのコマンドはGNU sed
固有なので、作成するsedプログラムが移植性に留意する必要がない場合のみ使うようにして下さい。以下はGNU sed
拡張を確認や日常の作業をするのに役立ちます。でも、まだ標準のsed
ではサポートされていません。
e [command]
このフラグはシェルコマンドからの入力をパターンスペースにパイプラインできます。e
コマンドをパラメータ無しに実行すると、パターンスペース内に見つけたコマンドを実行し、パターンスペースをそのコマンドの実行結果で置き換えます(末尾の改行は抑制されます)。
代わりに、パラメータを指定してe
コマンドを実行すると、コマンドはパラメータをシェルコマンドとして解釈して実行し、そのシェルコマンドの実行結果出力ストリームに送ります。コマンドは複数行に渡って書くことができ、コマンドの最後以外の各行の末尾にはバックスラッシュ'\'を書きます。
どちらの場合も、実行されるコマンドに\x00(ASCII NUL)バイトが含まれているとその結果は不明(未定義)です。
r
と異なり、シェルコマンドの実行結果を即座にプリントします。 一方、r
コマンドはサイクルの終わりまで出力を遅延します。
F
現在の入力ファイル名を(末尾に改行を伴って)出力します(標準入力の場合は'-')。
Q [exit-code]
このコマンドは単一のアドレスのみ受け入れます(アドレス範囲不可)。
このコマンドはq
コマンドと同じですが、パターンスペースの内容をプリントしません。q
コマンドと同様にsed呼び出し元へexit codeを返す事ができます。
このコマンドの代替方法は-nコマンドラインオプションの使用(スクリプトを必要以上に複雑にする)または次のコード片(スニペット)に頼る(何も表示されないけどファイル末尾まで行を読み込むので時間を無駄にする)ことです。
:eat $d 最終行で何も出力せず終了 N 何も出力せずもう1行読み込む g 毎回ホールドスペースの内容(空っぽ)をパターンスペースに上書き b eat
R filename
(read)filenameで指定したファイルからたかだか1行読み込み現在のサイクルの最後または次の入力行が読まれる時に出力ストリームに挿入する。注意:filenameで指定したファイルから読み込みできなかったり、既にEOFに到達していたら何もしない。なおその時何のエラーも出しません。
r
コマンドに/dev/stdinをファイル名として与えた時は標準入力から読み込みます。
T label
s
コマンドによる置換が失敗した後で、かつ最後の入力行が読み込まれてないか他の条件分岐が実行されてない場合(暗黙のs
コマンド実行結果フラグがまだクリアされてない間)、指定のラベルへジャンプします。ラベルを省略したときは次のサイクルを開始します。
v version
このコマンドはGNU sedでは何もしません(が、コマンドとして有効)。しかしGNU sed
拡張がサポートされていないと失敗します。なぜなら他のsed
ではこのコマンドは実装されてないからです。加えて、実行に必要なsed
のバージョンを 4.0.5
のように指定することができます(訳注:実行するsedが指定バージョンより低い場合はエラー'sed の新版が前提です'になります)。デフォルトのバージョンは 4.0
です。なぜならこのコマンドが最初に実装されたバージョンが4.0
だからです。
POSIXLY_CORRECT
環境変数が設定されていても、このコマンドはGNU拡張の利用を許可します。
W filename
パターンスペースの先頭から最初の改行(改行含む)までの内容を、与えられたファイル名のファイルに書き込みます。w
コマンドでファイル処理について述べられていることはこのコマンドにも全て当てはまります。
z
このコマンドはパターンスペースの内容を全削除します。これは‘s/.*//’と同様ですが、より有能で、入力ストリームに不正なマルチバイトつづりが現れる時も動作します。POSIXでは‘.’によって不正マルチバイトつづりにマッチしない事を強制します。そのためほとんどのマルチバイトロケール(UTF-8ロケールを含む)ではsedのバッファをスクリプトの途中で全削除する移植性のある方法はありません。
sed
プログラムでは複数のコマンドを与える時にいくつかの書き方があります。
sedスクリプトを( -fオプションを指定して)ファイルとして与える時は改行で区切るのが最も自然な方法です。
コマンドラインでも、全てのsed
コマンドは改行で区切る事ができます。代わりに各コマンドをそれぞれ-eオプションの引数として渡す事もできます。
$ seq 6 | sed '1d 3d 5d' 2 4 6 $ seq 6 | sed -e 1d -e 3d -e 5d 2 4 6
一番簡単に複数のコマンドを区切る方法はセミコロン(‘;’)です。
$ seq 6 | sed '1d;3d;5d' 2 4 6
{
、}
、b
、t
、T
、:
コマンドがセミコロンで区切れるのはGNU sed拡張です。
$ seq 4 | sed '{1d;3d}' 2 4 $ seq 6 | sed '{1d;3d};5d' 2 4 6
ラベルを使うコマンドである'b
'、't
'、'T
'、':
' は当該のコマンド直後からセミコロンや改行までを読み取ります。先頭の空白文字と末尾の空白文字があっても無視されます。ラベルの例として以下の‘x’をご覧ください。最初の例はGNU sed
用です。次の例は移植性のある(GNU sedでなくても動く)同等例です。分岐とラベルについて更に詳しくは「分岐と制御構文」参照。
$ seq 3 | sed '/1/b x ; s/^/=/ ; :x ; 3d' 1 =2 $ seq 3 | sed -e '/1/bx' -e 's/^/=/' -e ':x' -e '3d' 1 =2
次のコマンドはセミコロンで区切ることができなくて改行で区切る事が必要です。
a
,c
,i
(append/change/insert)a
、c
、i
コマンドの後にはappend/change/insertのためのテキストとして全ての文字を続ける事ができます。そこにセミコロンを使用すると残念な結果になります。
$ seq 2 | sed '1aHello ; 2d' 1 Hello ; 2d 2
これらのコマンドは-eオプションや改行で区切る必要があります。
$ seq 2 | sed -e 1aHello -e 2d 1 Hello $ seq 2 | sed '1aHello 2d' 1 Hello
a
、c
、i
コマンド直後に直接テキスト(‘Hello’)を追加できる自体がGNU sed
拡張であることに注意して下さい。移植性のある、POSIX準拠の代替手段は次のとおりです。
$ seq 2 | sed '1a\ Hello 2d' 1 Hello
#
(コメント)‘#’から次の改行までの全ての文字はsedから無視されます。
$ seq 3 | sed '# this is a comment ; 2d' 1 2 3 $ seq 3 | sed '# this is a comment 2d' 1 3
r
,R
,w
,W
(reading and writing files)r
、R
、w
、W
コマンドはその行末までをファイル名として解釈します。空白やコメントやセミコロンがある場合もファイル名の一部と解釈されるので、その場合は予期しない結果につながります。
$ seq 2 | sed '1w hello.txt ; 2d' 1 2 $ ls -log total 4 -rw-rw-r-- 1 2 Jan 23 23:03 hello.txt ; 2d $ cat 'hello.txt ; 2d' 1
r
、R
、w
、W
コマンドは(指定したファイルが存在しない等の)ファイル入出力エラーを単純に無視します。ご注意下さい。次の例ではsed
はファイル名‘hello.txt’のファイルを読み込もうとしています。. しかしファイルがありませんでした。でもエラーも一切出さずに無視され次のコマンドの実行に移ります。
$ echo x | sed '1rhello.txt ; N' x
e
(シェルコマンド実行)e
コマンドから改行までの全ての文字がシェルに送られます。空白やコメントやセミコロンがある場合もシェルコマンドに含まれるので、その場合は予期しない結果につながります。
$ echo a | sed '1e touch foo#bar' a $ ls -1 foo#bar $ echo a | sed '1e touch foo ; s/a/b/' sh: 1: s/a/b/: not found a
s///[we]
(上記をe
やw
フラグで代用する)w
フラグはs///
コマンド実行結果をファイルに書き込み、e
フラグはs///
コマンド実行結果をシェルコマンドとして実行します。r/R/w/W/e
コマンドは改行で終わっていなければなりません。空白やコメントやセミコロンがある場合もファイル名やシェルコマンドの一部と解釈されるので、その場合は予期しない結果につながります。
$ echo a | sed 's/a/b/w1.txt#foo' b $ ls -1 1.txt#foo
• アドレス概要: | アドレス概要 | |
• 数値指定アドレス: | 数値による行の選択 | |
• 正規表現アドレス: | テキストマッチによる行の選択 | |
• 範囲アドレス: | 行の範囲選択 |
アドレスはsed
コマンドを実行する対象行を決定します。次のコマンドは、144行でだけ‘hello’を‘world’に置き換えます。
sed '144s/hello/world/' input.txt > output.txt
アドレスが与えられてない時はコマンドは全ての行に対して実行されます。次のコマンドは、入力ファイルから読み込んだ全ての行で‘hello’を‘<s2>world</s2>’に置き換えます。
sed 's/hello/world/' input.txt > output.txt
アドレスは行番号の代わりに正規表現を含む事ができます。次のコマンドは、 ‘apple’を含む行でだけ‘hello’を‘world’に置き換えます。
sed '/apple/s/hello/world/' input.txt > output.txt
アドレス範囲を指定する時は2つのアドレスをカンマ(,
)で区切ります。アドレス範囲のアドレスは数字でも正規表現でも両方を混ぜる事もできます。次のコマンドは、4行から17行だけ‘hello’を‘world’に置き換えます(inclusive)。
sed '4,17s/hello/world/' input.txt > output.txt
!
文字をアドレス指定の終わり(コマンド文字の前) に指定するとマッチの否定になります。すなわち、!
文字がアドレスやアドレス範囲の後ろにあると、選択したアドレス以外の行を対象とします。次のコマンドは‘apple'を含まない行だけ‘hello’を‘world’に置き換えます。
sed '/apple/!s/hello/world/' input.txt > output.txt
次のコマンドは入力ファイルの1から3行と18から最終行だけ‘hello’を‘world’に置き換えます(すなわち excluding lines 4 to 17)。
sed '4,17!s/hello/world/' input.txt > output.txt
sed
スクリプトのアドレスは以下のいずれかの形式を取ります。
number
行番号を指定すると入力の当該行番号の行だけにマッチします(注意:-i や -s コマンドラインオプションを指定しない限り、全ての入力ファイルを通して行番号を振ります)。
$
このアドレス指定は入力ファイル群の最後のファイルの最終行、または、-i or -sコマンドラインオプションが指定された時は入力の各ファイルごとの最終行にマッチします。
first~step
このGNU拡張は、firstと、firstから指定stepごとの行にマッチします。数値 n がいずれかの正の数であるとして、 現在行が式 first + (n * step) に合致する場合に選択されます。したがって、奇数行を選択するには 1〜2
を、偶数行を選択するには 0〜2
を使用します。 2行目から3行おきに選択するには、「 2〜3 」を使用します。 10行目から5行ごとに選択するには、 10〜5 を使用します。 「 50〜0 」は、あいまいな 50
の言い方です。
以下のコマンドはステップアドレスのデモです。
$ seq 10 | sed -n '0~4p' 4 8 $ seq 10 | sed -n '1~3p' 1 4 7 10
GNU sed
は以下の正規表現をサポートしています。デフォルトの正規表現はBasic Regular Expression (BRE)(基本正規表現)です。-E や -r コマンドラインオプションを指定した場合、正規表現の文法はExtended Regular Expression (ERE)(拡張正規表現)でなければなりません。「BRE vs ERE」参照。
/regexp/
正規表現 regexp にマッチする全ての行を選択します。regexp それ自身が'/
'文字を含む時は、'\
'でエスケープしなければなりません。
次のコマンドは'/etc/passwd'ファイルの行末が‘bash’である行だけをプリントします。5
sed -n '/bash$/p' /etc/passwd
空の正規表現 '//'は最後の正規表現のマッチを繰り返します(空の正規表現が s
コマンドに渡される場合も同じです)。注意:正規表現のフラグは正規表現のコンパイル時に評価されるため、空の正規表現と一緒に指定しても無効です。
\%regexp%
('%
'は他の任意の1文字に置き換えることができます)。
これも正規表現 regexpにマッチします。つまり'/
'と異なる区切りを使えます。これはregexp自身がたくさんの'/'を含んでいる場合に特に便利です。なぜならこうすれば全ての'/
'にエスケープするのを避ける事ができるからです。regexp 内に区切り文字を含める時は、'\
'でエスケープしなければなりません。
次のコマンドはいずれも等価です。これらは‘/home/alice/documents/’で始まる行をプリントします。
sed -n '/^\/home\/alice\/documents\//p' sed -n '\%^/home/alice/documents/%p' sed -n '\;^/home/alice/documents/;p'
/regexp/I
\%regexp%I
GNU拡張の'I
'フラグは sed に正規表現 regexpの英大文字小文字を区別せずにマッチングするよう指示します。
他の多くのプログラミング言語では、小文字を区別しない正規表現のマッチングに小文字の i
が使用されます。でも sed
では、既に i
は挿入コマンドを表す文字としてつかわれているのです(「insert command(挿入コマンド)」参照)。
次の2つの例の違いをよく見て下さい。
1つ目の例では、'/b/I
'はアドレスです。正規表現は'I
'フラグを伴っています。d
は削除コマンドです。
$ printf "%s\n" a b c | sed '/b/Id' a c
では、次にの例では'/b/
'のみが正規表現です。'i
'は挿入コマンドです。'd
'は'i'コマンドによって挿入される文字列です。マッチした行の前にテキスト‘d’が挿入されます。
$ printf "%s\n" a b c | sed '/b/id' a d b c
/regexp/M
\%regexp%M
GNU sed
拡張の'M
'フラグは正規表現が複数行マッチモードで動くように指示します。このフラグは'^
'と'$
'をそれぞれ(通常の振る舞いに加えて)改行の後の空の文字列と改行の前の空の文字列に一致させます。常にバッファの先頭または末尾に一致する特殊文字つづり('\`
'と'\'
')があります。さらに、複数行モードではピリオド('.')は改行文字とマッチしません。
正規表現アドレスの場合はパターンスペースの現在の内容に作用します。(例えば s///
コマンドで)パターンスペースの内容が変更されると、正規表現マッチングは変更後のテキストに作用します。
次の例ではサイクル間の自動プリントは、-nコマンドラインオプションによって無効にされています。's/2/X/
'コマンドは対象行に含まれる‘2’を ‘X’に変更します。'/[0-9]/p
'は0から9の数字いずれかを含む行とマッチして、マッチした行をプリントします。次の例では正規表現アドレス/[0-9]/
とマッチを試みる前に2行目の内容の数字は'X'に置換されてしまいなくなってしまうので、/[0-9]/
とマッチすることもなく、プリントもしません。
$ seq 3 | sed -n 's/2/X/ ; /[0-9]/p' 1 3
アドレスの範囲は2つの単一アドレスをカンマ(',
')で区切ることで指定することが出来ます。. アドレスの範囲は最初のアドレスにマッチした行から始まって、2つ目のアドレスマッチするまで(2つ目のアドレス含む)続きます((inclusively)。
$ seq 10 | sed -n '4,6p' 4 5 6
2番目のアドレスが正規表現の場合、アドレス範囲の終わる行のマッチングは、最初のアドレスと一致した行の次の行から開始します。なお、範囲は(入力ストリームが最初のアドレスと一致した行で終了する場合を除き)常に2行以上になります。
$ seq 10 | sed -n '4,/[0-9]/p' 4 5
2番目のアドレスが最初のアドレス以下の数値の場合、最初のアドレスのみにマッチします(単一アドレス扱い)。
$ seq 10 | sed -n '4,1p' 4
GNU sed
は特殊な2アドレス形式もサポートしています。これらは全てGNU拡張です。
0,/regexp/
行番号0
(ゼロ)をアドレスに指定することが出来ます。 '0,/regexp/
'のようにすると、sed
は入力行の最初からregexpのマッチを試みます。'0,/regexp/
'は'1,/regexp/
'に似ていますが、'0,/regexp/
'のaddr2は入力行の最初から範囲終了としてマッチを試みますが、'1,/regexp/
'ではアドレス範囲の原則に従い、範囲は最低2行になります。つまり範囲終了としてマッチを試みるのは2行目からです。
注意:上記が0
アドレスが意味をなす唯一の場所です。0行目というのは存在しませんから、これ以外の方法で 0
アドレスが与えられるとエラーになります。
以下の例はアドレス 0開始と1開始の違いをデモしています。
$ seq 10 | sed -n '1,/[0-9]/p' 1 2 $ seq 10 | sed -n '0,/[0-9]/p' 1
addr1,+N
addr1と、それに続く N 行の範囲にマッチします。
$ seq 10 | sed -n '6,+2p' 6 7 8
addr1 は数値または正規表現を指定できます。
addr1,~N
addr1 とそれに続くNの倍数の行までの範囲にマッチします。次のコマンドは行6から開始して、4の倍数の行8までをプリントします。
$ seq 10 | sed -n '6,~4p' 6 7 8
addr1 は数値または正規表現を指定できます。
• 正規表現概要: | sed の正規表現の概要
| |
• BRE vs ERE: | 基本正規表現(basic;BRE) と拡張正規表現(extended; ERE)の文法。 | |
• BRE文法: | 基本正規表現文法概要 | |
• ERE文法: | 拡張正規表現文法概要 | |
• 文字クラスと角括弧式: | ||
• 正規表現拡張: | 追加の正規表現コマンド。 | |
• 後方参照と部分式 | 後方参照と部分式 | |
• エスケープ: | 特殊文字の指定方法。 | |
• ロケールへの配慮: | マルチバイト文字とロケールへの配慮。 |
sed
の正規表現の概要 sed
の使い方を知るためには、正規表現を理解する必要があります(正規表現 regular expresson は regexp と略される事があります)。正規表現は対象の文字列に対して左から右へマッチしていくパターンです。ほとんどの文字はそれそのもの(ordinary)です。パターンの中で自分自身を表し、自分自身が表す文字とマッチします。sed
の正規表現は2つのスラッシュ('/')で囲んで指定します。
次のコマンドは‘hello’を含む行をプリントします。
sed -n '/hello/p'
上野例は次のgrep
コマンドと同じです。
grep 'hello'
正規表現の威力は、パターンに選択肢と繰り返しを含めることができることにあります。これらは特殊文字を使用してパターンにエンコードされています。特殊文字はそれ自体を表す形ではなく、代わりに特殊な方法で解釈されます。
正規表現内で '^
' (カレット)は行の先頭にマッチします。'.
'(ピリオド)は任意の1文字にマッチします。次の sed
コマンドは、行頭が‘b’で、次の1文字が任意の1文字でその次の文字が‘d’である行をプリントします。
$ printf "%s\n" abode bad bed bit bid byte body | sed -n '/^b.d/p' bad bed bid body
次節では、正規表現における特殊文字の意味と使用法について説明します。
基本正規表現と拡張正規表現は、指定されたパターンの文法に対する2つのバリエーションです。基本正規表現(BRE)文法は sed
(および grep
でも同様)のデフォルトです。POSIX指定の -E オプション( -r 、 --regexp-extended )を使用して、拡張正規表現(ERE)文法を有効にします。
GNU sed
では、基本正規表現と拡張正規表現の唯一の違いは、いくつかの特殊文字、つまり、 '?'、 '+'、丸括弧('(...)')、中括弧('{...}')、パイプ('|')の動作です。
基本正規表現(BRE)文法では、これらの文字はバックスラッシュ('\')を前に付けない限り特別な意味を持ちません。 逆に拡張正規表現(ERE)文法では、これらの文字はバックスラッシュ('\')が付いていない限り特殊文字です。
望ましいパターン | Basic (BRE) Syntax | Extended (ERE) Syntax |
---|---|---|
文字としての‘+’ (プラス記号) | $ echo 'a+b=c' > foo $ sed -n '/a+b/p' foo a+b=c | $ echo 'a+b=c' > foo $ sed -E -n '/a\+b/p' foo a+b=c |
以下の例では、1つ以上の文字‘a’のあとに1文字の‘b’続きます(プラス記号は特殊メタキャラクタ扱いになっています)。 | $ echo aab > foo $ sed -n '/a\+b/p' foo aab | $ echo aab > foo $ sed -E -n '/a+b/p' foo aab |
本節ではsed
で使われる正規表現文法をさらっと説明します。
文字
その文字があらわすそのものにマッチします。
*
これはその直前の正規表現の0回以上(0の時は無し)の繰り返しのつづりにマッチします。直前の正規表現は、普通の文字、'\'が前に付いた特殊文字、'.'(ピリオド)、グループ化された正規表現(下記参照)、あるいは角括弧式でなければなりません。GNUの拡張として、接尾辞付きの正規表現の後に *
を続けることもできます。 たとえば、 a **
は a *
と同じです。POSIX 1003.1-2001は *
が正規表現または正規表現の部分式の始めに現れるときはそれ自身を意味すると言いますが、多くの非GNU実装はこれをサポートしておらず、移植可能なスクリプトはこれらの文脈では代わりに \*
を使うべきです。
.
任意のキャラクタにマッチします。改行も含みます。
^
パターンスペースの最初のNUL文字にマッチします。すなわち、'^'(曲折アクセント記号)に後ろに続くものはパターンスペースの最初の文字になります。
ほとんどのスクリプトでは、パターンスペースは各行の内容に初期化されます(「sed
はどのように動くか」参照)。なので、^#include
は、行の最初に'#include'がある行のみに一致するものと単純化すると分かりやすいです。例えば、その前にスペースがある場合はマッチは失敗します。この単純化は、元のパターンスペースの内容が変更されていない限り有効です。例えば s
コマンドで有効です。
^
は、正規表現または正規表現部分式の先頭(つまり、'\(
'または'\|
'の後)でのみ特殊文字として機能します。ただし、POSIXでは ^
をその文脈では通常の文字として扱う実装が許されているため、移植可能なスクリプトでは、正規表現部分式の冒頭で ^
を使用しないでください。
$
^
と同様ですが、これはパターンスペースの終わりを意味します。$
は、正規表現または正規表現部分式の末尾(つまり、'\)
'または'\|
'の前)でのみ特殊文字として機能します。そして正規表現部分式末尾でのこれの使用は移植性がありません。
[list]
[^list]
listの任意の1文字にマッチします。例えば [aeiou]
は(英語の)母音全てにマッチします。listは'char1-char2
'のようなつづりを含むことができます。それはchar1 から char2 の任意の1文字にマッチします。「文字クラスと角括弧式」参照。
\+
*
と同様ですが、1以上の繰り返しにマッチします。これはGNU拡張です。
\?
*
と同様ですが、0または1回の(繰り返し;出現)にマッチします。これはGNU拡張です。
\{i\}
*
と同様ですが、正確にi個の繰り返しのつづりにマッチします(i は10進整数値です。移植性を保つには0から255の範囲内で指定して下さい)。
\{i,j\}
繰り返しのうち、i番目からj番目の範囲だけマッチします。, inclusive, sequences.
\{i,\}
i個またはそれ以上の繰り返しのつづりにマッチします。
\(regexp\)
中に書いたregexpを一体としてグループにします。以下のように使います。
regexp1\|regexp2
これはregexp1 か regexp2 にマッチします。複雑な代替正規表現を使うために括弧を使って下さい。マッチング処理では、左から右へ順番に各選択肢を試し、成功した最初の選択肢が使用されます。これはGNU拡張です。
regexp1regexp2
regexp1 と regexp2 をつなげた正規表現にマッチします。連結は \|
、^
、 $
よりも強く結合しますが、他の正規表現演算子よりは強く結合しません。
\digit
正規表現内で括弧でくくられた部分のうちdigit番目の部分にマッチします。これは後方参照と呼ばれます。部分式は \(
の出現を左から右に順番に数えることによって暗黙にナンバリングされます。
\n
改行にマッチします
\char
charが、 $
, *
, .
, [
, \
、^
のいずれかであるとき、その文字自身にマッチします(特殊文字としての機能を打ち消します)。注意:移植可能と想定できるC言語風のバックスラッシュつづりは'\n
'と'\\
'だけです。 特に'\t
'は移植性がなく、sed
のほとんどの実装では、タブ文字ではなく't'にマッチします。
注意:正規表現マッチ機構は貪欲です。すなわち、マッチは左から右へ試みられ、そして同じ文字から始めて2つ以上のマッチが可能であるならば、その最長を選択します。
例:
‘abcdef’にマッチ。
0個以上の‘a’に続く1文字の‘b’のつづりにマッチします。例えば、‘b’や‘aaaaab’.
‘b’または‘ab’にマッチ。
1つ以上の‘a’に続く1つ以上の‘b’であるつづりにマッチ。‘ab’は最小のマッチです。他には‘aaaab’や‘abbbbb’や‘aaaaaabbbbbbb’。
上記2つは両方とも全ての文字にマッチします。けれども1つ目は空文字列含む全ての文字列にマッチする一方、2つ目は1文字以上の文字列にマッチします。
上記は‘main’ではじまり、その後に'('と')'がこの順番で出現する文字列にマッチします。‘n’と‘(’と‘)’は隣接している必要はありません。
‘#’で始まるストリングにマッチします。
1つのバックスラッシュ'\'で終わる文字列にマッチします。この正規表現には特殊文字のバックスラッシュとその意味を打ち消すエスケープ用のバックスラッシュの、2つのバックスラッシュが含まれています。
一方、上記は1つの'$'にマッチします。なぜなら$特殊文字の意味がバックスラッシュによってエスケープされているからです。
Cロケールでは、これはASCII文字と数字にマッチします。
(ここで «TAB» はタブ文字(ASCII HT;\x09)を表します)上記はスペース(0x20)またはタブ(0x09)以外の任意の文字の1文字以上にマッチします。通常これは(英語の)単語を意味します。
これは、改行で区切られた2つの等しい部分文字列で構成される文字列と一致します。
これは9文字にマッチし、その後に行末に'A'が続きます。
これは16文字でかつその最後が‘A’である文字列にマッチします。
基本正規表現と拡張正規表現の唯一の違いは、いくつかの特殊文字、つまり、 '?'、 '+'、丸括弧('(...)')、中括弧('{...}')、パイプ('|')の動作です。基本正規表現では、特殊文字として振る舞わせるにはこれらをエスケープする必要がありますが、逆に拡張正規表現を使用するときにはリテラル文字と一致させるにはエスケープする必要があります。ここで‘|’(パイプ)は特別な意味を持ちます。‘\|’はGNUの拡張機能なので、標準の基本正規表現では機能が提供されません。
例:
abc?
上記は拡張正規表現を使用すると、'abc\?'になります。'abc\?'は、拡張正規表現ではリテラル文字列‘abc?’にマッチします。
c\+
拡張正規表現では‘c+’になります。上記は拡張正規表現では1つ以上の‘c’にマッチします。
a\{3,\}
拡張正規表現では‘a{3,}’となります。上記は拡張正規表現では3個以上の‘a’にマッチします。
\(abc\)\{2,3\}
拡張正規表現では‘(abc){2,3}’になります。‘abcabc’か‘abcabcabc’のどちらかにマッチします。
\(abc*\)\1
拡張正規表現では‘(abc*)\1’となります。後方参照は拡張正規表現でも依然としてエスケープされる必要があります。
a\|b
拡張正規表現では‘a|b’となります。‘a’または‘b’にマッチします。
角括弧式は ‘[’と‘]’で囲まれた文字のリストです。リスト内の任意の1文字にマッチします。最初の文字が‘^’の時はリストに無い任意の1文字にマッチします。次のコマンドは‘gray’または‘grey’を‘blue’に置き換えます。
sed 's/gr[ae]y/blue/'
角括弧式は、基本と拡張の両方の正規表現で使用できます(つまり、 -E や -r の有無にかかわらず)。
角括弧式の中では、範囲式はハイフン'-'で区切られた2文字で構成されています。それは2つの文字の間でソートする任意の1文字と一致します。包括的(inclusive)です。デフォルトのCロケールでは、ソート順はネイティブの文字順です。 たとえば、'[a-d]'は'[abcd]'と同じです。
最後に、以下のように、特定の名前付き文字クラスが角括弧式の中で使えるよう事前定義されています。
これらの名前付きクラスはブラケット([...])の中でしか使えません。正しい使い方:
$ echo 1 | sed 's/[[:digit:]]/X/' X
間違った使い方はsed
の新しい版では拒絶されます。より古いバージョンはそれを受け入れましたが、現在それは単なる角括弧式として扱われます('[dgit:]'と等価です。すなわち、文字'd'、'g'、'i'、't'、':'のいずれかにマッチします)。
# GNU sed の現在の版ではこれは不正として拒絶される $ echo 1 | sed 's/[:digit:]/X/' sed: character class syntax is [[:space:]], not [:space:] # GNU sed の古い版 $ echo 1 | sed 's/[:digit:]/X/' 1
英数字を表すのは‘[:alpha:]’と‘[:digit:]’です。これは‘C’ロケールとACII文字エンコーディングでは‘[0-9A-Za-z]’と同じです。
アルファベット文字は‘[:lower:]’と‘[:upper:]’です。‘C’ロケールとASCII文字エンコーディングでは‘[A-Za-z]’と同じです。
空白文字は空白(0x20)とタブ(0x09)です。
コントロール文字。ASCIIでは8進数の000から037と、177(DEL)です(16進数では \x00から\x1Fと\x7F)。他の文字セットは、もしそれがあればその文字と等価です。
Digits(数字): 0 1 2 3 4 5 6 7 8 9
.
Graphical characters(グラフィック文字): ‘[:alnum:]’と‘[:punct:]’です。
小文字。‘C’ロケールでASCIIエンコーディングでは a b c d e f g h i j k l m n o p q r s t u v w x y z
です。
Printable characters(表示可能文字)。‘[:alnum:]’と‘[:punct:]’と空白です
Punctuation characters(句読点文字)。‘C’ロケールでASCIIエンコーディングではこれは以下のものです。! ” # $ % & ' ( ) * + , - . / : ; < = > ?@ [ \ ] ^ _ ` { | } ~
Space characters(空白文字)。‘C’ロケールでASCIIエンコーディングではこれは、タブ(HT;0x09)、改行(LF;0x0A)、垂直タブ(VT;0x0B)、フォームフィード(FF;0x0C)、キャリッジリターン(CR;0x0D)、空白(0x20)です。
大文字。‘C’ロケールでASCIIエンコーディングではこれは、A B C D E F G H I J K L M N O P Q R S T U V W X Y Z
です。.
16進数。0 1 2 3 4 5 6 7 8 9 A B C D E F a b c d e f
です。
注意: これらのクラス名のブラケット('[',']')は記号名の一部であり、角括弧式を区切る大括弧('[',']')に加えて含める必要があります。
ほとんどのメタキャラクタは角括弧式の中ではその特別な意味を失います。
最初のリスト項目ではない場合は、角括弧式を終了します。したがって、文字として'] 'の文字をリスト項目にする場合は、最初にそれを配置する必要があります。
リストの最初または最後ではない場合、または範囲の終点でない場合は、範囲を表します。
リストにない文字を表します。リストの項目として文字としての‘^’を使いたい場合はリストの最初以外に配置します。
TODO: incorporate this paragraph (copied verbatim from BRE section).
リストの中では $
, *
, .
, [
, \
は特殊文字ではなく通常の文字です。例えば、[\*]
は文字‘\’か文字‘*’のどちらかにマッチします。なぜなら\
は特殊文字ではないからです。けれども、[.ch.]
、[=a=]
、[:space:]
のような文字列はリスト内では特殊です。これらはそれぞれ照合シンボル、等価クラス、文字クラスを表します。したがって、
[
の後に.
、=
、:
が続く場合、 list 内で特別です。また、POSIXLY_CORRECT
モードではない場合、\n
や\t
のような特別なエスケープはリスト内でで無効になりません。「エスケープ」参照。
照合シンボルの開始を表します。
照合シンボルの終了を表します。
等価クラスの開始を表します。
等価クラスの終了を表します。
文字クラスシンボルの開始を表し、その後に有効な文字クラス名を続ける必要があります。
文字クラスシンボルの終了を表します。
以下のつづり達は(アドレスや s
コマンドで使われる)正規表現の内側で特別な意味を持ちます。
これらは基本と拡張の両方の正規表現で使用できます(つまり、 -E や -r の有無にかかわらず)。
\w
任意の「単語」の文字にマッチします。「単語」の文字とは、任意の文字または数字またはアンダースコア'_'です。
$ echo "abc %-= def." | sed 's/\w/X/g' XXX %-= XXX.
\W
「非単語」文字にマッチします。
$ echo "abc %-= def." | sed 's/\W/X/g' abcXXXXXdefX
\b
単語の境界に一致します。 つまり、左側の文字が「単語」の文字で右側の文字が「非単語」の文字である場合、またはその逆の場合に一致します。
$ echo "abc %-= def." | sed 's/\b/X/g' XabcX %-= XdefX.
\B
単語の境界を除くあらゆる場所に一致します。 つまり、左側の文字と右側の文字が両方とも「単語」の文字であるか、両方の「非単語」の文字であるかに一致します。
$ echo "abc %-= def." | sed 's/\B/X/g' aXbXc X%X-X=X dXeXf.X
\s
空白文字(空白とタブ)にマッチします。パターンスペースやホールドスペースに埋め込まれた改行にも一致します。
$ echo "abc %-= def." | sed 's/\s/X/g' abcX%-=Xdef.
\S
非空白文字にマッチします。
$ echo "abc %-= def." | sed 's/\S/X/g' XXX XXX XXXX
\<
単語の最初にマッチします。
$ echo "abc %-= def." | sed 's/\</X/g' Xabc %-= Xdef.
\>
単語の最後にマッチします。
$ echo "abc %-= def." | sed 's/\>/X/g' abcX %-= defX.
\`
パターンスペースの最初にのみマッチします。これは複数行モードの ^
とは異なります。
以下の2つの例を比べてみて下さい。
$ printf "a\nb\nc\n" | sed 'N;N;s/^/X/gm' Xa Xb Xc $ printf "a\nb\nc\n" | sed 'N;N;s/\`/X/gm' Xa b c
\'
パターンスペースの最後にのみマッチします。これは複数行モードでの $
とは異なります。
後方参照は、一致した正規表現の前の部分を参照する正規表現コマンドです。後方参照はバックスラッシュと1桁の数字で指定されます(例:\1 )。それらが参照する正規表現の一部は部分式と呼ばれ、丸括弧で示されます。
後方参照と部分式は、正規表現検索パターンの中とs
コマンドreplacementの部分の2つの場合に使用されます(「正規表現アドレス」と「The "s" Command」参照)。
正規表現パターンでは、後方参照は、以前に一致した部分式と同じ内容を一致させるために使用されます。次の例では、部分式は‘.’で、この場合任意の1文字を意味します(丸括弧で囲まれていると部分式になります)。後方参照 '\1'は、部分式と同じ内容(同じ文字)に一致するように要求します。
以下のコマンドは、任意の文字で始まり、その後に文字‘o’、その後に最初の文字と同じ文字が続く単語に一致します。
$ sed -E -n '/^(.)o\1$/p' /usr/share/dict/words bob mom non pop sos tot wow
複数の部分式は左から右に自動的に採番されます。このコマンドは6文字の回文を検索します(最初の3文字は3つの部分式で、その後に3つの後方参照が逆順に続きます)。
$ sed -E -n '/^(.)(.)(.)\3\2\1$/p' /usr/share/dict/words redder
s
コマンドでは、 replacement 部分で後方参照を使用して regexp 部分の部分式を参照できます。
次の例では、スペースで区切られた2つの単語に一致させるために、正規表現で2つの部分式を使用しています。 replacement 部分の後方参照は、単語を異なる順序で表示します。
$ echo "James Bond" | sed -E 's/(.*) (.*)/The name is \2, \1 \2./' The name is Bond, James Bond.
alternation('|')が使用されている時、部分マッチした側にグループが含まれていないと、後方参照は全体のマッチを失敗させます。例えば‘a(.)|b\1’は‘ba’にはマッチしません。-e やファイル(‘-f file’)で複数の正規表現を指定する時、後方参照は指定ごとの各正規表現ローカルです。
この章までは、 sed
に曲折アクセント記号('^')を特殊文字として解釈するのではなく、文字通りに解釈するように指示する '\^'という形式のエスケープにしか遭遇しませんでした。例えば、‘\*’は0個以上のバックスラッシュ'\'ではなく1文字の'*'にマッチします。
この章では、別の種類のエスケープ6、つまり通常文字そのものとして使用される文字・文字のつづりに適用されるエスケープ、およびsed
が特殊文字に置き換えるエスケープを紹介します。これは、印刷不可能な文字をパターンで視覚的にエンコードする方法を提供します。 sed
スクリプト内の非印刷文字の表示に制限はありませんが、スクリプトがシェル内またはテキスト編集によって準備されている場合は、通常、それを示す文字コードを指定するよりも以下のエスケープシーケンスのいずれかを使用するほうが簡単です。
それらのエスケープの一覧です。
\a
BEL文字を生成するかマッチします。それは"alert"(ASCII BEL;0x07)です。
\f
フォームフィード(ASCII FF;0x0C)を生成するかマッチします。
\n
改行(ASCII LF;0x0A)を生成するかマッチします。
\r
キャリッジ・リターン(ASCII CR;0x0D)を生成するかマッチします。
\t
タブ(水平タブ)(ASCII HT;0x09)を生成するかマッチします。
\v
垂直タブ(ASCII VT;0x0B)を生成するかマッチします。
\cx
コントロール文字(CONTROL-x)を生成するかマッチします。ここで x は任意の文字です。‘\cx’の正確な効果は以下のとおりです。なお、x が小文字の場合は大文字に変換したうえで評価されます。それから文字の6ビット目(16進数で 0x40)を反転させます。したがって、「\cz」は16進数1Aになり、「\c{」は16進数3Bになり、「\c;」は16進数7Bになります。
\dxxx
ASCII 値が10進数の xxx の文字を生成またはマッチします。
\oxxx
ASCII 値が8進数の xxx の文字を生成またはマッチします。
\xyy
ASCII 値が16進数の yy の文字を生成またはマッチします。
‘\b’(バックスペース)は、既存の「単語境界」の意味と競合するため省かれています。
GNU sed
は s///
コマンドの正規表現マッチングやアドレスのマッチングにテキストを渡す前にエスケープシーケンスを処理します。次の2つのコマンドは等価です(‘0x5e’は16進表記した文字‘^’のASCII値)。
$ echo 'a^c' | sed 's/^/b/' ba^c $ echo 'a^c' | sed 's/\x5e/b/' ba^c
‘[’のASCII値が‘0x5b'、‘]’のASCII値が‘0x5d’であるのだからと、次の通り書いたとします。
$ echo abc | sed 's/[a]/x/' Xbc $ echo abc | sed 's/\x5ba\x5d/x/' Xbc
ただし、予期しない境界ギリギリの状態(edge-case)が発生するため、このような特殊文字は避けてください。例えば次の2つの例は等価ではありません。
$ echo 'a^c' | sed 's/\^/b/' abc $ echo 'a^c' | sed 's/\\\x5e/b/' a^c
GNU sed
はマルチバイトロケール(例 UTF-8
)でマルチバイト文字を適切に処理できます。7
次の例ではギリシャ文字の大文字のシグマ (Σ, ユニコードでは 0x03A3
)を使用しています。UTF-8
ロケールではsed
は2オクテット(2バイト)であってもシグマを正しく1文字として処理します。
$ locale | grep LANG LANG=en_US.UTF-8 $ printf 'a\u03A3b' aΣb $ printf 'a\u03A3b' | sed 's/./X/g' XXX $ printf 'a\u03A3b' | od -tx1 -An 61 ce a3 62
1オクテット(1バイト)単位の処理をsed
に強制したいときは、(POSIX
ロケールとして知られている)C
ロケールを使って下さい。
$ printf 'a\u03A3b' | LC_ALL=C sed 's/./X/g' XXXX
マルチバイトロケールでのsed
の正規表現は不正なマルチバイトつづりにマッチできません。
次の例は不完全なマルチバイト文字である0xCE
です(�と表示されます)。正規表現‘.’はこれにマッチできません。
$ printf 'a\xCEb\n' a�e $ printf 'a\xCEb\n' | sed 's/./X/g' X�X $ printf 'a\xCEc\n' | sed 's/./X/g' | od -tx1c -An 58 ce 58 0a X X \n
同様に、’全てをキャッチする’ 正規表現 ‘.*’ を使ってみても行全体ともマッチできません。
$ printf 'a\xCEc\n' | sed 's/.*//' | od -tx1c -An ce 63 0a c \n
GNU sed
には不正なマルチバイト文字に関係なくパターンスペースの内容を全削除する特別なコマンドz
コマンドがあります(s/.*//
のように動作しますが、無効なマルチバイト文字も削除します。
$ printf 'a\xCEc\n' | sed 'z' | od -tx1c -An 0a \n
あるいは、C
ロケールにして1オクテット単位(1バイト単位で)処理させます(C
ロケールでは全てのオクテット値(バイト値)が有効です)。
$ printf 'a\xCEc\n' | LC_ALL=C sed 's/.*//' | od -tx1c -An 0a \n
sed
が不正なマルチバイト文字を処理できないことを、ファイル内のそのような不正つづりの検知に使うことができます。以下の例では\xCE\xCE
は不正マルチバイトつづりですが、 \xCE\A3
は適正なマルチバイト文字(ギリシャ文字のシグマ)を含むつづりです。
sed
プログラムはs/.//g
によって全ての適正な文字を取り除きます。パターンスペースに残った任意の内容(不正なマルチバイト文字)は、H
コマンドによってホールドスペースに追加されます。最終行($
)でホールドスペースの内容は回収されます(x
)。改行が全て削除され(s/\n//g
)、残った任意のデータが非表示文字も印刷可能な形で(unambiguously)プリントされます(l
)。したがって、不正なマルチバイトつづりは8進値として出力されます。
$ printf 'ab\nc\n\xCE\xCEde\n\xCE\xA3f\n' > invalid.txt $ cat invalid.txt ab c ��de Σf $ sed -n 's/.//g ; H ; ${x;s/\n//g;l}' invalid.txt \316\316$
さらにいくつかのコマンドを使用すると、 sed
は無効な各文字に対応する正確な行(この例では3行目)の行番号を表示できます。これらの文字は、 C
ロケールを強制し、8進エスケープシーケンスを使用することで削除できます。
$ sed -n 's/.//g;=;l' invalid.txt | paste - - | awk '$2!="$"' 3 \316\316$ $ LC_ALL=C sed '3s/\o316\o316//' invalid.txt > fixed.txt
GNU sed
’の置換コマンド(s
)は\U
、\L
を使うことで大文字小文字変換をサポートします。 これらの変換はマルチバイト文字をサポートします。
$ printf 'ABC\u03a3\n' ABCΣ $ printf 'ABC\u03a3\n' | sed 's/.*/\L&/' abcσ
「The "s" Command」参照
Cロケール以外の他のロケールでは、ソート順は指定されておらず、 ‘[a-d]’は‘[abcd]’または ‘[aBbCcDd]’と同等であるか、または任意の文字、またはそれが一致する文字のセットと一致しない可能性があります。マッチは不規則かもしれません。角括弧式の伝統的な解釈を取得するために、環境変数 LC_ALL
を値 C に設定して ' C 'ロケールを使用できます。
# TODO: is there any real-world system/locale where 'A' # is replaced by '-' ? $ echo A | sed 's/[a-z]/-/' A
これらの解釈は LC_CTYPE
ロケールに依存します。 たとえば、 [[:alnum:]] は、現在のロケールでの数字と文字の文字クラスを意味します。
TODO: show example of collation
# TODO: this works on glibc systems, not on musl-libc/freebsd/macosx. $ printf 'cliché\n' | LC_ALL=fr_FR.utf8 sed 's/[[=e=]]/X/g' clichX
sed
の高度な話題: サイクルとバッファ• 実行サイクル: | sed はどのように動いているか
| |
• ホールド用とパターン用のバッファ: | ||
• 複数行テクニック: | D,G,H,N,P コマンドで複数行処理 | |
• 分岐と制御構文: |
sed
はどのように動いているかsed
は2つのバッファを保持しています。それは現に活動中のパターンスペースと補助のホールドスペースです。両方とも最初は空です。
sed
は入力の各行ごとに以下のサイクルを実行します。最初にsed
は入力ストリームから1行読み取り、末尾の改行を削除し、パターンスペースに入れます。次にコマンド群を実行します。各コマンドはそのコマンドに関連付けられたアドレスを持つこともできます。アドレスは一種の条件コードで、条件に合致した時だけそのコマンドが実行されます。
スクリプトの最後まで到達した時(-nが指定されてなければ)、最初に一行読み込む時に削除した行末の改行を戻してから(読み込む時に行末の改行を削除してなかったらそのまま)、パターンスペースの内容を出力ストリームにプリントアウトします。8 それから次の入力行の為のサイクルを開始します。
(Dコマンドのような)特殊コマンドが使われてない限り、次のサイクルを開始する前にパターンスペースの内容を削除します。一方ホールドスペースの内容はサイクル毎に削除しません。以降の新しいサイクルが始まっても内容を保持しています(両バッファの間でデータを移動させるためのコマンド、 ‘h’, ‘H’, ‘x’, ‘g’, ‘G’ 参照)。
TODO
複数行は D
,G
,H
,N
,P
コマンドを使って1つのバッファで処理できます。これらは、それぞれ対応する小文字のコマンド(d
,g
,h
,n
,p
)と似ていますが、埋め込まれた改行を尊重しながらデータを追加または削除するという点が異なります。パターンスペースとホールドスペースで行を追加・削除できます。
これらのコマンドの動作は以下の通り。
D
パターンスペースから最初の改行まで(改行含む)1行を削除する。パターンスペースのプリントや全削除をスキップして次のサイクルを開始する。
G
パターンスペースの末尾に改行を追加し更にホールドスペースから1行パターンスペースに追加します。
H
ホールドスペースの末尾に改行を追加し更にパターンスペースから1行追加します。
N
1行追加。入力ストリームから1行パターンスペースに追加する。
P
パターンスペースの最初の改行(改行含む)までの1行をプリントする。
次の例は、N
コマンドやD
コマンドの動作を示しています。
$ seq 6 | sed -n 'N;l;D' 1\n2$ 2\n3$ 3\n4$ 4\n5$ 5\n6$
sed
は最初の1行をパターンスペースに読み込み(すなわちパターンスペースの内容は‘1’)
N
コマンドは(最初の1行をパターンスペースに読み込む時に取り除いた)改行を追加し、更に次の1行をパターンスペースに読み込みます( すなわちパターンスペースの内容は‘1’, ‘\n’, ‘2’ となる)。
l
(小文字のエル)コマンドはパターンスペースの内容を非表示文字等含めて目に見える形でプリントします(削除はしない)。
D
コマンドはパターンスペースの内容を最初の改行まで(その改行含む)削除し、そしてD
パターンスペースの削除をスキップして次のサイクルを開始します (よって、次のサイクルは(2行目の)2’だけ状態から始まる)。
N
コマンドは同様に削除してあった改行追加し入力行をパターンスペースに追加します(すなわち、‘2’, ‘\n’, ‘3’).
(行ごとではなく)段落などのテキストブロックを処理するには以下のような構文を使用するのが一般的です。
sed '/./{H;$!d} ; x ; s/REGEXP/REPLACEMENT/'
/./{H;$!d}
は空行以外の全ての行に対して実行され、(パターンスペース内の) 現在行をホールドスペースに追加します。$!
によって最終行以外ではパターンスペースの内容の全削除と残りの処理をスキップして次のサイクルを開始します。
x
と s
は空行(すなわち段落の区切り)に対してだけ実行されます。x
コマンドはパターンスペースの内容をホールドスペースの内容(累積した行)で置き換えます。s///
は(改行を含んだ)段落内の全てのテキストに対して実行されます 。
以下の例はこのテクニックのデモです。
$ cat input.txt a a a aa aaa aaaa aaaa aa aaaa aaa aaa bbbb bbb bbb bb bb bbb bb bbbbbbbb bbb ccc ccc cccc cccc ccccc c cc cc cc cc $ sed '/./{H;$!d} ; x ; s/^/\nSTART-->/ ; s/$/\n<--END/' input.txt START--> a a a aa aaa aaaa aaaa aa aaaa aaa aaa <--END START--> bbbb bbb bbb bb bb bbb bb bbbbbbbb bbb <--END START--> ccc ccc cccc cccc ccccc c cc cc cc cc <--END
注釈付きの例については、「複数行にわたるテキスト検索」や「行の長さを揃える」参照。
分岐コマンドのb
やt
やT
はsed
プログラムの流れを変える事を可能にします。
デフォルトではsed
は入力行をパターンスペースに読み込み、それから全てのコマンドを順番に実行します。アドレス指定の無いコマンドは全ての行で実行されます。アドレス指定のあるコマンドはアドレス指定に合致する行に対してだけ実行されます。「実行サイクル」と「アドレス概要」参照。
sed
には典型的なif/then
構文がありません。代わりにいくつかのコマンドは、条件文や、制御の流れを変えるために使えます。
d
パターンスペースの内容を全削除し、このコマンド以降のスクリプトの実行をスキップしてパターンスペースの内容をプリントせずに次のサイクルを開始する。
D
パターンスペースの最初の改行まで(その改行含む)削除し、このコマンド以降のスクリプトの実行をスキップしてパターンスペースの内容をプリントせずに次のサイクルを開始する。
[addr]X
[addr]{ X ; X ; X }
/regexp/X
/regexp/{ X ; X ; X }
アドレスや正規表現はif/then
構文として使える。「if パターンスペースの内容が[addr] にマッチ then コマンド実行」。例:/^#/d
は、「if パターンスペースが正規表現^#
(行頭が#)にマッチする then d
コマンド実行(当該行を削除し、プリントせず、次のサイクルを開始する)」。
b
無条件分岐(指定のラベルへジャンプ。当該スクリプトの中で前にジャンプしてループを構成するのに使ったり、条件と組み合わせてelse部分をスキップするのに使える。あくまで当該スクリプトの中でジャンプするだけで当該サイクルを終了したり次のサイクルを開始することはない)。分岐はアドレスと組み合わせると、条件に適合した時だけジャンプさせることができます。
t
条件分岐。最後に読み込まれた入力行のs///
コマンドが成功し、かつ、まだ他の条件分岐が実行されてない場合に分岐実行する(指定のラベルへジャンプ)。
T
t
コマンドと逆に、最後に読み込まれた入力行の's'コマンドが失敗した場合に分岐する。
以下の2つのsed
プログラムは等価です。最初の(わざとらしい)例は‘1’を含む行の時にs///
をスキップするためにb
コマンドを使っています。2番目の例ではアドレスの否定( '!')を使用して、目的の行のみs///
コマンドを実行します。いずれにせよy///
コマンドは全ての行で実行されます。
$ printf '%s\n' a1 a2 a3 | sed -E '/1/bx ; s/a/z/ ; :x ; y/123/456/' a4 z5 z6 $ printf '%s\n' a1 a2 a3 | sed -E '/1/!s/a/z/ ; y/123/456/' a4 z5 z6
b
コマンドやt
コマンドやT
コマンドは、コマンドに続くジャンプ先ラベルが必要です(通常はアルファベット1文字)。飛び先ラベルはコロン(:)に続く1文字またはそれ以上の文字列として定義します(例えば‘:x’)。なお、ブランチコマンドでラベルを省略すると次のサイクルを開始します。ブランチコマンドによるジャンプと次のサイクルの開始との違いに注意して下さい。次のサイクルの開始時はsed
はまずパターンスペースの内容をプリントして次に入力ストリームから1行パターンスペースに読み込みます。一方ラベルへのジャンプは(それがたとえプログラムの先頭へジャンプしたとしても)、パターンスペースの内容はプリントされませんし入力ストリームから次の1行を読み込む事もありません。
以下のプログラム自身は何もしません。(このプログラム唯一のコマンドである)b
コマンドは飛び先ラベルが書かれていないので次のサイクルを開始します。よってどのサイクルでもパターンスペースの内容がプリントされて入力ストリームから次の入力行を読み取ります。
$ seq 3 | sed b 1 2 3
次のサンプルは無限ループに陥ります。一切プリントすることなく終了もしません(訳注:CTRL+C等で強制停止させる)。b
コマンドは‘x’ラベルにジャンプし、そして永遠に最初のサイクルにとどまり決して新しいサイクルが始まることはありません。
$ seq 3 | sed ':x ; bx' # 上記コマンド実行には gnu sed が必要です。 # (ラベル定義のあとで改行しないでいいのは gnu 拡張です。)gnu sed 以外でも動くようにするには以下のようにします。 # sed -e ':x' -e bx
分岐はしばしばn
コマンドやN
コマンドと一緒に使われます。両コマンドは次のサイクルを開始することなしに入力ストリームから1行入力行をパターンスペースに入れます。 n
コマンドはパターンスペースの内容をプリントして、そしてパターンスペースの内容を全削除してから入力ストリームから次の1行を読み込みます。一方、 N
コマンドはひたすら改行と次の入力行をパターンスペースに追加していきます。
ここで以下の2つの例について考えてみます。
$ seq 3 | sed ':x ; n ; bx' 1 2 3 $ seq 3 | sed ':x ; N ; bx' 1 2 3
n
コマンドは最初にパターンスペースの内容をプリントし、それからパターンスペースの内容を全削除し、それから次の入力行を読み込みます。入力ストリームからこれ以上入力行が読み込めなくなるとn
コマンドはsedを終了させます。
N
コマンドはひたすら次の行を(改行付きで)パターンスペースに追加していきます。入力ストリームからこれ以上入力行が読み込めなくなるまで入力行をパターンスペースに蓄積します。そして入力ストリームからこれ以上入力行が読み込めなくなるとN
コマンドはsed
を終了させます。プログラムが終了する時はサイクル終了のアクションが実行されます。つまりパターンスペースの内容がプリントされます。
sed
を要求します。なぜならN
のPOSIX標準外の動作を使っているからです。. 「報告されているバグ」の “最終行でのN
コマンド"段落参照。
printf '%s\n' aa bb cc dd | sed ':x ; n ; = ; bx' printf '%s\n' aa bb cc dd | sed ':x ; N ; = ; bx' printf '%s\n' aa bb cc dd | sed ':x ; n ; s/\n/***/ ; bx' printf '%s\n' aa bb cc dd | sed ':x ; N ; s/\n/***/ ; bx'
現実的な分岐の使用例として、通常電子メールメッセージのエンコードに使用される quoted-printable ファイルの場合を考えます。これらのファイルでは、長い行が分割され、行末に単一の「=」文字からなるソフト改行が付けられます。
$ cat jaques.txt All the wor= ld's a stag= e, And all the= men and wo= men merely = players: They have t= heir exits = and their e= ntrances; And one man= in his tim= e plays man= y parts.
次のプログラムは、アドレス一致 '/=$/'を条件として使用します。現在のパターンスペースが '='で終わっている場合は、 N
を使って次の入力行を読み込み、改行が後ろに続くすべての '='文字を置き換え、新しいサイクルを開始せずに無条件でプログラムの先頭に分岐します(b
)。パターンスペースが「=」で終わっていない場合は、デフォルトのアクションが実行されます。パターンスペースがプリントされ、次のサイクルが開始されます。
$ sed ':x ; /=$/ { N ; s/=\n//g ; bx }' jaques.txt All the world's a stage, And all the men and women merely players: They have their exits and their entrances; And one man in his time plays many parts.
お次は、少し異なるアプローチをしたプログラムです。最後の行を除くすべての行で、N
は行をパターンスペースに追加します。それから置換コマンドは、'= 'と、それに続く改行なつづりを空文字列に置き換える事によってソフト改行を取り除きます。もし置換が成功した場合(つまり、パターンスペースに結合すべき行が含まれていた場合)、条件付き分岐コマンド t
は、現在のサイクルを完了させることもなく、新しいサイクルを開始することもなくプログラムの先頭にジャンプします。置換が失敗した場合(ソフト改行がないことを意味する)、 t
コマンドは分岐しません。そして、 P
は最初の改行までパターンスペースの内容を印刷し、 D
は最初の新しい行までパターンスペースの内容を削除します。( N
、 P
、 D
コマンドの詳細については、「複数行テクニック」参照)。
$ sed ':x ; $!N ; s/=\n// ; tx ; P ; D' jaques.txt All the world's a stage, And all the men and women merely players: They have their exits and their entrances; And one man in his time plays many parts.
更に行連結の例を見たい方は「行連結」参照。
ここには、sed
をマスターするのに参考になる、いくつかのスクリプトがあります。
便利な一行野郎: | ||
---|---|---|
• 行連結: | ||
いくつかのエキゾチックな例: | ||
• センタリング: | ||
• 数字のインクリメント: | ||
• ファイル名を小文字にリネーム: | ||
• bash環境変数をプリント: | ||
• 行内の文字列を逆順にする。: | ||
• 複数行に渡るテキスト検索: | ||
• 行の長さを揃える: | ||
標準のユーティリティをエミュレート: | ||
• tac: | ファイルの各行の内容を逆順にする。 | |
• cat -n: | 各行に行番号を付ける | |
• cat -b: | 空行以外に行番号を付ける | |
• wc -c: | 文字数を数える | |
• wc -w: | 単語数を数える | |
• wc -l: | 行数を数える | |
• head: | 最初の数行をプリントする。 | |
• tail: | 最後の数行をプリントする。 | |
• uniq: | 重複行を取り除く | |
• uniq -d: | 入力から重複した行をプリントする。 | |
• uniq -u: | 全ての重複した行を削除する。 | |
• cat -s: | 連続した空行の出力を行わない |
この節では、 N
、 D
、 P
コマンドを使用して複数行を処理し、b
と t
コマンドを使用して分岐します。「複数行テクニック」、「分岐とフロー制御」参照。
指定行を連結する(例:2行目と3行目を結合する必要がある場合)。
$ cat lines.txt hello hel lo hello $ sed '2{N;s/\n//;}' lines.txt hello hello hello
バックスラッシュで継続された行を連結する。
$ cat 1.txt this \ is \ a \ long \ line and another \ line $ sed -e ':x /\\$/ { N; s/\\\n//g ; bx }' 1.txt this is a long line and another line #TODO: The above requires gnu sed. # non-gnu seds need newlines after ':' and 'b'
空白で始まる行(例:SMTPヘッダ)を結合します。
$ cat 2.txt Subject: Hello World Content-Type: multipart/alternative; boundary=94eb2c190cc6370f06054535da6a Date: Tue, 3 Jan 2017 19:41:16 +0000 (GMT) Authentication-Results: mx.gnu.org; dkim=pass header.i=@gnu.org; spf=pass Message-ID: <abcdef@gnu.org> From: John Doe <jdoe@gnu.org> To: Jane Smith <jsmith@gnu.org> $ sed -E ':a ; $!N ; s/\n\s+/ / ; ta ; P ; D' 2.txt Subject: Hello World Content-Type: multipart/alternative; boundary=94eb2c190cc6370f06054535da6a Date: Tue, 3 Jan 2017 19:41:16 +0000 (GMT) Authentication-Results: mx.gnu.org; dkim=pass header.i=@gnu.org; spf=pass Message-ID: <abcdef@gnu.org> From: John Doe <jdoe@gnu.org> To: Jane Smith <jsmith@gnu.org> # A portable (non-gnu) variation: # sed -e :a -e '$!N;s/\n */ /;ta' -e 'P;D'
このスクリプトは全ての行を80カラム幅でセンタリングします。幅を変更するには、'\{…\}
'の数を置き換え、追加スペースの数も変更する必要があります。
正規表現内の分かれた部分を一致させるためにbufferコマンドを使用する方法に注意してください。これは一般的なテクニックです。
#!/usr/bin/sed -f
# ホールドスペースに80個の空白を置く 1 { x s/^$/ / s/^.*$/&&&&&&&&/ x }
# 先行する空白と末尾の空白を削除
y/TAB/ /
s/^ *//
s/ *$//
# 行の後ろに改行と80個の空白を追加する G
# 最初の81文字(80 + a newline)のみを残し以降を削除 s/^\(.\{81\}\).*$/\1/
# \2 は残りの空白の半分にマッチし、それを先頭に移動する。 s/^\(.*\)\n\(.*\)\2/\2\1/
このスクリプトは、 sed
で算術演算を実行する方法を示すいくつかのうちの1つです。これは確かに可能ですが、手動で行う必要があります。9
数字を1つ増やすには、最後の数字に1を足して次の数字に置き換えます。例外が1つあります。数字が9のときは、9がなくなるまで、前の数字も増分する必要があります。
Bruno Haibleによるこの解法は、単一のバッファを使用するため、非常に巧妙でスマートです。 この制限がない場合は、行番号をつけるで使用されるアルゴリズムのほうが速くなります。末尾の9文字をアンダースコア'_'に置き換えて、そして最後の数字を増やすために複数の s
コマンドを使用し、そしてアンダースコア'_'をゼロ'0'に置き換えます。
#!/usr/bin/sed -f /[^0-9]/ d
# 末尾の9文字をすべて'_'に置き換えます # (数字以外の任意の文字を使用できます) :d s/9\(_*\)$/_\1/ td
# 最後の数字のみ増やします。最初の行は、数字を追加する必要がある場合、 # 最上位桁の1を追加します。
s/^\(_*\)$/1\1/; tn s/8\(_*\)$/9\1/; tn s/7\(_*\)$/8\1/; tn s/6\(_*\)$/7\1/; tn s/5\(_*\)$/6\1/; tn s/4\(_*\)$/5\1/; tn s/3\(_*\)$/4\1/; tn s/2\(_*\)$/3\1/; tn s/1\(_*\)$/2\1/; tn s/0\(_*\)$/1\1/; tn
:n y/_/0/
これは sed
のかなり奇妙な使い方です。テキストを変換し、それをシェルコマンドに変換してから、単にそれらをシェルに送ります。だがご心配なく。 sed
を使用するともっとひどいハックだってあります。私は date
の出力を bc
プログラムに変換するスクリプトを見たことがあります。
この本体は sed
スクリプトで、名前を下から上に(またはその逆に)再マップし、再マップされた名前が元の名前と同じであるかどうかを調べます。スクリプトがシェル変数と適切な引用符を使用してどのようにパラメータ化されるかに注意してください。
#!/bin/sh # rename files to lower/upper case... # # usage: # move-to-lower * # move-to-upper * # or # move-to-lower -R . # move-to-upper -R . #
help() { cat << eof Usage: $0 [-n] [-r] [-h] files...
-n do nothing, only see what would be done -R recursive (use find) -h this message files files to remap to lower case
例: $0 -n * (see if everything is ok, then...) $0 *
$0 -R .
eof }
apply_cmd='sh' finder='echo "$@" | tr " " "\n"' files_only=
while : do case "$1" in -n) apply_cmd='cat' ;; -R) finder='find "$@" -type f';; -h) help ; exit 1 ;; *) break ;; esac shift done
if [ -z "$1" ]; then echo Usage: $0 [-h] [-n] [-r] files... exit 1 fi
LOWER='abcdefghijklmnopqrstuvwxyz' UPPER='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
case `basename $0` in *upper*) TO=$UPPER; FROM=$LOWER ;; *) FROM=$UPPER; TO=$LOWER ;; esac
eval $finder | sed -n '
# remove all trailing slashes s/\/*$//
# add ./ if there is no path, only a filename /\//!s/^/.\//
# save path+filename h
# remove path s/.*\///
# do conversion only on filename y/'$FROM'/'$TO'/
# now line contains original path+file, while # hold space contains the new filename x
# add converted file name to line, which now contains # path/file-name\nconverted-file-name G
# check if converted file name is equal to original file name, # if it is, do not print anything /^.*\/\(.*\)\n\1/b
# escape special characters for the shell s/["$`\\]/\\&/g
# now, transform path/fromfile\n, into # mv path/fromfile path/tofile and print it s/^\(.*\/\)\(.*\)\n\(.*\)$/mv "\1\2" "\1\3"/p
' | $apply_cmd
bash
の環境変数をプリントこのスクリプトは、Bourne-shellの set
コマンドの出力からシェル関数の定義を取り除きます。
#!/bin/sh
set | sed -n ' :x
# if no occurrence of ‘=()’ print and load next line /=()/!{ p; b; } / () $/!{ p; b; }
# これがFOO = "()"のようなvarである場合に備えて、 # functionsセクションの開始で行を保存する h
# 次の行に波括弧'{'がある場合、 # 関数の後には何も入っていないので終了します。 n /^{/ q
# print the old line x; p
# work on the new line now x; bx '
このスクリプトは、行内の文字の位置を逆にするために使用できます。この手法は一度に2文字ずつ移動するため、より直感的な実装よりも高速です。
ラベルの定義の前にある tx
コマンドに注意してください。これは t
コマンドによってテストされるフラグをリセットするためにしばしば必要とされます。
想像力豊かな読者はこのスクリプトの用途を見つけるでしょう。例として、 banner
の出力を元に戻すことが挙げられます。10
#!/usr/bin/sed -f /../!b
# 行を反転する。ふたつの改行の間に行を埋め込み始める s/^.*$/\ &\ /
# 最初の文字を最後に移動させる。正規表現は、マーカーの間に # 0個または1個の文字が入るまでマッチします。 tx :x s/\(\n.\)\(.*\)\(.\n\)/\3\2\1/ tx
# 改行マーカーを削除 s/\n//g
この節では、 N
および D
コマンドを使用して、複数行にわたる連続した単語を検索します。「複数行テクニック」参照
これらの例では、文書内で同じ単語が2回出現することを検出します。
二重の単語を一行内で探すのは、GNU grep
を使えば簡単で、それはGNU sed
でも同じです。
$ cat two-cities-dup1.txt It was the best of times, it was the worst of times, it was the the age of wisdom, it was the age of foolishness, $ grep -E '\b(\w+)\s+\1\b' two-cities-dup1.txt it was the the age of wisdom, $ grep -n -E '\b(\w+)\s+\1\b' two-cities-dup1.txt 3:it was the the age of wisdom, $ sed -En '/\b(\w+)\s+\1\b/p' two-cities-dup1.txt it was the the age of wisdom, $ sed -En '/\b(\w+)\s+\1\b/{=;p}' two-cities-dup1.txt 3 it was the the age of wisdom,
二重の単語が2行にまたがる場合、grep
と sed
は行ごとに動作するので、上記の正規表現はそれらを見つけられません。
N
やD
コマンドを使用することで、sed
は複数行に正規表現を適用できます(つまり、正規表現はパターンスペースに格納した複数行に作用します)。
$ cat two-cities-dup2.txt It was the best of times, it was the worst of times, it was the the age of wisdom, it was the age of foolishness, $ sed -En '{N; /\b(\w+)\s+\1\b/{=;p} ; D}' two-cities-dup2.txt 3 worst of times, it was the the age of wisdom,
N
コマンドは、次の行をパターンスペースに追加します(したがって、すべてのサイクルで連続した2行が含まれるようにします)。
p
でプリントされます。 -n オプションのため、デフォルトでは行はプリントされません。
D
は最初の行をパターンスペースから削除(つまり最初の改行まで削除)し、次のサイクルに備えます。
tr -s
や uniq
を使った別の解法については、https://gnu.org/s/coreutils/manual/html_node/Squeezing-and-deleting.htmlのGNU coreutils
マニュアルをご覧ください。
この節では、N
および D
コマンドを使用して複数行にわたる連続した単語を検索し、b
コマンドを使用して分岐します。「複数行テクニック」、「分岐とフロー制御」参照。
この(多少工夫された)例は、以下の入力ファイルのテキストのフォーマッティングと行の折り返しを扱います。
$ cat two-cities-mix.txt It was the best of times, it was the worst of times, it was the age of wisdom, it was the age of foolishness,
次のプログラムは40文字で行を折り返します。
$ cat wrap40.sed # outer loop :x # 改行と続く次の入力行をパターンスペースに追加 N # パターンスペース内の全ての改行を削除 s/\n/ /g # Inner loop :y # 最初の40文字の後ろに改行を挿入 s/(.{40,40})/\1\n/ # もしパターンスペースに改行があれば # (すなわち、前の置換が改行を追加していれば) /\n/ { # パターンスペースには改行があり - # 最初の改行までの内容をプリントします。 P # 印刷した文字達と最初の改行を削除します s/.*\n// # ラベル'y'へ無条件ジャンプ - 内部ループの繰り返し by } # パターンスペースに改行が無い - ラベル'x'へ無条件ジャンプ(外部ループ) # そして次の入力行を読み込む bx
以下は折り曲げられた出力です。
$ sed -E -f wrap40.sed two-cities-mix.txt It was the best of times, it was the wor st of times, it was the age of wisdom, i t was the age of foolishness,
これは、さまざまなUnixコマンドをエミュレートする、まったく役に立たない(それでも面白い)スクリプトのシリーズの始まりです。これは特に tac
の動作に似ています。
GNU sed
以外の実装では、このスクリプトはすぐに内部バッファをオーバーフローさせるかもしれません。
#!/usr/bin/sed -nf #入力のすべての行を反転します。つまり、最初の行が最後になりました...
# 2行目以降、バッファ(前の行をすべて含む)は # 現在の行に「追加」されるので、順序は逆になります。 1!G
# 最終行に居るなら、作業終了したのです -- 全てをプリントします。 $ p
# すべてを再びバッファに保存する h
このスクリプトは‘cat -n’を置き換えます。 実際、GNU cat
とまったく同じフォーマットで出力します。
もちろん、これはまったく役に立ちません。2つの理由があります。1つは誰かが既にC言語で書いためであり、2つ目は、次のBourneシェルスクリプトが同じ目的で使用でき、はるかに高速だからです。
#!/bin/sh sed -e "=" $@ | sed -e ' s/^/ / N s/^ *\(......\)\n/\1 / '
sed
を使用して行番号を印刷し、次にN
を使用して2行ずつグループ化します。もちろん、このスクリプトは以下に提示されているものほど多くは教えていません。
インクリメントに使用されるアルゴリズムは両方のバッファーを使用するので、行はできるだけ早く印刷されてから廃棄されます。数字は分割されているので、変更された数字はバッファに入り、変更されていない数字はもう一方に入ります。 変更された桁は(y
コマンドを使用して)単一のステップで変更されます。. 次の行の行番号が構成され、ホールドスペースに格納されて、次の反復で使用されます。
#!/usr/bin/sed -nf
# 最初のラインでポンプを吸い込む x /^$/ s/^.*$/1/
# パターンの前に正しい行番号を追加 G h
# Format it and print it s/^/ / s/^ *\(......\)\n/\1 /p
# ホールドスペースから行番号を取得 # 次の行に数字を追加する場合0(ゼロ)を追加 g s/\n.*$// /^9*$/ s/^/0/
# x によって、変更/未変更の数字を分ける s/.9*$/x&/
# 変更した数字をホールドスペース内で保持 h s/^.*x// y/0123456789/1234567890/ x
# 未変更の数字をパターンスペース内で保持 s/x.*$//
# 新しい番号を作成し、Gが暗黙のうちに追加した改行を削除する G s/\n// h
' cat -b 'をエミュレートすることは、 ' cat -n 'とほぼ同じです。どの行に番号を付け、どの行に番号を付けないかを選択するだけです。
このスクリプトと前のスクリプトに共通する部分は、 sed
スクリプトを正しくコメントすることがどれほど重要かを敢えて示すためにコメント化されていません...
#!/usr/bin/sed -nf
/^$/ { p b }
# Same as cat -n from now x /^$/ s/^.*$/1/ G h s/^/ / s/^ *\(......\)\n/\1 /p x s/\n.*$// /^9*$/ s/^/0/ s/.9*$/x&/ h s/^.*x// y/0123456789/1234567890/ x s/x.*$// G s/\n// h
このスクリプトは sed
を使って算術演算を行う別の方法を示しています。この場合、私たちはおそらくもっと大きな数を追加しなければならないので、その実装を連続的なインクリメントで行うのはうまくいきそうにありません(そしておそらくこのスクリプトよりもさらに複雑になります)。
この、別のアプローチは、数字を文字にマッピングすることです。これは、 sed
で実装されたそろばんのようなものです。' a 'は1の位の数、 ' b 'は10の位の数などです。現在の行の文字数を1の位の数として追加してから、桁上がり(キャリー)を伝播します。 数十、数百などに。
通常どおり、積算合計はホールドスペースに保持されます。
最終行で、そろばん形式を10進数に戻します。多様性のために、これは80個のs
コマンドではなくループで行われます。最初に1の位を変換し、数字から‘a’の並びを削除します。 それから、数十の位が‘a’の並びになるように文字をローテートさせ、文字がなくなるまで続けます。
#!/usr/bin/sed -nf
# Add n+1 a's to hold space (+1 is for the newline) s/./a/g H x s/\n/a/
# Do the carry. t's や b's は不要ですが... # それらによってスピードアップが図れます t a : a; s/aaaaaaaaaa/b/g; t b; b done : b; s/bbbbbbbbbb/c/g; t c; b done : c; s/cccccccccc/d/g; t d; b done : d; s/dddddddddd/e/g; t e; b done : e; s/eeeeeeeeee/f/g; t f; b done : f; s/ffffffffff/g/g; t g; b done : g; s/gggggggggg/h/g; t h; b done : h; s/hhhhhhhhhh//g
: done $!{ h b }
# 最終行で数字に戻します。
: loop /a/!s/[b-h]*/&0/ s/aaaaaaaaa/9/ s/aaaaaaaa/8/ s/aaaaaaa/7/ s/aaaaaa/6/ s/aaaaa/5/ s/aaaa/4/ s/aaa/3/ s/aa/2/ s/a/1/
: next y/bcdefgh/abcdefg/ /[a-h]/ b loop p
このスクリプトは、行の各単語が1つの ‘a’に変換されると、前のスクリプトとほぼ同じになります(前のスクリプトでは、各文字が ‘a’に変更されました)。
本物の wc
プログラムが ' wc -c 'のために最適化されたループを持っているのは興味深いですが、それらは文字よりもむしろ単語を数える方がはるかに遅いです。代わりに、このスクリプトのボトルネックは算術演算です。したがって、単語数を数えるほうが速くなります(小さい数を管理する必要はあります)。
繰り返しますが、前のと共通部分は sed
スクリプトにコメントすることの重要性を示すために敢えてコメントしていません
#!/usr/bin/sed -nf
# Convert words to a's s/[ TAB][ TAB]*/ /g s/^/ / s/ [^ ][^ ]*/a /g s/ //g
# Append them to hold space H x s/\n//
# これ以降はwc -cと同じです。 /aaaaaaaaaa/!bx; s/aaaaaaaaaa/b/g /bbbbbbbbbb/!bx; s/bbbbbbbbbb/c/g /cccccccccc/!bx; s/cccccccccc/d/g /dddddddddd/!bx; s/dddddddddd/e/g /eeeeeeeeee/!bx; s/eeeeeeeeee/f/g /ffffffffff/!bx; s/ffffffffff/g/g /gggggggggg/!bx; s/gggggggggg/h/g s/hhhhhhhhhh//g :x $!{ h; b; } :y /a/!s/[b-h]*/&0/ s/aaaaaaaaa/9/ s/aaaaaaaa/8/ s/aaaaaaa/7/ s/aaaaaa/6/ s/aaaaa/5/ s/aaaa/4/ s/aaa/3/ s/aa/2/ s/a/1/ y/bcdefgh/abcdefg/ /[a-h]/ by p
sed
は私たちに無料で「 wc -l 」機能を提供してくれるので、今回はわざわざ変なことはしていません。見よ!
#!/usr/bin/sed -nf $=
このスクリプトはおそらく最も簡単で便利な sed
スクリプトです。表示される行数は q
コマンドの直前までです。
#!/usr/bin/sed -f 10q
最初の行ではなく最後の n 行を印刷するのは、より複雑だけども可能ではあります。nは、スクリプト2行目の'!'(bang文字)の前に書いてあります(。
このスクリプトは tac
スクリプトと似ていますが、最終的な出力をホールドスペースに保持し、最後に出力するという点です。
#!/usr/bin/sed -nf
1!{; H; g; } 1,10 !s/[^\n]*\n// $p h
主に、スクリプトは10行のウィンドウを保持し、行を追加して最も古い行を削除することによってそれをスライドさせます(2行目の置換コマンドは D
コマンドのように機能しますがループを再開しません)。
「スライディングウィンドウ」技術は、効率的で複雑な sed
スクリプトを書くための非常に強力な方法です。なぜなら、手動で実装した場合、 P
のようなコマンドは多くの作業を必要とするからです。
N
、P
、D
コマンドに基づいたテクニックをこの章の残りの部分で十分に紹介するために、ここでは「スライディングウィンドウ」を使ったtail
を実装します。
これは複雑に見えますが、実際の作業はさっきのスクリプトと同じです。ただし、適切な行数を入力した後は、行間の状態を維持するためにホールドスペースを使用せず、代わりにN
とD
を使用して一行でパターンスペースをスライドします。
#!/usr/bin/sed -f
1h 2,10 {; H; g; } $q 1,9d N D
最初の10行の入力後、1行目、2行目、4行目が非アクティブになっていることに注意してください。その後、スクリプトはすべて、入力の最後の行で終了し、次の入力行をパターンスペースに追加して、最初の行を削除します。
これは N
、 P
、および D
コマンドを使用する技術の例の中で、おそらく習得が最も困難です。
#!/usr/bin/sed -f h
:b # On the last line, print and exit $b N /^\(.*\)\n\1$/ { # The two lines are identical. 効果を元に戻す - # the n command. g bb }
# If the N
command had added the last line, print and exit
$b
# The lines are different; print the first and go # back working on the second. P D
ご覧のとおり、 P
と D
を使用して2行のウィンドウを管理しています。このテクニックは、高度な sed
スクリプトでよく使われます。
このスクリプトは、 ' uniq -d 'のように、重複した行だけを出力します。
#!/usr/bin/sed -nf
$b N /^\(.*\)\n\1$/ { # 重複行の最初の行を印刷する s/.*\n// p
# Loop until we get a different line :b $b N /^\(.*\)\n\1$/ { s/.*\n// bb } }
# 最後の行の後に重複を続けることはできません $b
# 別のものを見つけました。パターンスペース内にほっとく # そしてトップに戻り、その重複をハンティングする。 D
このスクリプトは ' uniq -u 'のようにユニークな行だけを印刷します。
#!/usr/bin/sed -f
# 重複行を検索します---それまでは、見つけたものを印刷します。 $b N /^\(.*\)\n\1$/ !{ P D }
:c # Got two equal lines in pattern space. # ファイルの終わりで、単に終了します $d
# そうでなければ、私たちは N
で行を読み続けます。
# find a different one
s/.*\n//
N
/^\(.*\)\n\1$/ {
bc
}
# 最後の重複行を削除し # トップへ戻る D
最後の例として、これは複雑さとスピードを増す3つのスクリプトです。これらは「 cat -s 」と同じ機能を実装しています。
最初と最後に既に空行が1行以上会った場合、それぞれ空行1行だけは残さなければなりません。
#!/usr/bin/sed -f
# 空行だったら次の行を連結する # Note there is a star in the regexp :x /^\n*$/ { N bx }
# 今、連続する'\n'を1つにする。無い時は何もしない # s/^\(\n\)*/\1/ と同等 s/\n*/\ /
これはもう少し複雑で、最初に空の行をすべて削除します。最後に1行の空白行があったとしても、それは残ります。
#!/usr/bin/sed -f
# 先行する全ての空行を削除 1,/^./{ /./!d }
# 空行であればそれを削除し、 # それに続く空行も同じです。 :x /./!{ N s/^\n$// tx }
これは先導する空行達と後続する空行達を削除します。それも最速です。ループは n
と b
で全部処理され、各行末で次のサイクルに移る通常の自動的な動作が全くありません。
#!/usr/bin/sed -nf
# 全ての(先導する)空白を削除 /./!d
# ここに居る、すなわち空でない :x # それをプリント p # 次の入力行を得る n # 文字(列)があった?なら再びそれをプリントして, etc... /./bx
# 文字が無かった。つまり空行を得た :z # 次を読み込んで、ここが最終行の場合は、 # 後続の空行達は書き込みません n # 空かな?ならばそれを無視、そして次を取得... # 全ての空行を削除 /./!bz
# 全ての空行は削除/無視した。全く無くなった。しかし我々は空にしたい訳じゃない # 我々は圧縮(squeeze)したいのだ。よって露骨に空行を挿入する。 i\
bx
sed
の制限と、GNU sed
で撤廃された制限移植可能な sed
スクリプトを書きたいという人は、(パターンスペースとホールドスペースのための)行の長さを4000バイト以下に制限する実装があることに注意してください。 POSIX 規格では、準拠した sed
の実装で少なくとも8192バイトの行の長さをサポートすることを規定しています。GNU sed
には行の長さに関する制限は組み込まれていません。 より多くの(仮想)メモリをmalloc()
できれば、好きなだけ行を注ぎ込んだり構築したりすることができます。
ただし、再帰はサブパターンと不定の繰り返しを処理するために使用されます。これは、利用可能なスタックスペースが、特定のパターンで処理できるバッファのサイズを制限する可能性があることを意味します。
sed
を習得するためのこの文書以外の資料GNU sed
の最新情報についてはこちら。https://www.gnu.org/software/sed/
一般的な質問や提案の送り先: sed-devel@gnu.org(訳注:このMLに参加するには https://lists.gnu.org/mailman/listinfo/sed-devel のページ従って操作すると自分宛てに確認メールが届くのでそれに従って下さい)。過去の議論のメーリングリストアーカイブはこちら。https://lists.gnu.org/archive/html/sed-devel/.
以下、 sed
(GNU sed
とその他のバリエーションの両方)に関する資料ですこれらはGNU sed
開発者によって保守されていないことに注意してください。
$HOME
: http://sed.sf.net
sed-users
メーリングリストはSven Guckesが維持しています。 http://groups.yahoo.com/group/sed-users/ (注意これは GNU sed
メーリングリストではありません)。
バグ報告はこちらへ(もちろん英語で) bug-sed@gnu.org. また、可能なかぎり報告本文に‘sed --version’の出力を含めて下さい。
以下のようなバグレポートは送らないでください。
while building frobme-1.3.4
$ configure
error→ sed: file sedscr line 1: Unknown option to 's'
もしGNU sed
があなたのお気に入りのパッケージを設定しないならば、特定の問題を識別して、独立したテストケースを作るために数分余分に時間をかけてください。Cコンパイラのような他のプログラムとは異なり、 sed
のためのそのようなテストケースを作ることは非常に簡単です。
独立したテストケースには、テストを実行するために必要なすべてのデータと、問題を引き起こす sed
の特定の呼び出しを含めます。独立したテストケースは短いほどいいです。テストケースの sed
から「frobme-1.3.4を設定してみてください」というようなものを削除してはいけません。もちろん、それは基礎的なバグを探すのには十分な情報ですが、それは非常に役立つ技術情報というわけではありません。
なお以下は俗に言う「既知のバグ」であって、再度再度報告して頂くようなバグではありません。
N
コマンドの振る舞い sed
のほとんどのバージョンは、ファイルの最後の行で N
コマンドが発行されると、何も表示せずに終了します。 -n
コマンドラインオプションが指定されていない限り、GNU sed
は終了する前にパターンスペースを表示します。この選択は仕様によるものです。
デフォルトの動作(GNU拡張、非POSIX準拠):
$ seq 3 | sed N 1 2 3
POSIX準拠の動作を強制:
$ seq 3 | sed --posix N 1 2
たとえば、次の振る舞い
sed N foo bar
は、fooの行数が偶数か奇数かに依存します。12. また、パターンマッチの後に続く数行を読むためのスクリプトを書くとき、伝統的な実装の sed
はあなたに次のようなものを書くことを強いるでしょう。
/foo/{ $!N; $!N; $!N; $!N; $!N; $!N; $!N; $!N; $!N }
GNU sedでは代わりに次のように書ける
/foo/{ N;N;N;N;N;N;N;N;N; }
いずれにせよ、最も簡単な回避策は、従来の振る舞いに依存するスクリプトで $ d; N
を使うか、または POSIXLY_CORRECT
変数を空でない値に設定することです。
sed
は POSIX 基本正規表現文法を使います。規格によると、いくつかのエスケープシーケンスの意味はこの文法では定義されていません。 sed
の場合、\|
、\+
、 \?
、\`
、\'
、\<
、 \>
、\b
、\B
、\w
、 \W
です。
POSIX 基本正規表現を使用するすべてのGNUプログラムと同様に、 sed
はこれらのエスケープシーケンスを特殊文字として解釈します。x\+
は、1つまたはそれ以上現れる‘x’にマッチします。. abc\|def
は‘abc’または‘def’のいずれかにマッチします。
これらの文法が問題を引き起こすのは他のsed
の為に書かれたスクリプトを実行するときです。いくつかのsed
プログラムは \|
や \+
は 文字|
や +
するものだと決めつけています。このようなスクリプトは、GNU sed
のような現代的な sed
の実装で使用する場合には、誤ったバックスラッシュを削除して修正する必要があります。
一方、スクリプトによっては s|abc\|def||g を使用して、abc
またはdef
のどちらかの出現を削除します。これは sed
4.0.xまでは機能しましたが、新しいバージョンではabc|def
という文字列を削除するものとして解釈されます。POSIXによれば、これもまた未定義の振る舞いであり、この解釈は間違いなくより健全(robust)です。例えば、より古いsed
では、スラッシュをエスケープする一般的なケースでは正規表現照合プログラムが \/
を /
として解析する必要がありました。 新しい振る舞いはこれを避けています、そしてこれは良いことです。正規表現マッチ機構は部分的にしか私たちの管理下にないからです。
さらに、このバージョンの sed
では、スクリプトに印刷不可能な文字を挿入するための複数のエスケープ文字(そのうちのいくつかは複数文字)がサポートされています(\a
, \c
, \d
, \o
, \r
, \t
, \v
, \x
)。これらも他の sed
用に書かれたスクリプトで同様の問題を引き起こす可能性があります。
要するに、 ' sed -i 'を指定すると、読み取り専用ファイルの内容を削除できます。一般に、 -i オプション(起動を参照)を使用すると、保護されているファイルを破壊できます。これはバグではなく、むしろUnixファイルシステムがどのように機能するかの結果です。
ファイルに対する許可は、そのファイル内のデータに何が起こり得るかを示し、ディレクトリに対する許可は、そのディレクトリ内のファイルのリストに何が起こりうるかを示します。' sed -i 'はすでにディスク上にあるファイルを書き込むために開くことはありません。そうではなく、一時的なファイルに対して操作し最終的に元の名前に変更されます。ファイルの名前を変更または削除すると、実際にはディレクトリの内容が変更されるため、操作はファイルの権限ではなくディレクトリの権限に依存します。 同じ理由で、 sed
は読み取り専用ディレクトリの書き込み可能なファイルに '-i'を使用させず、 '-i'がそのようなファイルに使用されるとハードリンクまたはシンボリックリンクを解除します。
0a
が動作しない(エラーになる)問題行番号0の行は存在しません。0は、スクリプトの起動時に 0,/RE/
のようなアドレスをアクティブとして扱うためだけに使用される特殊なアドレスです。 1,/abc/d
と書き、最初の行に ‘abc’という単語が含まれていると、アドレス範囲は少なくとも2行にわたる必要があるため(ファイルの終わりを除く)、その一致は無視されます。 しかし、おそらくあなたが望んでいたのは ‘abc’を含む最初の行まですべての行を削除することです。これは 0,/abc/d
で得られます。
[a-z]
が大文字小文字を区別しない問題あなたはロケールに関する問題に遭遇しています。POSIXは[a-z]
に現在のロケールの照合順序を使用することを強制しています。C言語で言えば strcmp(3)
の代わりにstrcoll(3)
を使用することを意味します。大/小文字を区別しない照合順を持つロケールもあれば、そうでないロケールもあります。
別の問題は、[a-z]
が照合記号を使おうとしていることです。これは、GNU sedを提供しているものをコンパイルするのではなく、GNU libcの正規表現マッチャーを使用して、GNUシステムを使用している場合にのみ発生します。たとえば、デンマーク語のロケールでは、正規表現 ^[a-z]$
は文字列 ‘aa’と一致します。これは、 ‘a’の後で、 ‘b’の前にある単一の照合記号だからです。 ‘ll’はスペイン語のロケールでも‘ij’のオランダ語のロケールでも同じように動作します。
シェルスクリプトでバグを引き起こす可能性があるこれらの問題を回避するには、 LC_COLLATE
および LC_CTYPE
環境変数を ‘C’に設定してください。
s/.*//
がパターンスペースを全削除しない問題これは入力ストリームが不正なマルチバイトつづりを含んでいると発生します。POSIXは、そのようなシーケンスは ‘.’と一致しないことを強制しているので、 ‘s/.*//’はあなたが期待するようにパターンスペースを全削除しないでしょう。実際、ほとんどのマルチバイトロケール(UTF-8ロケールを含む)では、スクリプトの途中でsedのバッファを全削除することはできません。このため、GNU sed
では、(zap用の)zコマンドが拡張機能として提供されています。
シェルスクリプトでバグを引き起こす可能性があるこれらの問題を回避するには、 LC_COLLATE
および LC_CTYPE
環境変数を ‘C’に設定してください。
Copyright © 2000, 2001, 2002, 2007, 2008 Free Software Foundation, Inc. https://fsf.org/ Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed.
The purpose of this License is to make a manual, textbook, or other functional and useful document free in the sense of freedom: to assure everyone the effective freedom to copy and redistribute it, with or without modifying it, either commercially or noncommercially. Secondarily, this License preserves for the author and publisher a way to get credit for their work, while not being considered responsible for modifications made by others.
This License is a kind of “copyleft”, which means that derivative works of the document must themselves be free in the same sense. It complements the GNU General Public License, which is a copyleft license designed for free software.
We have designed this License in order to use it for manuals for free software, because free software needs free documentation: a free program should come with manuals providing the same freedoms that the software does. But this License is not limited to software manuals; it can be used for any textual work, regardless of subject matter or whether it is published as a printed book. We recommend this License principally for works whose purpose is instruction or reference.
This License applies to any manual or other work, in any medium, that contains a notice placed by the copyright holder saying it can be distributed under the terms of this License. Such a notice grants a world-wide, royalty-free license, unlimited in duration, to use that work under the conditions stated herein. The “Document”, below, refers to any such manual or work. Any member of the public is a licensee, and is addressed as “you”. You accept the license if you copy, modify or distribute the work in a way requiring permission under copyright law.
A “Modified Version” of the Document means any work containing the Document or a portion of it, either copied verbatim, or with modifications and/or translated into another language.
A “Secondary Section” is a named appendix or a front-matter section of the Document that deals exclusively with the relationship of the publishers or authors of the Document to the Document’s overall subject (or to related matters) and contains nothing that could fall directly within that overall subject. (Thus, if the Document is in part a textbook of mathematics, a Secondary Section may not explain any mathematics.) The relationship could be a matter of historical connection with the subject or with related matters, or of legal, commercial, philosophical, ethical or political position regarding them.
The “Invariant Sections” are certain Secondary Sections whose titles are designated, as being those of Invariant Sections, in the notice that says that the Document is released under this License. If a section does not fit the above definition of Secondary then it is not allowed to be designated as Invariant. The Document may contain zero Invariant Sections. If the Document does not identify any Invariant Sections then there are none.
The “Cover Texts” are certain short passages of text that are listed, as Front-Cover Texts or Back-Cover Texts, in the notice that says that the Document is released under this License. A Front-Cover Text may be at most 5 words, and a Back-Cover Text may be at most 25 words.
A “Transparent” copy of the Document means a machine-readable copy, represented in a format whose specification is available to the general public, that is suitable for revising the document straightforwardly with generic text editors or (for images composed of pixels) generic paint programs or (for drawings) some widely available drawing editor, and that is suitable for input to text formatters or for automatic translation to a variety of formats suitable for input to text formatters. A copy made in an otherwise Transparent file format whose markup, or absence of markup, has been arranged to thwart or discourage subsequent modification by readers is not Transparent. An image format is not Transparent if used for any substantial amount of text. A copy that is not “Transparent” is called “Opaque”.
Examples of suitable formats for Transparent copies include plain ASCII without markup, Texinfo input format, LaTeX input format, SGML or XML using a publicly available DTD, and standard-conforming simple HTML, PostScript or PDF designed for human modification. Examples of transparent image formats include PNG, XCF and JPG. Opaque formats include proprietary formats that can be read and edited only by proprietary word processors, SGML or XML for which the DTD and/or processing tools are not generally available, and the machine-generated HTML, PostScript or PDF produced by some word processors for output purposes only.
The “Title Page” means, for a printed book, the title page itself, plus such following pages as are needed to hold, legibly, the material this License requires to appear in the title page. For works in formats which do not have any title page as such, “Title Page” means the text near the most prominent appearance of the work’s title, preceding the beginning of the body of the text.
The “publisher” means any person or entity that distributes copies of the Document to the public.
A section “Entitled XYZ” means a named subunit of the Document whose title either is precisely XYZ or contains XYZ in parentheses following text that translates XYZ in another language. (Here XYZ stands for a specific section name mentioned below, such as “Acknowledgements”, “Dedications”, “Endorsements”, or “History”.) To “Preserve the Title” of such a section when you modify the Document means that it remains a section “Entitled XYZ” according to this definition.
The Document may include Warranty Disclaimers next to the notice which states that this License applies to the Document. These Warranty Disclaimers are considered to be included by reference in this License, but only as regards disclaiming warranties: any other implication that these Warranty Disclaimers may have is void and has no effect on the meaning of this License.
You may copy and distribute the Document in any medium, either commercially or noncommercially, provided that this License, the copyright notices, and the license notice saying this License applies to the Document are reproduced in all copies, and that you add no other conditions whatsoever to those of this License. You may not use technical measures to obstruct or control the reading or further copying of the copies you make or distribute. However, you may accept compensation in exchange for copies. If you distribute a large enough number of copies you must also follow the conditions in section 3.
You may also lend copies, under the same conditions stated above, and you may publicly display copies.
If you publish printed copies (or copies in media that commonly have printed covers) of the Document, numbering more than 100, and the Document’s license notice requires Cover Texts, you must enclose the copies in covers that carry, clearly and legibly, all these Cover Texts: Front-Cover Texts on the front cover, and Back-Cover Texts on the back cover. Both covers must also clearly and legibly identify you as the publisher of these copies. The front cover must present the full title with all words of the title equally prominent and visible. You may add other material on the covers in addition. Copying with changes limited to the covers, as long as they preserve the title of the Document and satisfy these conditions, can be treated as verbatim copying in other respects.
If the required texts for either cover are too voluminous to fit legibly, you should put the first ones listed (as many as fit reasonably) on the actual cover, and continue the rest onto adjacent pages.
If you publish or distribute Opaque copies of the Document numbering more than 100, you must either include a machine-readable Transparent copy along with each Opaque copy, or state in or with each Opaque copy a computer-network location from which the general network-using public has access to download using public-standard network protocols a complete Transparent copy of the Document, free of added material. If you use the latter option, you must take reasonably prudent steps, when you begin distribution of Opaque copies in quantity, to ensure that this Transparent copy will remain thus accessible at the stated location until at least one year after the last time you distribute an Opaque copy (directly or through your agents or retailers) of that edition to the public.
It is requested, but not required, that you contact the authors of the Document well before redistributing any large number of copies, to give them a chance to provide you with an updated version of the Document.
You may copy and distribute a Modified Version of the Document under the conditions of sections 2 and 3 above, provided that you release the Modified Version under precisely this License, with the Modified Version filling the role of the Document, thus licensing distribution and modification of the Modified Version to whoever possesses a copy of it. In addition, you must do these things in the Modified Version:
If the Modified Version includes new front-matter sections or appendices that qualify as Secondary Sections and contain no material copied from the Document, you may at your option designate some or all of these sections as invariant. To do this, add their titles to the list of Invariant Sections in the Modified Version’s license notice. These titles must be distinct from any other section titles.
You may add a section Entitled “Endorsements”, provided it contains nothing but endorsements of your Modified Version by various parties—for example, statements of peer review or that the text has been approved by an organization as the authoritative definition of a standard.
You may add a passage of up to five words as a Front-Cover Text, and a passage of up to 25 words as a Back-Cover Text, to the end of the list of Cover Texts in the Modified Version. Only one passage of Front-Cover Text and one of Back-Cover Text may be added by (or through arrangements made by) any one entity. If the Document already includes a cover text for the same cover, previously added by you or by arrangement made by the same entity you are acting on behalf of, you may not add another; but you may replace the old one, on explicit permission from the previous publisher that added the old one.
The author(s) and publisher(s) of the Document do not by this License give permission to use their names for publicity for or to assert or imply endorsement of any Modified Version.
You may combine the Document with other documents released under this License, under the terms defined in section 4 above for modified versions, provided that you include in the combination all of the Invariant Sections of all of the original documents, unmodified, and list them all as Invariant Sections of your combined work in its license notice, and that you preserve all their Warranty Disclaimers.
The combined work need only contain one copy of this License, and multiple identical Invariant Sections may be replaced with a single copy. If there are multiple Invariant Sections with the same name but different contents, make the title of each such section unique by adding at the end of it, in parentheses, the name of the original author or publisher of that section if known, or else a unique number. Make the same adjustment to the section titles in the list of Invariant Sections in the license notice of the combined work.
In the combination, you must combine any sections Entitled “History” in the various original documents, forming one section Entitled “History”; likewise combine any sections Entitled “Acknowledgements”, and any sections Entitled “Dedications”. You must delete all sections Entitled “Endorsements.”
You may make a collection consisting of the Document and other documents released under this License, and replace the individual copies of this License in the various documents with a single copy that is included in the collection, provided that you follow the rules of this License for verbatim copying of each of the documents in all other respects.
You may extract a single document from such a collection, and distribute it individually under this License, provided you insert a copy of this License into the extracted document, and follow this License in all other respects regarding verbatim copying of that document.
A compilation of the Document or its derivatives with other separate and independent documents or works, in or on a volume of a storage or distribution medium, is called an “aggregate” if the copyright resulting from the compilation is not used to limit the legal rights of the compilation’s users beyond what the individual works permit. When the Document is included in an aggregate, this License does not apply to the other works in the aggregate which are not themselves derivative works of the Document.
If the Cover Text requirement of section 3 is applicable to these copies of the Document, then if the Document is less than one half of the entire aggregate, the Document’s Cover Texts may be placed on covers that bracket the Document within the aggregate, or the electronic equivalent of covers if the Document is in electronic form. Otherwise they must appear on printed covers that bracket the whole aggregate.
Translation is considered a kind of modification, so you may distribute translations of the Document under the terms of section 4. Replacing Invariant Sections with translations requires special permission from their copyright holders, but you may include translations of some or all Invariant Sections in addition to the original versions of these Invariant Sections. You may include a translation of this License, and all the license notices in the Document, and any Warranty Disclaimers, provided that you also include the original English version of this License and the original versions of those notices and disclaimers. In case of a disagreement between the translation and the original version of this License or a notice or disclaimer, the original version will prevail.
If a section in the Document is Entitled “Acknowledgements”, “Dedications”, or “History”, the requirement (section 4) to Preserve its Title (section 1) will typically require changing the actual title.
You may not copy, modify, sublicense, or distribute the Document except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense, or distribute it is void, and will automatically terminate your rights under this License.
However, if you cease all violation of this License, then your license from a particular copyright holder is reinstated (a) provisionally, unless and until the copyright holder explicitly and finally terminates your license, and (b) permanently, if the copyright holder fails to notify you of the violation by some reasonable means prior to 60 days after the cessation.
Moreover, your license from a particular copyright holder is reinstated permanently if the copyright holder notifies you of the violation by some reasonable means, this is the first time you have received notice of violation of this License (for any work) from that copyright holder, and you cure the violation prior to 30 days after your receipt of the notice.
Termination of your rights under this section does not terminate the licenses of parties who have received copies or rights from you under this License. If your rights have been terminated and not permanently reinstated, receipt of a copy of some or all of the same material does not give you any rights to use it.
The Free Software Foundation may publish new, revised versions of the GNU Free Documentation License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. See https://www.gnu.org/copyleft/.
Each version of the License is given a distinguishing version number. If the Document specifies that a particular numbered version of this License “or any later version” applies to it, you have the option of following the terms and conditions either of that specified version or of any later version that has been published (not as a draft) by the Free Software Foundation. If the Document does not specify a version number of this License, you may choose any version ever published (not as a draft) by the Free Software Foundation. If the Document specifies that a proxy can decide which future versions of this License can be used, that proxy’s public statement of acceptance of a version permanently authorizes you to choose that version for the Document.
“Massive Multiauthor Collaboration Site” (or “MMC Site”) means any World Wide Web server that publishes copyrightable works and also provides prominent facilities for anybody to edit those works. A public wiki that anybody can edit is an example of such a server. A “Massive Multiauthor Collaboration” (or “MMC”) contained in the site means any set of copyrightable works thus published on the MMC site.
“CC-BY-SA” means the Creative Commons Attribution-Share Alike 3.0 license published by Creative Commons Corporation, a not-for-profit corporation with a principal place of business in San Francisco, California, as well as future copyleft versions of that license published by that same organization.
“Incorporate” means to publish or republish a Document, in whole or in part, as part of another Document.
An MMC is “eligible for relicensing” if it is licensed under this License, and if all works that were first published under this License somewhere other than this MMC, and subsequently incorporated in whole or in part into the MMC, (1) had no cover texts or invariant sections, and (2) were thus incorporated prior to November 1, 2008.
The operator of an MMC Site may republish an MMC contained in the site under CC-BY-SA on the same site at any time before August 1, 2009, provided the MMC is eligible for relicensing.
To use this License in a document you have written, include a copy of the License in the document and put the following copyright and license notices just after the title page:
Copyright (C) year your name. Permission is granted to copy, distribute and/or modify this document under the terms of the GNU Free Documentation License, Version 1.3 or any later version published by the Free Software Foundation; with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts. A copy of the license is included in the section entitled ``GNU Free Documentation License''.
If you have Invariant Sections, Front-Cover Texts and Back-Cover Texts, replace the “with…Texts.” line with this:
with the Invariant Sections being list their titles, with the Front-Cover Texts being list, and with the Back-Cover Texts being list.
If you have Invariant Sections without Cover Texts, or some other combination of the three, merge those two alternatives to suit the situation.
If your document contains nontrivial examples of program code, we recommend releasing these examples in parallel under your choice of free software license, such as the GNU General Public License, to permit their use in free software.
これはsed
コマンドとコマンドラインオプションの例外を除く、この文書で述べた全ての話題の索引です。
Jump to: | - 0 ; A B C D E F G H I J L M N O P Q R S T U V W X Z |
---|
Jump to: | - 0 ; A B C D E F G H I J L M N O P Q R S T U V W X Z |
---|
全てのsed
コマンドとコマンドラインオプションのアルファベット順リストです。
Jump to: | # - : = { A B C D E F G H I L N P Q R S T U V W X Y Z |
---|
Jump to: | # - : = { A B C D E F G H I L N P Q R S T U V W X Y Z |
---|
sed
スクリプト
sed
の高度な話題: サイクルとバッファ
bash
の環境変数をプリントsed
の制限と、GNU sed
で撤廃された制限sed
を習得するためのこの文書以外の資料これは'=
'、'a
'、'c
'、'i
'、'l
'、'p
'のようなコマンドにも適用されます。. それでも、'w
'、'W
'コマンドに /dev/stdout を指定して標準出力に書き込む事ができます。
注意:GNU sed
は実際に変更が行われたかどうかにかかわらずバックアップファイルを作成します。
'-i'オプションが指定されてない限り、これは'p
'と同じです。
'-i'オプションが指定されてない限り、これは'p
'と同じです。
もちろん、同じ事をするのにいろんな方法があります。例えば次のようなのです。
grep 'bash$' /etc/passwd awk -F: '$7 == "/bin/bash"' /etc/passwd
ここで紹介しているエスケープは、\n
を除きGNU拡張です。基本正規表現モードでは、環境変数 POSIXLY_CORRECT
をセットするとブラケット('['...']')の中でそれを無効にします。
正規表現のマルチバイト文字処理についてはオペレーティングシステムとlibcの実装に依存するものがあります。ここで挙げた例はglibcを使うGNU/Linuxシステムでは期待どおりに動く事が分かっています。
実際には、sed
が行末の改行無しの行をプリントするときでも、同じ出力ストリームに更にテキストが送られると、行末の改行なしの行に続いて改行をプリントしてから更なるテキストをプリントします。単に内容の通り出力するのではないわけで、sed -n pコマンドはcat
コマンドと完全に同じ動作ではありません。
sed
導師のGreg UbbenはRPNのdc
を実装しました!それはsedと一緒に配布されました。
これにはバナー出力を埋め込むためのもう一つのスクリプトが必要です。例えば次のようなのです。
#!/bin/sh banner -w $1 $2 $3 $4 | sed -e :a -e '/^.\{0,'$1'\}$/ { s/$/ /; ba; }' | ~/sedscripts/reverseline.sed
いくつかのsed実装では1スクリプト辺りのコマンド数は199までという制限があります。
これは、動作の変更を促した実際の「バグ」です。