Looking for sed Answers? Try Ask4KnowledgeBase
Looking for sed Keywords? Try Ask4Keywords

sedBSD / macOS Sed対GNU Sed対POSIX Sed仕様


前書き

@ SnoringFrogのトピック作成リクエストから引用するには:

「sedを使用している最大の悪夢の1つは、それらが1つではなく別のもので書かれているため、失敗する(または予期せぬ方法で成功する)スクリプトです。

備考

macOSBSD版のsed [1]を使用しています。これは、 Linuxディストリビューションに付属しているGNU sedバージョンとは多くの点で異なります。

それらの共通の分母POSIXによって宣言された機能です: POSIX sed specを見てください

もっとも移植性の高いアプローチは、 POSIX機能のみ使用することですが、 機能に限界があります

  • 特に、POSIXでは、多くの制限がある基本正規表現 (例えば、 | (交替)はまったくサポートされておらず、 +?直接サポートしてい? )と異なるエスケープ要件のみをサポートしています。

    • 警告: GNU sed-rなし) \|サポートしています\|\+\? POSIX準拠ではありません。無効にするには--posixを使います (下記参照)。
  • 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 ''を使うと動作しない。
    • -iは、 GNU sed最近のバージョンのBSD sed (FreeBSD 10など)では入力ファイルごとの行番号付け を有効にしますが、10.12以降のmacOSでは有効にません
      -iが指定されていない場合は、 すべてのバージョンが入力ファイルに累積的に番号を-iことに注意してください。

    • 最後の入力行に改行がない場合(および出力された場合):

      • BSD sed :入力行が1つで終わっていなくても、常に出力に改行追加します
      • GNU sed後続改行ステータスを保持します 。つまり、入力行が1つに終わる場合にのみ改行を追加します。
  • 共通の機能:

    • あなたのsedスクリプトをBSD sedサポートしているものに制限すると、それらは-Eプラットフォーム固有の拡張正規表現機能を使用するという顕著な例外を除いて、一般にGNU sedでも動作します。明らかに、GNU版特有の拡張機能も忘れてしまいます。次のセクションを参照してください。

クロスプラットフォームサポート (OS X / BSD、Linux)のガイドラインは、BSDバージョンのより厳しい要件に基づいています

なお、速記のMacOSLinuxは時折のBSDやGNUのバージョンを参照するために以下で使用されていることをsed 、彼らがそれぞれのプラットフォーム上での在庫のバージョンがあるため、それぞれ、。をしかし、 brew install gnu-sedを使ってHomebrewを使って、macOSにGNU sedをインストールすることは可能です。

注意-r-Eフラグが使用されている場合拡張正規表現)を除いて、以下の手順はPOSIX準拠の sedスクリプトの作成になります。

  • POSIX準拠の場合は、 POSIX BRE( 基本正規表現)に制限する必要があります。これは残念なことに、名前が示すように非常に基本的なものです。
    警告 :それを想定しない\|\+\?サポートされています:-- --posixが使われていない限り、GNU sedサポートしていますが、BSD sedはそうではありません - これらの機能は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
    • sコマンドで使用される置換文字列では、 制御文字のエスケープ・シーケンスはサポートされていないため、制御文字も含めてください。 リテラルとして、上記のように。

      • Linuxのみ:
        sed 's/-/\t/' <<<$'ab' # -> 'a<tab>b'
      • macOS Linux:
        sed 's/-/'$'\t''/' <<<'a-b'
        sed 's/-/'"$(printf '\t')"'/' <<<'a-b'
    • 同上にテキスト引数の iと機能制御文字列を使用していません -以下を参照してください。 a

  • ラベルと分岐 :ラベルとbt関数の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'
  • テキストを挿入/追加aための関数ia :テキスト引数を指定する前に、関数名の後に\リテラル改行またはスプライスイン$'\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のみ:
      • sed -n '1 {p;q}' <<<$'a\nb' # -> 'a'
    • macOS Linux:
      • sed -n '1 {p;q;}' <<<$'a\nb'

GNU sed特有の機能がBSD sedから完全になくなった:

両方のプラットフォームをサポートする必要がある場合は、あなたが逃してしまうGNUの機能:


[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'']

BSD / macOS Sed対GNU Sed対POSIX Sed仕様 関連する例