web-dev-qa-db-ja.com

マッチした後、ファイルの最後まですべての行を印刷する方法は?

入力ファイル1は次のとおりです。

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

other fileのパターンを([file2のdog 123 4335のように)一致させます。

行のパターンに一致するのはdog 123 4335で、一致行のないすべての行を印刷すると、出力は次のようになります。

cat 13123 23424
deer 2131 213132
bear 2313 21313

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

52
loganaayahee

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; ...; 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のすべてのバージョンがプラス表記をサポートしているわけではないことに注意してください。

29
Thor

適度に短いファイルがある場合、grepだけでも機能する可能性があります。

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

grepは最初の一致を見つけて次の5000行と一緒に出力するので、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式を複雑にして、そのバッファーを破棄することもできます。)

27
Aet3miirah

実際には私はおそらく Aet3miirahの答え をほとんど使用します alexey's answer は行をナビゲートしたいときに素晴らしいです(また、less)。 OTOH、私は本当に別のアプローチが好きです(それは一種の逆転 Gillesの答え

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

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

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

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

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

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

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

一致を部分文字列だけでなく行全体にしたい場合は、パターンを^…$で囲みます。

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

$ more +/"dog 123 4335" file1

14
alexey

awkの場合:

awk 'BEGIN {getline pattern < "other file"}
   NR == 1, $0 ~ pattern {next}; {print}' < "input file"
11

入力が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

GNU grep-mオプション付きで呼び出された場合、一致時に入力が中止され、その(lseekable)入力fdは、見つかったポイントの直後に残ります最後の試合。したがって、grep w/-m1を呼び出すと、ファイル内のパターンの最初の出現箇所が検出され、入力オフセットがcatの正しい場所に正確に残り、ファイル内のパターンの最初の一致に続くすべてがstdoutに書き込まれます。

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

5
mikeserv

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

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

ここで、file2には検索パターンが含まれています。まず、file2のすべての内容が配列 "a"に格納されます。 file1が処理されると、すべての行が配列と照合され、存在しない場合にのみ出力されます。

5
Guru

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
4
jbgood

Wth ed

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

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

2
Jeff Schaller

一時ファイルの作成を気にせず、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"

上記のcsplitフラグなしのprefixは、ファイルxx00を作成します(接頭辞はxx、接尾辞は00)。上記のフラグを使用すると、ファイルfile1_00が作成されます。 quietフラグがない場合、出力ファイルのサイズ(結果のファイルのサイズ)が出力されます。

1
YenForYang

Awkは明示的に禁止されていないので、「猫」が一致すると仮定した私のオファリングは次のとおりです。

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

マッチした後、ファイルの最後まですべての行を印刷する方法は?

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

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