ファイルの最後まで一致した後にすべての行を印刷する方法は?


48

入力file1は次のとおりです。

dog 123 4335
cat 13123 23424 
deer 2131 213132
bear 2313 21313

一致するパターンをinからother filedog 123 4335file2のように)指定します。

行のパターンに一致し、dog 123 4335一致行なしですべての行を印刷した後の出力は次のとおりです。

cat 13123 23424
deer 2131 213132
bear 2313 21313

行のアドレスなしでのみ使用する場合は、パターンを使用するだけです(たとえば1s 、行を照合して印刷する方法など)。


他のファイルには、検索する単一のパターンまたは行ごとに1つのパターンを含め、検索したファイルで最初に見つかった行から検索を開始できますか?
Ciro Santilli新疆改造中心法轮功六四事件

回答:


27

GNUを使用してsed、行全体をパターンと一致させたい場合、これは機能します。

sed -n '/^dog 123 4335$/ { :a; n; p; ba; }' infile

同等の標準:

sed -ne '/^dog 123 4335$/{:a' -e 'n;p;ba' -e '}' infile

次の入力(infile)で:

cat 13123 23424 
deer 2131 213132
bear 2313 21313
dog 123 4335
cat 13123 23424 
deer 2131 213132
bear 2313 21313

出力は次のとおりです。

cat 13123 23424 
deer 2131 213132
bear 2313 21313

説明:

  • /^dog 123 4335$/ 目的のパターンを検索します。
  • :a; n; p; ba;は、入力から新しい行をフェッチし(n)、それを印刷し(p)、ラベルaに戻るループです:a; ...; ba;

更新

あなたのニーズに近い答えがあります。つまり、file2のパターン、file1からgreppingです。

tail -n +$(( 1 + $(grep -m1 -n -f file2 file1 | cut -d: -f1) )) file1

埋め込まれたgrepとcutは、file2からパターンを含む最初の行を見つけます。この行番号に1を加えたものが末尾に渡され、プラス1がパターンのある行をスキップします。

最初の一致ではなく最後の一致から開始する場合は、次のようになります。

tail -n +$(( 1 + $(grep -n -f file2 file1 | tail -n1 | cut -d: -f1) )) file1

tailのすべてのバージョンがプラス表記をサポートしているわけではないことに注意してください。


これは、sedのnおよびpコマンドの最初の例であり、sedを使いすぎないように感じています。(私の短いテストから)sed -n '/^dog 123 4335$/ { :a; p; n; ba; }' infile(pとnを切り替えて)一致する行も正常に含めるようです。
ジョサイアヨーダー

26

あなたが合理的に短いファイルをgrep単独で持っている場合はうまくいくかもしれません:

grep -A5000 -m1 -e 'dog 123 4335' animals.txt

5000はgrep、最初の一致を見つけて次の5000行と一緒に出力するため、「合理的に短い」という推測に過ぎません(ファイルにはそれほど多くの行は必要ありません)。マッチ自体が必要ない場合は、カットする必要があります。例えば

grep -A5000 -m1 -e 'dog 123 4335' animals.txt | tail -n+2


最初ではなく、区切り文字として最後の一致が必要な場合は、これを使用できます。

tac animals.txt | sed -e '/dog 123 4335/q' | tac

この行animals.txtは、行の逆順で読み取り、行を含む行まで出力しdog 123 4335、その後再び逆順にして適切な順序に戻します。

繰り返しますが、結果に一致する必要がない場合は、末尾を追加します。(sed式を複雑にして、終了する前にバッファーを破棄することもできます。)


私のテストでは、GNU grep 3.0は(指定された値に関係なく)コンテキスト後の132行以上を出力しません。
-ruvim

22

実際には、ほとんどの場合、Aet3miirahの回答を使用しますが、alexeyの回答は、行をナビゲートしたいときに素晴らしいです(また、で動作しますless)。OTOH、私は本当に別のアプローチが好きです(逆のGillesの答えの一種です:

sed -n '/dog 123 4335/,$p'

-nフラグを指定sedして呼び出された場合、デフォルトでは、処理する行を印刷しません。次に/dog 123 4335/、ファイルの最後(で表される$)まで一致する行からコマンドを適用するという2アドレス形式を使用します。問題のコマンドはp、現在の行を出力します。したがって、これは「一致するもの/dog 123 4335/から最後まですべての行を印刷する」ことを意味します。


3
dogここでは不要な行を出力します。
ステファンシャゼル

1
これはベストアンサーのように見えますが(私自身のケースでも機能します)、一致した行もスキップするように適合させる必要があります。
パベルシメルダ

1
sed -n '/ dog 123 4335 /、$ p' | sed '1d'は犬のラインを削除します
ケミン・ジョウ

1
sed -n '/dog 123 4335/,$p' | tail -n +2同様に試合を削除します
gilad mayani

15
sed -e '1,/dog 123 4335/d' file1

ファイルからパターンを読み取る必要がある場合は、sedコマンドに置き換えてください。ファイルにsedパターンが含まれる場合:

sed -e "1,/$(cat file2)/d" file1

ファイルに検索するリテラル文字列が含まれている場合は、すべての特殊文字を引用符で囲みます。ファイルには単一行が含まれていると思います。

sed -e "1,/$(sed 's/[][\\\/^$.*]/\\&/g' file2)/d" file1

部分文字列だけでなく行全体を一致させる場合は、パターンをでラップし^…$ます。

sed -e "1,/^$(sed 's/[][\\\/^$.*]/\\&/g' file2)\$/d" file1

6
パターンが最初の行にある場合は機能しません。GNU sed0,/dog.../dそのために持っています。
ステファンシャゼル

14

$ more +/"dog 123 4335" file1


4
でも動作しlessます。
ブランディッツィ

3
端末では賢いですが、のような他のものにパイプすると実際には機能しませんtac
jcomeau_ictx

私はこのように使用しています、$ more + / "match my words" file1 >> file2
AMB

1
POSIX 7ではpubs.opengroup.org/onlinepubs/9699919799/utilities/more.html+に置き換えられたかもしれませんが、util-linux 2.20.1にはまだ実装されていません。そして、これも印刷し、いくつかの余分な改行を追加します(stderrに期待しているので、大丈夫かもしれません)。-pskipping..
Ciro Santilli新疆改造中心法轮功六四事件

たぶんそれ以来、状況は変わったのでしょうか?私のコメントは3つの賛成票を得たので、それは当時関連していたかもしれません
...-jcomeau_ictx


5

awkを使用する1つの方法:

awk 'NR==FNR{a[$0];next}f;($0 in a){f=1}'  file2 file1

file2には検索パターンが含まれます。最初に、file2のすべてのコンテンツが配列「a」に格納されます。file1が処理されると、すべての行が配列と照合され、存在しない場合にのみ出力されます。


OPはパターンに続くすべての行を出力したいと思います。
トール

@Thor:指摘してくれてありがとう、今すぐ更新しました...-
グル

うまくやった:)。
トール

