行番号の長いリストに基づいて行を除外する


3

ファイルに入れたくない行番号の長いリスト(35389208)があります。行番号とは、ファイル内の行(たとえば、行277)を意味します。不要な行番号のリストは次のようになります。

277
278
279
280
289
290
291
292
321
322
....

これらの行番号をファイルから除外する最良の方法は何ですか?perl sedまたはawk(またはその他)のソリューション。

回答:


1

次の正規表現を使用してみてくださいsed

sed '/^[0-9]*$/d' filename.txt

これにより、ファイルに数字のみが含まれる行が削除されます。

次のPerlスクリプトは、ファイルからn行目を削除しinput.txt、残りをに出力しstdoutます。行番号は次で指定できますline_numbers.txt

#!/usr/bin/perl

my @lines_to_exclude;

open(my $fh_line_numbers, "<", "line_numbers.txt") or die "Failed to open file: $!\n";
while(<$fh_line_numbers>) { 
  chomp; 
  push @lines_to_exclude, $_;
} 
close $fh_line_numbers;

my $linecounter = 1;

open (my $fh_datafile, '<', 'input.txt') or die "Cannot open $filename: $!";

while ( my $line = <$fh_datafile> ) {

  if ( ! ( $linecounter ~~ @lines_to_exclude ) ) {
    print $line;
  }

  $linecounter++;
}

close($fh_datafile);

~~演算子はperl> = 5.10でのみ利用可能です)


すみません、あなたは誤解したと思います。行番号のリストがあり、ファイルからそれらの行番号を省略したい。私のファイルがfilename.txtの場合、277、278、279行などを省略します。これらの行には必ずしも番号277などが含まれているとは限りません。
bdeonovic 14年

私は確かに誤解@Benjamin、私は私の答えを更新
mtak

最終的にはperlスクリプトも実行しました。私のものが正しいことをしないなら、私はあなたのものを試みます。
bdeonovic 14年

1

すべての行番号をメモリに読み込むことがオプションである場合、次のようにしてこのようにすることができますawk

awk 'FNR == NR { h[$1]; next } !(FNR in h)' line-numbers.txt input.txt

使用可能なメモリが限られていて、line-numbers.txtファイルが数値でソートされている場合、次のようにできます。

delete-lines.awk

BEGIN {  
  lines_file = "line-numbers.txt"
  if(!(getline n < lines_file)) { 
    print "Unable to open lines file " lines_file > "/dev/stderr" 
    exit 
  } 
} 

FNR != n

FNR == n {
  getline n < lines_file
}

次のように実行します。

awk -f delete-lines.awk input.txt

次をline-numbers.txt含む場所のテスト:

277
278
279
280
289
290
291
292
321
322

input.txt表されseq 325ます。

最初にメモリ内の行番号で:

seq 325 | awk 'FNR == NR { h[$1]; next } !(FNR in h)' line-numbers.txt -

次に、行番号を1つずつ読み取ります。

seq 325 | awk -f delete-lines.awk -

両方の場合の出力(1行目から274行目は省略):

.
.
.
275
276
281
282
283
284
285
286
287
288
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
323
324
325


0

これはあなたのために働くかもしれません(GNU sed):

sed 's/.*/&d/' line-numbers-to-delete-file | sed -f - file-to-be-shortened

削除する行を含むファイルからスクリプトを生成し、入力として短縮したいファイルを使用してsedのインスタンスにフィードします。


0

試行2の追加コードを除いて、すべてのコードは実際にOPが要求したものとは反対のことに注意してください。試行2でわかるように、コマンドを簡単に調整できます。

サイズが約83 MBの1.108.752行のテキストファイルがありました。15行目から1.108.716行目までの46.744行を取得したかったのですが、これは平均で約24行ごとです。

tl; dr;

2回目の試行は最初の試行よりも高速です。3番目は、少ない行でのみ機能します。

最初の試み(悪い)

必要なすべての行についてsed、テキストファイルの先頭から行を読み取りますが、印刷しません(-n)。目的の行に到達したら、ファイルの最後まで読み込むのではなく、印刷(p)してから終了(q)します。その後、次の行番号に対してもう一度それを行います。

明らかに、これは毎回sedよりも多くの行を通過する必要があるため、実行ごとに少し長くかかります。

私がその権利を計算した場合、私の場合、全体で307332472188パスがテキストファイルを通過します。ああ。

このアプローチでは、行番号のファイルでは行の順序は無関係です。

while read line; do
    sed -n "${line}{p;q}" "${INFILE}"
done

タイミング結果:2568.80s user 256.10s system 92% cpu 51:00.37 total。ダメ。

2回目の試行(より良い)

これはファイルから行番号を読み取り、p(この行を印刷するために)を追加します。この文字列は、次にパイプされるsedファイル(から読み込む、-fここでれる)、STDINとして書か-れるたびに最初から出力され、sed印刷される行番号は、実際には、。

sed 's/$/p/' "${LINENUMS}" | sed -n -f - "${INFILE}"

タイミング結果:146.54s user 0.18s system 100% cpu 2:26.70 total。かなり良い!

あなたがしたい場合はありません(OPをやってみたかったような)linefileから行を印刷、linenumbersがされているように、わずかにコマンドを変更日間のではなく、eleted P rinted、および印刷他のすべての行を代わりに彼らに(-n)を削除:

sed 's/$/d/' "${LINENUMS}" | sed -f - "${INFILE}"

3回目の試行(バッジ)

抽出したい行が多すぎたので、これはまったく役に立ちませんでした。ただし、(はるかに)少ない行で機能するはずですが、その制限がわかりません。

私はsedの長い文字列を作成しようとしましたが、これsedはファイルを1回だけ通過することになります(!)、文字列の行番号以外を印刷しません:

sed -n "12p;15p;24p;345p;...;12345;" ${INFILE}"

しかし、その結果、420076文字数についての文字列が生成され、sed単純にに導かれsed: Argument list is too longます。これは理解できます。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.