sed
BSD / macOS Sed対GNU Sed対POSIX Sed仕様
サーチ…
前書き
@ SnoringFrogのトピック作成リクエストから引用するには:
「sedを使用している最大の悪夢の1つは、それらが1つではなく別のもので書かれているため、失敗する(または予期せぬ方法で成功する)スクリプトです。
備考
macOSはBSD版のsed
[1]を使用しています。これは、 Linuxディストリビューションに付属しているGNU sed
バージョンとは多くの点で異なります。
それらの共通の分母はPOSIXによって宣言された機能です: POSIX sed
specを見てください。
もっとも移植性の高いアプローチは、 POSIX機能のみを使用することですが、 機能には限界があります 。
特に、POSIXでは、多くの制限がある基本正規表現 (例えば、
|
(交替)はまったくサポートされておらず、+
と?
直接サポートしてい?
)と異なるエスケープ要件のみをサポートしています。- 警告: GNU
sed
(-r
なし) は\|
サポートしています\|
、\+
と\?
POSIX準拠ではありません。無効にするには--posix
を使います (下記参照)。
- 警告: GNU
POSIX機能のみを使用するには :
(両方のバージョン):-
-n
と-e
オプションのみを使用します(特に、 拡張正規表現のサポートを有効にするには-E
または-r
を使用しないでください)GNU
sed
:POSIXのみの機能を確実にするためのオプション--posix
を追加する(これは厳密には必要ではないが、それがなければ非POSIX機能を気付かずに使用することになる可能性がある; - 注意 :----posix
自体はPOSIX準拠ではない )POSIXのみの機能を使うことは、より厳密なフォーマット要件を意味します(GNU
sed
利用可能な多くの利便性)。-
\n
や\t
などの制御文字列は、一般的にはサポートされていません。 - ラベルや分岐コマンド(例:
b
)の後には、 実際の改行や、別の-e
オプションによる継続が続かなければなりません 。 - 詳細は以下を参照してください。
-
しかし、 どちらのバージョンもPOSIX標準への拡張を実装しています。
- 彼らがどのような拡張機能を実装しているかは異なります (GNU
sed
はもっと多くを実装しています)。 - それらが両方とも実装している拡張機能でも 構文が異なります 。
両方のプラットフォームをサポートする必要がある場合(相違点の説明)
互換性のない機能:
引数なしで
-i
オプションを使用する(バックアップなしのインプレース更新)は互換性がありません。- BSD
sed
:-i ''
使用しなければならない - GNU
sed
:-i
だけを使用しなければならない(-i''
と同等)-i ''
を使うと動作しない。
- BSD
-i
は、 GNUsed
と最近のバージョンのBSDsed
(FreeBSD 10など)では入力ファイルごとの行番号付け を有効にしますが、10.12以降のmacOSでは有効にしません 。
-i
が指定されていない場合は、 すべてのバージョンが入力ファイルに累積的に番号を-i
ことに注意してください。最後の入力行に改行がない場合(および出力された場合):
- BSD
sed
:入力行が1つで終わっていなくても、常に出力に改行を追加します 。 - GNU
sed
: 後続改行ステータスを保持します 。つまり、入力行が1つに終わる場合にのみ改行を追加します。
- BSD
共通の機能:
- あなたの
sed
スクリプトをBSDsed
サポートしているものに制限すると、それらは-E
プラットフォーム固有の拡張正規表現機能を使用するという顕著な例外を除いて、一般にGNUsed
でも動作します。明らかに、GNU版特有の拡張機能も忘れてしまいます。次のセクションを参照してください。
- あなたの
クロスプラットフォームサポート (OS X / BSD、Linux)のガイドラインは、BSDバージョンのより厳しい要件に基づいています 。
なお、速記のMacOSとLinuxは時折のBSDやGNUのバージョンを参照するために以下で使用されていることをsed
、彼らがそれぞれのプラットフォーム上での在庫のバージョンがあるため、それぞれ、。をしかし、 brew install gnu-sed
を使ってHomebrewを使って、macOSにGNU sed
をインストールすることは可能です。
注意 : -r
と-E
フラグが使用されている場合 ( 拡張正規表現)を除いて、以下の手順はPOSIX準拠の sed
スクリプトの作成になります。
POSIX準拠の場合は、 POSIX BRE( 基本正規表現)に制限する必要があります。これは残念なことに、名前が示すように非常に基本的なものです。
警告 :それを想定しない\|
、\+
と\?
サポートされています:----posix
が使われていない限り、GNUsed
サポートしていますが、BSDsed
はそうではありません - これらの機能はPOSIXに準拠していません 。
\+
と\?
POSIX準拠の方法でエミュレートできます 。
\{1,\}
は\+
、
\{0,1\}
は\?
、
\|
残念なことに、 (代替) できません 。より強力な正規表現については、 使用
-E
(というより-r
のERE( 拡張正規表現)(GNUのサポートするために)sed
記述されていません-E
、それはの別名としてそこに働くん-r
、BSDの新しいバージョンsed
FreeBSD 10などでも-r
サポートしていますが、10.12以降のmacOSバージョンはサポートしていません )。
警告 :-r
/-E
使用は、あなたのコマンドがPOSIXに準拠していないことを意味しますが、 POSIX ERE(拡張正規表現)に制限する必要があります。残念なことに、これはあなたがいくつかの有用な構成を使用することができないことを意味します。- 単語境界表明、彼らは、 プラットフォーム固有のだから(例えば、
\<
Linux上、[[:<]]
OS X上)。 - BSD
sed
は拡張正規表現でそれらをサポートしていないので( 正規表現の中での逆参照は(関数の呼び出しs
置換文字列でs
捕捉グループの一致に対する "逆参照"とは対照的ですが)、興味深いことに基本的なPOSIX準拠のものです)。
- 単語境界表明、彼らは、 プラットフォーム固有のだから(例えば、
\n
や\t
ような制御文字のエスケープシーケンス:regexes (行選択のパターンと
s
関数の最初の引数の両方)では、\n
だけがエスケープシーケンスとして認識されると仮定します(通常、パターンスペースは\n
を終了せずに1行です)。ではなく、文字クラス内の、例えば、そのよう[^\n]
動作しません。(あなたの入力は何の制御文字が含まれていない場合以外。\t
、あなたがエミュレートすることができます[^\n]
と[[:print:][:blank:]]
いずれかで、一般的に、 リテラルとして制御文字が含まれるスプライスさ-にANSI C-引用符で囲まれた文字列 (例えば、経由 - [2]) リテラルとしてそれ以外の場合は、スプライス制御文字で;$'\t'
中)それをサポートするシェル(bash,
ksh、zsh
)、またはprintf
(例えば"$(printf '\t')"
) を使用したコマンド置換を介して実行できます。- Linuxのみ:
sed 's/\t/-/' <<<$'a\tb' # -> 'a-b'
- OSX および Linux:
sed 's/'$'\t''/-/' <<<$'a\tb' # ANSI C-quoted string
sed 's/'"$(printf '\t')"'/-/' <<<$'a\tb' # command subst. with printf
- Linuxのみ:
s
コマンドで使用される置換文字列では、 制御文字のエスケープ・シーケンスはサポートされていないため、制御文字も含めてください。 リテラルとして、上記のように。- Linuxのみ:
sed 's/-/\t/' <<<$'ab' # -> 'a<tab>b'
- macOS と Linux:
sed 's/-/'$'\t''/' <<<'a-b'
sed 's/-/'"$(printf '\t')"'/' <<<'a-b'
- Linuxのみ:
同上にテキスト引数の
i
と機能 : 制御文字列を使用していません -以下を参照してください。a
ラベルと分岐 :ラベルと
b
とt
関数のlabel-name 引数には、 リテラル改行またはスプライスされた$'\n'
いずれかが続く必要があります 。または、複数の-e
オプションを使用して、ラベル名の後ろの各行を終了することもできます。- Linuxのみ:
sed -n '/a/ bLBL; d; :LBL p' <<<$'a\nb' # -> 'a'
- macOS と Linux:
- どちらか(実際の改行):
sed -n '/a/ bLBL d; :LBL p' <<<$'a\nb'
- OR(spliced-in
$\n
インスタンス):
sed -n '/a/ bLBL'$'\n''d; :LBL'$'\n''p' <<<$'a\nb'
- OR(複数の
-e
オプション):
sed -n -e '/a/ bLBL' -e 'd; :LBL' -e 'p' <<<$'a\nb'
- どちらか(実際の改行):
- Linuxのみ:
テキストを挿入/追加
a
ための関数i
とa
:テキスト引数を指定する前に、関数名の後に\
、 リテラル改行またはスプライスイン$'\n'
いずれかを続けます。- Linuxのみ:
sed '1 i new first line' <<<$'a\nb' # -> 'new first line<nl>a<nl>b'
- OSX および Linux:
sed -e '1 i\'$'\n''new first line' <<<$'a\nb'
- 注意:
-
-e
ないと、テキスト引数は、macOS(バグ?)の出力では改行で終了するのは不可能です。 - text引数に
\n
や\t
などの制御文字エスケープを使用しないでください 。これはLinuxでのみサポートされているからです。 - テキスト引数は、したがって、実際の内部改行を持っている場合は、
\
それらを-escape。 - text引数の後ろに追加のコマンドを置くには、改行(リテラルまたはスプライスされていない)で(エスケープしていない)改行を終了するか、別々の
-e
オプションを続ける必要があります(これは全バージョンに適用される一般的な要件です) 。
-
- Linuxのみ:
関数リスト (
{...}
囲まれた複数の関数呼び出し)の中で、 最後の関数を閉じる前に必ず終了してください}
;
。- Linuxのみ:
-
sed -n '1 {p;q}' <<<$'a\nb' # -> 'a'
-
- macOS と Linux:
-
sed -n '1 {p;q;}' <<<$'a\nb'
-
- Linuxのみ:
GNU sed
特有の機能がBSD sed
から完全になくなった:
両方のプラットフォームをサポートする必要がある場合は、あなたが逃してしまうGNUの機能:
さまざまな正規表現マッチングと置換のオプション (行選択のパターンと
s
関数の最初の引数の両方):- 大文字と小文字を区別しない正規表現マッチングの
I
オプション(信じられないほど、BSDsed
はこれをまったくサポートしていません)。 - 複数行のマッチングのための
M
オプション(^
/$
は各行の開始/終了と一致します ) - 固有の追加オプションについては
s
機能を参照してくださいhttps://www.gnu.org/software/sed/manual/sed.html#The-_0022s_0022-Commandを
- 大文字と小文字を区別しない正規表現マッチングの
エスケープシーケンス
substring操作を可能にする
s///
関数s///
置換引数の\u
などの置換に関連するエスケープシーケンス。例:sed 's/^./\u&/' <<<'dog' # -> 'Dog'
- http://www.gnu.org/software/sed/manual/sed.html#The-_0022s_0022を参照してください。 -コマンド制御文字のエスケープシーケンス:
\n
、\t
、...、コードポイントに基づくエスケープに加えて。たとえば、次のすべてのエスケープ(16進数、8進数、10進数)は一重引用符('
)を表します:\x27
、\o047
、\d039
- https://www.gnu.org/software/sed/manual/ sed.html#エスケープ
以下のようなアドレス拡張 、
first~step
ステップごと番目の行にマッチする、addr, +N
次Nラインを一致させるaddr
、... -参照http://www.gnu.org/software/sed/manual/sedを。 html#アドレス
[1] macOS sed
バージョンは、FreeBSDやPC-BSDのような他のBSDのようなシステムのバージョンより古いです。残念ながら、これは、例えば、FreeBSDで動作する機能がmacOS上で動作するとは想定できないことを意味します。
[2] ANSI Cで引用された文字列$'\001\002\003\004\005\006\007\010\011\013\014\015\016\017\020\021\022\023\024\025\026\027\030\031\032\033\034\035\036\037\177'
は\n
(およびNUL)以外のすべてのASCII制御文字が含まれているため、 [:print:]
[^\n]
かなり頑丈なエミュレーションのために:
'[[:print:]'$'\001\002\003\004\005\006\007\010\011\013\014\015\016\017\020\021\022\023\024\025\026\027\030\031\032\033\034\035\036\037\177'']
すべての改行をタブで置き換える
注意:簡潔にするため、コマンドではhere-strings( <<<
)とANSI Cで引用符で囲まれた文字列( $'...'
)を使用します。これらのシェル機能は、両方ともbash
、 ksh
、およびzsh
ます。
# GNU Sed
$ sed ':a;$!{N;ba}; s/\n/\t/g' <<<$'line_1\nline_2\nline_3'
line_1 line_2 line_3
# BSD Sed equivalent (multi-line form)
sed <<<$'line_1\nline_2\nline_3' '
:a
$!{N;ba
}; s/\n/'$'\t''/g'
# BSD Sed equivalent (single-line form, via separate -e options)
sed -e ':a' -e '$!{N;ba' -e '}; s/\n/'$'\t''/g' <<<$'line 1\nline 2\nline 3'
BSD Sedノート:
ラベル(
:a
)を終了し、実際の改行または別々の-e
オプションを使用してコマンド(ba
)を分岐する必要があることに注意してください。\t
などの制御文字のエスケープシーケンスは置換文字列でサポートされていないため、ANSI C引用符付きタブリテラルが置換文字列に継承されます。
( 正規表現の部分では、BSD Sed は\n
をエスケープシーケンスとして認識します)。
リテラルテキストを関数 'a'の行に追加する
注意:簡潔にするため、コマンドではhere-strings( <<<
)とANSI Cで引用符で囲まれた文字列( $'...'
)を使用します。これらのシェル機能は、両方ともbash
、 ksh
、およびzsh
ます。
# GNU Sed
$ sed '1 a appended text' <<<'line 1'
line 1
appended text
# BSD Sed (multi-line form)
sed '1 a\
appended text' <<<'line 1'
# BSD Sed (single-line form via a Bash/Ksh/Zsh ANSI C-quoted string)
sed $'1 a\\\nappended text' <<<'line 1'
BSD Seedは\
て、 実際の改行を続けて、追加するテキストを渡す必要があることに注意してください。
関連するi
(挿入)関数とc
(削除と挿入)関数についても同様です。