説明で補完された、多くの役立つ既存の回答の概要:
ここでの例では、単純化された使用例を使用しています。最初の一致する行のみで単語「foo」を「bar」に置き換えます。ANSI C で引用された文字列 ( )
を
使用してサンプル入力行を提供しているため、、、またはがシェルと見なされます。$'...'
bash
ksh
zsh
GNU sed
のみ:
Ben Hoffstein の回答は、GNUが次の2 アドレス形式を許可するPOSIX 仕様の拡張を提供していることを示しています: (ここでは任意の正規表現を表します)。sed
0,/re/
re
0,/re/
正規表現が最初の行でも一致するようにします。言い換えれば、このようなアドレスは、最初の行から一致する行までの範囲を作成しre
ますre
。
- これを POSIX 準拠の form と比較してください。これは、最初の行から後続
1,/re/
の行で一致する行まで、およびその行を含む範囲を作成しre
ます。言い換えれば、最初の行で一致が発生した場合、これは最初の一致を検出せず、最近使用された正規表現を再利用するための短縮形の使用も防止します(次のポイントを参照)。1re
//
0,/re/
アドレスを、同じs/.../.../
正規表現を使用する (置換) 呼び出しと組み合わせると、コマンドは、一致する最初の行でのみ効果的に置換を実行します。は、最近適用された正規表現 を再利用するための便利なショートカットを提供します:空の区切り文字ペア.re
sed
//
$ sed '0,/foo/ s//bar/' <<<$'1st foo\nUnrelated\n2nd foo\n3rd foo'
1st bar # only 1st match of 'foo' replaced
Unrelated
2nd foo
3rd foo
sed
BSD (macOS) などの POSIX 機能のみ( sed
GNU でも動作しますsed
):
0,/re/
は使用できず、たまたま最初の行で発生してもフォーム1,/re/
は検出されないため(上記を参照)、 1 行目の特別な処理が必要です。re
MikhailVS の回答では、この手法について言及しており、ここに具体的な例を示しています。
$ sed -e '1 s/foo/bar/; t' -e '1,// s//bar/' <<<$'1st foo\nUnrelated\n2nd foo\n3rd foo'
1st bar # only 1st match of 'foo' replaced
Unrelated
2nd foo
3rd foo
ノート:
ここでは、空の正規表現の//
ショートカットが 2 回使用されていs
ます。どちらの場合も、正規表現foo
は暗黙的に再利用されるため、重複する必要がなくなり、コードが短くなり、保守しやすくなります。
POSIX では、ここsed
の場合のように、特定の関数の後に実際の改行が必要です。たとえば、ラベルの名前やその省略の後にさえありt
ます。-e
スクリプトを戦略的に複数のオプションに分割することは、実際の改行を使用する代わりの方法-e
です。通常、改行が必要な場所で各スクリプト チャンクを終了します。
1 s/foo/bar/
foo
そこにある場合は、最初の行のみを置き換えます。その場合t
は、スクリプトの最後に分岐します (行の残りのコマンドをスキップします)。(t
関数は、最新のs
呼び出しが実際の置換を実行した場合にのみ、ラベルに分岐します。この場合のように、ラベルがない場合は、スクリプトの最後に分岐します)。
その場合、1,//
通常は行 2 から始まる最初のオカレンスを検索する範囲 address が一致せず、範囲は処理されません。これは、現在の行が既に であるときにアドレスが評価されるため2
です。
逆に、最初の行に一致がない場合1,//
は入力され、真の最初の一致が検索されます。
最終的な効果は GNUsed
の場合と同じ0,/re/
です。最初の行で発生するか他の行で発生するかに関係なく、最初に発生したものだけが置き換えられます。
非範囲アプローチ
potong's answerは、 range の必要性を回避するループ手法を示しています。彼はGNU構文を使用しているため、POSIX準拠の同等のものは次のとおりです。 sed
ループ手法 1: 最初の一致で置換を実行し、残りの行をそのまま出力するループに入ります。
$ sed -e '/foo/ {s//bar/; ' -e ':a' -e '$!{n;ba' -e '};}' <<<$'1st foo\nUnrelated\n2nd foo\n3rd foo'
1st bar
Unrelated
2nd foo
3rd foo
小さいファイルのみのループ手法 2 :入力全体をメモリに読み込み、それに対して単一の置換を実行します。
$ sed -e ':a' -e '$!{N;ba' -e '}; s/foo/bar/' <<<$'1st foo\nUnrelated\n2nd foo\n3rd foo'
1st bar
Unrelated
2nd foo
3rd foo
1 1.618031,/re/
は、 がある場合、後続の がある場合、およびない場合の例を示していますs//
。
sed '1,/foo/ s/foo/bar/' <<<$'1foo\n2foo'
利回り$'1bar\n2bar'
; つまり、両方の行が更新されました。これは、行番号1
が最初の行と一致し、正規表現(範囲の末尾) が次の行/foo/
から開始するためにのみ検索されるためです。したがって、この場合は両方の行が選択され、両方に対して置換が実行されます。s/foo/bar/
sed '1,/foo/ s//bar/' <<<$'1foo\n2foo\n3foo'
失敗: sed: first RE may not be empty
(BSD/macOS) およびsed: -e expression #1, char 0: no previous regular expression
(GNU) では、最初の行が処理されている時点で (1
範囲の開始行番号のため)、まだ正規表現が適用されていないため//
、何も参照していません。GNUの特別な構文を
除いて、行番号で始まる範囲は事実上.
sed
0,/re/
//