[〜#〜] 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
「クリーンソリューション」と同様:
sed -e '1,/HI_THERE/d' input_file
ファイルの最初の行は1行目です。常に知っているので特別な^
アドレスはありませんが、最後に$
は(必然的に)どの行かわからないので必要です。
一致する行がファイルのfirst行である場合、これはフォールオーバーします。 GNU sedを使用すると、0
の代わりに1
を使用して対処できます。POSIXsedと移植性(この場合は異なるようです)の場合は、さらに多くの機能があります。複雑(以下のコメントと このフォローアップの質問 を参照)。
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
最も近い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 Q
をw
(ファイルへの書き込み)に置き換えます。
sed
が機能しているのに、1、/ HI/dでed
が失敗するのはなぜですか?sed
は、正規表現が次の行で一致することを期待しているためです。
ed
では、3,3
3,/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
grep -nw HI_THERE file.txt |awk -F":" '{print $1}' | xargs -I % sed '1,%d' file.txt
説明:正確な単語w
を使用してgrepし、行番号n
を取得します
次に、awkを使用して行番号をプルします。区切り文字は:
さらにxargsを使用してこれをパイプし、それまで削除します。
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 を参照してください。
Posix sedに固執したい場合は、これを使用できます。
sed -ne '
/HI_THERE/!d
:loop
n
p
bloop
' inp.file
または、凝縮された方法で書かれています:
sed -n '/HI_THERE/!d;:a;n;p;ba' inp.file
$ Perl -ne 'print if 1 <(/HI_THERE/...eof)' input_file
範囲演算子を使用する場合...
適切な範囲を形成し、選択した範囲内の最初の要素を拒否するようにさらに制約します。