web-dev-qa-db-ja.com

sed:これを含む1つに一致する前にすべての行を削除します

[〜#〜] target [〜#〜]

これを含め、一致する行の前にテキストファイルのすべての行を削除するにはどうすればよいですか?

入力ファイルの例:

Apple
pear
banana
HI_THERE
lemon
coconut
orange

必要な出力:

lemon
coconut
orange

目的は、「-i」オプション(直接編集)を使用するためにsedでそれを行うことです。

クリーンソリューション?

同様の問題に対するほとんどの回答は、次のようなものを提案しています。

sed -n '/HI_THERE/,$p' input_file

ただし、一致した行は削除されません。

HI_THERE
lemon
coconut
orange

次に、これを知っていると、一致した行(それを含む)からファイルの終わりまですべてが削除されます。

sed '/HI_THERE/,$d' input_file

私はこのようなことを試みました:

sed '^,/HI_THERE/d' input_file

しかし、sedは不平を言います:

sed: -e expression #1, char 1: unknown command: `^'

ダーティソリューション

最後の(汚い)解決策はパイプラインを使用することです:

sed -n '/HI_THERE/,$p' input_file | tail -n +2

ただし、ファイルの直接編集は機能しません。

sed -n '/HI_THERE/,$p' input_file | tail -n +2 > input_file
cat input_file # returns nothing

そして、そのような一時ファイルを使用する必要があります...

sed -n '/HI_THERE/,$p' input_file | tail -n +2 > tmp_file
mv tmp_file input_file
2
taalf

「クリーンソリューション」と同様:

sed -e '1,/HI_THERE/d' input_file

ファイルの最初の行は1行目です。常に知っているので特別な^アドレスはありませんが、最後に$は(必然的に)どの行かわからないので必要です。

一致する行がファイルのfirst行である場合、これはフォールオーバーします。 GNU sedを使用すると、0の代わりに1を使用して対処できます。POSIXsedと移植性(この場合は異なるようです)の場合は、さらに多くの機能があります。複雑(以下のコメントと このフォローアップの質問 を参照)。

4
Michael Homer

sed

Sedにはあなたが求めていることをする簡単な方法はありません。
sed用の最も単純なポータブルPOSIXlyソリューションは次のようなものです。

sed -ne '/HI/{:1' -e 'n;p;b1' -e '}'

その他の簡単な解決策は次のとおりです。

sed '0,/HI/d'      ./file             # GNU sed
awk 'f; /HI/{f=1}' ./file

ed

最も近いPOSIXlynon-sedソリューションは、edを使用することです。 HIが同じ最初の行にある場合でも、ファイルの最初の行から正規表現/HI/までの範囲を削除するだけです。

printf '%s\n' 1,/HI/d ,p Q | ed -s file

または

ed -Gs imfile2 <<-\edscript
1,/HI/d
,p
Q
edscript

つまり:

  • オプション-sで追加情報(読み取られた行数)を出力しません
  • fileの最初の行から正規表現/HI/1,/HI/d)までのすべての行を削除(削除)します。
  • 次に、ファイル全体を印刷します(,p)。
  • ファイルが変更されていても終了します(Q)。

ファイルを変更する場合は、,p Qw(ファイルへの書き込み)に置き換えます。

sedが機能しているのに、1、/ HI/dでedが失敗するのはなぜですか?

sedは、正規表現が次の行で一致することを期待しているためです。

edでは、3,33,/3//3/,3/3/,/3/のいずれかが3を1つだけ出力します。

$ printf '%s\n' 3,3p   3,/3/p   /3/3p   /3/,/3/p   Q | ed -s <(seq 5)
3
3
3
3

Sedがこれを行う間:

$ sed -ne 3,3p  <(seq 5)
3

$ sed -ne 3,/3/p  <(seq 5)
3
4
5

$ sed -ne /3/,3p  <(seq 5)
3

$ sed -ne /3/,/3/p <(seq 5)
3
4
5

範囲の終わりの正規表現は、行と一致することが期待されますfollowing範囲の開始(,の左側)で一致する行。 3の番号が付いた次の行には3がないため、sedは次のすべての行(4および5)を出力します。

そのため、GNU sedは0,/HI/の問題を解決します。

なぜ:1;n;p;b1

範囲のすべての行(最初の行を除く)を出力する方法は、firstが次の行を要求し、thenがそれを出力するループを使用することです。

$     sed -n '5{:1;n;p;b1}' <(seq 8)    # GNU syntax
6
7
8

したがって、必要な正規表現/HI/を一致させて、そのようなループに入るだけです。

sed -n '/HI/{:1;n;p;b1}' file        # GNU syntax

一部の古いsedではlabels;で終了できないため、これをより複雑なスクリプトに拡張する必要があります。

sed -n -e '/HI/{:1' -e 'n;p;b1' -e '}' file        # portable syntax
0
Isaac

grep -nw HI_THERE file.txt |awk -F":" '{print $1}' | xargs -I % sed '1,%d' file.txt

説明:正確な単語wを使用してgrepし、行番号nを取得します
次に、awkを使用して行番号をプルします。区切り文字は:
さらにxargsを使用してこれをパイプし、それまで削除します。

0
Death Metal

sedは、すべての個々の文字列に対してs/old/newを実行するためのものです。それ以外の場合は、awkを使用する必要があります。すべてのUNIXボックスの任意のシェルに任意のawkがあり、任意の行に表示される「HI_THERE」を処理します。

$ awk 'f; /HI_THERE/{f=1}' file
lemon
coconut
orange

必要に応じてGNU sed for -i次にGNU awk for -i inplace代わりに。ファイルのセクションを選択する他のスクリプトについては、 https://stackoverflow.com/a/17914105/1745001 を参照してください。

0
Ed Morton

Posix sedに固執したい場合は、これを使用できます。

sed -ne '
  /HI_THERE/!d
  :loop
    n
    p
  bloop
' inp.file

または、凝縮された方法で書かれています:

sed -n '/HI_THERE/!d;:a;n;p;ba' inp.file
0
Rakesh Sharma
$ Perl -ne 'print if 1 <(/HI_THERE/...eof)' input_file

範囲演算子を使用する場合...適切な範囲を形成し、選択した範囲内の最初の要素を拒否するようにさらに制約します。

0
Rakesh Sharma