sed範囲が常に1行だけ一致できるわけではありません。

sed範囲が常に1行だけ一致できるわけではありません。

次の範囲を考慮してください。1,/pattern/最初の行でパターンが一致すると、範囲はファイル全体と一致します。

$ cat 1.sh
#!/usr/bin/env bash
set -eu
seq 1 4 | sed -rn '1,/'"$1"'/p'
$ ./1.sh 1
1
2
3
4
$ ./1.sh 2
1
2

あなたは何をしますか?

UPD私がしたことは次のとおりです。

re='/1/'
seq 1 4 | sed -rn "1{$re{p;q}}; 1,${re}p"

またはこれ:

seq 1 4 | sed -rn "1{/1/{p;q}}; 1,//p"

答え1

うん、迷惑なことだsed(見てsedよくある質問約このポイント)。 GNU sed(GNU固有)を使用しているので、-r次のことができます。

 sed -En "0,/$1/p"

(私はFreeBSDのような他のツールでもサポートされ、一貫性があるので-E好みます。-rsedgrepPOSIX/Single UNIX 仕様標準の次号)).

より良い代替(および移植可能)は次のとおりです。

sed "/$1/q"

sed最初のゲームが終了したら、終了(そして読み取りを停止)するように指示します。

問題がないので、awk次のように書くことができます。

PATTERN=$1 awk 'NR==1, $0 ~ ENVIRON["PATTERN"]'

(forに似ていますが、sed作成することをお勧めします):

PATTERN=$1 awk '1; $0 ~ ENVIRON["PATTERN"] {exit}'

答え2

これは通常の動作ですsed。 POSIXではsed文書:

sedのアドレス

アドレスは、ファイルの入力行を累積計算する10進数、入力の最後の行アドレスを指定する「$」文字、またはコンテキストアドレス(sedの正規表現で説明されているようにBREで構成されている)です。その後に区切り記号(通常はスラッシュ)が続きます。

アドレスのない編集コマンドは、各パターンスペースを選択する必要があります。

アドレスを持つ編集コマンドは、そのアドレスと一致するすべてのパターンスペースを選択する必要があります。

2つのアドレスを持つ編集コマンドは、最初のアドレスと一致する最初のパターンスペースから2番目のアドレスと一致する次のパターンスペースまで、包含範囲を選択する必要があります。。 (2番目のアドレスの番号が最初の選択された行番号より小さいか等しい場合は、1行だけ選択できます。)選択した範囲の後の最初の行から始めて、sedは最初のアドレスを再検索します。その後、このプロセスを繰り返す必要があります。次の形式のアドレス部分の一方または両方を省略すると、未定義の結果が生成されます。

[住所[,住所]]

sed最初のアドレスから次の一致するアドレスまで、包含範囲が印刷されていることがわかります。

あなたの場合は1,/1/p住所sedと一致するため、最初の行が印刷されます1。次に、2行目から始めて、sedはパターンに一致する2番目のアドレスを検索します/1/。見つかったら印刷を中止します。 2行目から始めると一致するパターンがないので、残りを印刷してください/1/sed

上記のようにsedを使用している場合は、1./2/p最初の行を印刷し、2番目の行をパターンに合わせて印刷し、/2/残りsedを繰り返します。ただし、1残りのアドレスは一致しないため、sed何も印刷されません。

一例:

$ echo 1 2 3 1 4 1 | tr ' ' $'\n' | sed -rn '1,/1/p'
1
2
3
1

を使用しているため、GNU sed次のフォームを使用できます0,addr2

0,addr2
              Start  out  in  "matched  first  address"  state, until addr2 is
              found.  This is similar to 1,addr2, except that if addr2 matches
              the very first line of input the 0,addr2 form will be at the end
              of its range, whereas the 1,addr2 form  will  still  be  at  the
              beginning of its range.  This works only when addr2 is a regular
              expression.

したがって、あなたのコマンドは次のようになります。

seq 1 4 | tr ' ' $'\n' | sed -rn '0,/'"$1"'/p'

それから:

$ ./1.sh 1
1

答え3

あなたができることはいくつかあります。たとえば、あなたのコメントは、あなたが次のことを意味することを示します。

...ファイルの先頭から特定の行(最初の行)まですべてを削除します。

次のことができます。

sed -n "/$1"'/,$p'

形を反転させるだけです。上記のコマンドは、特定の行からファイルの終わりまでのみ印刷します。

特定の行を印刷したくない場合は...

sed -n "/$1"'/,$p' | sed 1d

...トリックを実行する必要があります...

それ以外の場合は、問題を直接解決し、サイクルを直接処理できます。

seq 20 | sed -ne"/$1"'/!d;:B' -e'n;p;bB'
seq 20 | sed -n "/$1"'/!d;h;n;G;P;D'

両方のコマンドは、パターンが表示されるdまで着信する各行を削除します。$1

その後、最初のコマンドはnパターン空間を外部入力ラインで上書きし、:bラベルを設定します。その後、pラインを印刷してラベルに戻るn前に、パターンスペースを外部ラインで上書きします。ファイルの最後までこのように繰り返されます。このコマンドはおそらく2番目のコマンドよりも速く、より少ない操作を実行します。b:b

2番目は、h一致する項目で前のスペースを上書きします$1。次に、入力の追加の行でパターンスペースを上書きしますn。次に、Gスペースを解放し、インポートしたばかりの入力行に追加します。これにより、2行の順序が変わり、改行文字で区切られます。それは次のとおりです。

  • 1号線 > スペース確保

  • 2号線 > 1号線

  • 予約スペース >> 2号線

  • = ライン 2\n ライン 1

この時点で、パターンスペースに現れる最初のewline文字sed Pのみが印刷され、残りのループを再開する前に同じ要素 - end\nDいつも$1最初のマッチラインです各ライン。したがって、一致する最初の行$1は次のようになります。いつもパターン空間ではいいえ印刷。

したがって、以下を$1印刷すると:5

6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

答え4

quitコマンドを含むスコープの後に関数リストを使用するときは、スコープを保持したりオプションsedを使用したりする-Eことはできません(FreeBSDとGNUでテスト済み)。-rsedqsed

printf '%s\n' {1..10} | sed -n '1,/1/{p;q;}'

# your solution adapted to work with FreeBSD sed as well
re='/1/'
printf '%s\n' {1..4} | sed -En "1{$re{p;q;};}; 1,${re}p"
printf '%s\n' {1..4} | sed -En "1{/1/{p;q;};}; 1,//p"

関連情報