5

入力がlseekable通常ファイルの場合:

GNUの場合grep

{ grep  -xFm1 'dog 123 4335' >&2
  cat; } <infile 2>/dev/null >outfile

sed

{ sed -n '/^dog 123 4335$/q'
  cat; } <infile >outfile

オプションとgrep呼ばれるGNU -mは、マッチで入力を終了します-そして、最後のマッチを見つけたポイントの直後に(lseekable)入力fd を残します。したがって、grepw / -m1を呼び出すと、ファイル内のパターンの最初の出現が検出され、ファイル内catのパターンの最初の一致に続くすべてをstdoutに書き込むための正確な場所に入力オフセットが残されます。

GNU grepがなくても、POSIX互換とまったく同じことを行うことができます-uitsが指定されているsed場合sed q、入力オフセットを正しい場所に残すように指定されています。sedただし、GNU はこの方法では標準に準拠していないため、上記の方法はsed-uスイッチで呼び出さない限りGNUでは機能しません。


sedここで示されているストリーム共有は、示されている自由形式で条件付きで協調的なワークフローの特別なものではありません(はい、参照されている標準sedはユーティリティとして具体的に例を示しています)。特に、すべての標準ユーティリティは、次のリーダーの処理をまったく失敗させることなく、入力ストリームのカーソル位置を協力して共有することを意図および指定しています。grep -qこれを行う必要があります。grep入力で一致するものが見つかるとすぐに静かに戻り、標準では残りの入力はデフォルトで消費されません。
mikeserv

4

2番目のファイルにパターンを保存せずに、件名の質問に対する私の答え。これが私のテストファイルです。

$ cat animals.txt 
cat 13123 23424 
deer 2131 213132
bear 2313 21313
dog 123 4335
cat 13123 23424 
deer 2131 213132
bear 2313 21313

GNU sed:

 $ sed '0,/^dog 123 4335$/d' animals.txt 
 cat 13123 23424 
 deer 2131 213132
 bear 2313 21313

Perl:

$ perl -ne 'print unless 1.../^dog 123 4335$/' animals.txt
cat 13123 23424 
deer 2131 213132
bear 2313 21313

ファイルにパターンがあるPerlバリアント:

$ cat pattern.txt 
dog 123 4335
$ perl -ne 'BEGIN{chomp($p=(<STDIN>)[0])};print unless 1../$p/;' animals.txt < pattern.txt
cat 13123 23424 
deer 2131 213132
bear 2313 21313

2

Wth ed

ed -s file1 <<< '/dog 123 4335/+1,$p'

これにより、1つのprintコマンドがhere-stringでedに送信されます。印刷コマンドの範囲は、ファイルの最後()まで一致+1)に制限されます。dog 123 4335$


1

一時ファイルの作成を気にせず、csplit利用できる場合、これは動作します:

sh -c 'csplit -sf"$1_" "$1" "%^$(cat "$2")%+1" && cat "${1}_00"' sh file1 file2

file1は入力ファイルでfile2あり、パターンファイルです(質問に記載されています)。

上記のコマンドの長い形式は次のとおりです。

sh -c 'csplit --quiet --prefix="$1_" "$1" "%^$(cat "$2")%+1" && cat "${1}_00"' sh file1 file2

すなわち、

csplit --quiet --prefix="file1_" "file1" "%^$(cat "file2")%+1" && cat "file1_00"

csplitprefix上記のフラグがないと、ファイルが作成されますxx00(プレフィックスはxx、サフィックスは00)。上記のフラグを使用すると、ファイルが作成されますfile1_00quietフラグを指定しないと、出力ファイルサイズ(結果ファイルのサイズ)が印刷されます。


0

awkは明示的に禁止されていないため、「猫」が一致すると仮定した場合の私の提案です。

awk '$0 ~ /cat/ { vart = NR }{ arr[NR]=$0 } END { for (i = vart; i<=NR ; i++) print arr[i]  }' animals.txt

0

ファイルの最後まで一致した後にすべての行を印刷する方法は?

別の言い方をすると、「最初の行から一致するまですべての行を削除する方法(含む)」であり、これは次のようにsed書くことができます。

sed -e '1,/MATCH PATTERN/d'

1
唯一の問題は、パターンが最初の行にあるときです
...-don_crissti


ここに委員会が必要だと思います。
-poige

1
@poige:ああ、あなたは同じ答えをあまり包括的に提供しません
トール

@don_crissti、sed -e '0,/MATCH PATTERN/d'それではどうですか?
ベルカン
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.