ファイルの最初の行を削除する方が速いのは…sedとtailのどちらですか?


14

この回答(sedを使用してファイルの最初の行を削除するにはどうすればよいですか?)では、ファイルの最初のレコードを削除する2つの方法があります。

sed '1d' $file >> headerless.txt

** ----------------または---------------- **

tail -n +2 $file >> headerless.txt

個人的には、このtailオプションは見た目が楽しく、読みやすいと思いますが、おそらく私はセドに挑戦しているからでしょう。

どの方法が最速ですか?


5
答えではありませんが、考えられる考慮事項は、sedより移植性が高いことです。GNU tailを使用するUbuntuで正常に動作する「+2」ですtailが、BSDでは動作しませんtail
ジョンN

@JohnN tailは、クロスプラットフォームの互換性の欠如を共有してくれてありがとう。
WinEunuuchs2Unix

3
尾はBSDのtailコマンドを使用する請求シエラを実行している5月のMac上で罰金を働くための@ジョンN「2」
ニックSillito

ウル、あなたはまったく正しいです-私はちょうどそれを再実行し、今回は入力をチェックしました。初めてやるべきだった。それもPOSIXです。/ slinks off、恥ずかしい。
ジョンN

2
@JohnNあなたは完全に間違っていません。過去には、UNIXは-nオプションを提供せず、構文を使用していましたtail +2 $filefreebsd.org/cgi/を参照してください現代のBSDの1つではなく、そのことを考えていた可能性があります。
hvd 16

回答:


28

sedvs.のパフォーマンスtail、ファイルの最初の行を削除する

TL; DR

  • sed は非常に強力で汎用性がありますが、これが、特に多くの行を含む大きなファイルの場合、それを遅くするものです。

  • tail 単純なことを1つだけ実行しますが、その1つは、多くの行がある大きなファイルに対しても、適切かつ高速に実行します。

中小ファイルの場合、sedおよびtail(あなたの期待に応じて、または遅い)速い同様に行っています。ただし、大きな入力ファイル(複数のMB)の場合、パフォーマンスの差は大幅に大きくなり(数百MBの範囲のファイルでは1桁)、tail明らかにパフォーマンスが向上しますsed

実験

一般的な準備:

分析するコマンドは次のとおりです。

sed '1d' testfile > /dev/null
tail -n +2 testfile > /dev/null

/dev/nullパフォーマンスのボトルネックとしての端末出力またはファイル書き込みをなくすために、毎回出力をパイピングしていることに注意してください。

RAMディスクをセットアップして、潜在的なボトルネックとしてのディスクI / Oを排除しましょう。私は個人的にtmpfsマウントされている/tmpのでtestfile、この実験のためにそこに置いただけです。

次に、$numoflinesこのコマンドを使用して、ランダムな行の長さとランダムなデータを含む指定された量の行を含むランダムなテストファイルを作成します(これは明らかに最適ではなく、約200万行を超えると本当に遅くなりますが、私たちが分析しているもの):

cat /dev/urandom | base64 -w0 | tr 'n' '\n'| head -n "$numoflines" > testfile

ああ、ところで。私のテスト用ラップトップは、Intel i5-6200U CPU上で64ビットのUbuntu 16.04を実行しています。比較のためだけに。

大きなファイルのタイミング:

巨大なセットアップtestfile

上記のコマンドを実行して、10 numoflines=10000000MBの行を含むランダムファイルを生成し、600 MBを少し超えて占有します-それは非常に巨大ですが、次のことができるので、始めましょう。

$ wc -l testfile 
10000000 testfile

$ du -h testfile 
611M    testfile

$ head -n 3 testfile 
qOWrzWppWJxx0e59o2uuvkrfjQbzos8Z0RWcCQPMGFPueRKqoy1mpgjHcSgtsRXLrZ8S4CU8w6O6pxkKa3JbJD7QNyiHb4o95TSKkdTBYs8uUOCRKPu6BbvG
NklpTCRzUgZK
O/lcQwmJXl1CGr5vQAbpM7TRNkx6XusYrO

私たちのhugeで時限実行を実行しますtestfile

では、まず両方のコマンドを使用して1回だけ実行し、どの程度の大きさで作業しているかを推定しましょう。

$ time sed '1d' testfile > /dev/null
real    0m2.104s
user    0m1.944s
sys     0m0.156s

$ time tail -n +2 testfile > /dev/null
real    0m0.181s
user    0m0.044s
sys     0m0.132s

我々はすでに、大きなファイルのために本当に明確な結果を参照してくださいtail大きさよりも高速ですsed。ただし、楽しみのために、また大きな違いをもたらすランダムな副作用がないことを確認するために、100回行ってみましょう。

$ time for i in {1..100}; do sed '1d' testfile > /dev/null; done
real    3m36.756s
user    3m19.756s
sys     0m15.792s

$ time for i in {1..100}; do tail -n +2 testfile > /dev/null; done
real    0m14.573s
user    0m1.876s
sys     0m12.420s

結論は同じままsedで、大きなファイルの最初の行を削除するには非効率的であり、tailそこで使用する必要があります。

そして、はい、Bashのループ構造が遅いことはわかっていますが、ここでは比較的少数の反復しか行っておらず、とにかくsed/ tailランタイムに比べて単純なループにかかる時間は重要ではありません。

小さなファイルのタイミング:

小さなセットアップtestfile

完全を期すために、kBの範囲に小さな入力ファイルがあるというより一般的なケースを見てみましょう。のようなランダムな入力ファイルを作成しましょうnumoflines=100

$ wc -l testfile 
100 testfile

$ du -h testfile 
8,0K    testfile

$ head -n 3 testfile 
tYMWxhi7GqV0DjWd
pemd0y3NgfBK4G4ho/
aItY/8crld2tZvsU5ly

私たちの小さなもので時限実行を実行しますtestfile

このような小さなファイルのタイミングは経験から数ミリ秒の範囲にあると予想できるため、すぐに1000回の反復を実行してみましょう。

$ time for i in {1..1000}; do sed '1d' testfile > /dev/null; done
real    0m7.811s
user    0m0.412s
sys     0m7.020s

$ time for i in {1..1000}; do tail -n +2 testfile > /dev/null; done
real    0m7.485s
user    0m0.292s
sys     0m6.020s

ご覧のように、タイミングは非常に似ており、解釈したり疑問に思うことはあまりありません。小さいファイルの場合、両方のツールが同様に適しています。


+1回答ありがとうございます。私awkもこれを行うことができますセルグからのコメントに基づいて、元の質問(ごめん)を編集しました。私の最初の質問は、最初に見つけたリンクに基づいていました。すべてのハードワークしてくださいアドバイスの後、私は削除する必要がある場合awkのみの元のプロジェクトのスコープを解決候補とリターン焦点としてsedtail
WinEunuuchs2Unix 16

これはどのシステムですか?私のMac(BSDツール)では、/ usr / share / dict / wordsでテストすると、sedで0.09秒、tailで0.19秒(そしてawk 'NR > 1'興味深いことに)が得られます。
ケビン

5

bashビルトインとcat

{ read ; cat > headerless.txt; } < $file

$file{ }コマンドのグループにリダイレクトされます。read単に最初の行を読み取り、破棄します。次に、ストリームの残りの部分がパイプさcatれて、宛先ファイルに書き込まれます。

私のUbuntu 16.04では、これとtailソリューションのパフォーマンスは非常に似ています。私は次のように大きなテストファイルを作成しましたseq

$ seq 100000000 > 100M.txt
$ ls -l 100M.txt 
-rw-rw-r-- 1 ubuntu ubuntu 888888898 Dec 20 17:04 100M.txt
$

tail 解決:

$ time tail -n +2 100M.txt > headerless.txt

real    0m1.469s
user    0m0.052s
sys 0m0.784s
$ 

cat/ブレースソリューション:

$ time { read ; cat > headerless.txt; } < 100M.txt 

real    0m1.877s
user    0m0.000s
sys 0m0.736s
$ 

ただ、今のところ便利なのはUbuntu VMだけです。両方とも同じ球場にいますが、両方のタイミングに大きな違いがあります。


1
+1の回答ありがとうございます。これは非常に興味深い解決策であり、bashの階層順序による中括弧と右から左への読み取りが大好きです。(私がそれを正しく言ったかどうかわからない)。入力ファイルのサイズとタイミングベンチマークの結果で答えを更新することは可能ですか?
WinEunuuchs2Unix 16

@ WinEunuuchs2Unix Timingsが追加されましたが、VM上にあるため、信頼性はそれほど高くありません。現在、ベアメタルのUbuntuインストールは手元にありません。
デジタル外傷

とにかくVMとVMを比較するとき、VM対Bare Metalは重要ではないと思います。タイミングの証拠をありがとう。私はおそらく一緒に行くだろうがtail、それでもこのreadオプションはとてもクールだと思う。
WinEunuuchs2Unix 16

4

私のシステムで試して、各コマンドの前timeに次の結果が得られました:

sed:

real    0m0.129s
user    0m0.012s
sys     0m0.000s

と尾:

real    0m0.003s
user    0m0.000s
sys     0m0.000s

これは、Ubuntu 16.04を実行している少なくともAMD FX 8250のシステムでは、tailが大幅に高速であることを示唆しています。テストファイルには、サイズが540kの10,000行がありました。ファイルはHDDから読み取られました。


+1回答ありがとうございます。AU Chatroomでの別のテストでは、61 MBのファイルを含むRAMDiskを使用したsed(21.86秒)の10倍の速さ(2.31秒)を示したユーザーがいました。コードブロックを適用するために回答を編集しましたが、使用したファイルサイズで編集することもできます。
WinEunuuchs2Unix 16

これが唯一の事例の答えであり、潜在的にあなたが異なるハードウェア構成、異なるテストファイルなどと異なる結果になるだろうということ@Serg絶対に公正
ニックSillito

2
キャッシュにないファイル、使用しているときは、sedあなたがそれらをテストしているためです。この結果の要因を、再生することがあります。
Minixの

どんなシステム?ここで別の投稿でコメントしたように、私のMac sedでは約2倍の速さでした。
ケビン

1

プログラムの実行中にシステムで実行されるのは、それだけではないためsed、どちらが優れているかを客観的に示す方法tailはありません。ディスクI / O、ネットワークI / O、優先度の高いプロセスのCPU割り込みなど、多くの要素がプログラムの実行速度に影響します。

どちらもCで書かれているため、これは言語の問題ではなく、環境の問題です。たとえば、SSDを使用しており、システム上ではマイクロ秒単位で時間がかかりますが、HDDの速度が大幅に遅いため、ハードドライブ上の同じファイルの場合は時間がかかります。したがって、これでもハードウェアが役割を果たします。

どのコマンドを選択するかを検討する際に留意すべきことがいくつかあります。

  • あなたの目的はなんですか ?sedテキストを変換するためのストリームエディターです。tail特定のテキスト行を出力するためのものです。行を処理し、それらを印刷するだけの場合は、を使用しますtail。テキストを編集する場合は、を使用しますsed
  • tailの構文ははるかに単純なのでsed、自分で読めるものと他の人が読めるものを使用してください。

もう1つの重要な要素は、処理しているデータの量です。小さなファイルを使用しても、パフォーマンスに違いはありません。大きなファイルを処理している場合、この画像は興味深いものになります。2 GBのBIGFILE.txtを使用すると、のsedシステムコールよりもはるかに多くのシステムコールがtailあり、実行速度がかなり遅いことがわかります。

bash-4.3$ du -sh BIGFILE.txt 
2.0G    BIGFILE.txt
bash-4.3$ strace -c  sed '1d' ./BIGFILE.txt  > /dev/null
% time     seconds  usecs/call     calls    errors syscall
------ ----------- ----------- --------- --------- ----------------
 59.38    0.079781           0    517051           read
 40.62    0.054570           0    517042           write
  0.00    0.000000           0        10         1 open
  0.00    0.000000           0        11           close
  0.00    0.000000           0        10           fstat
  0.00    0.000000           0        19           mmap
  0.00    0.000000           0        12           mprotect
  0.00    0.000000           0         1           munmap
  0.00    0.000000           0         3           brk
  0.00    0.000000           0         2           rt_sigaction
  0.00    0.000000           0         1           rt_sigprocmask
  0.00    0.000000           0         1         1 ioctl
  0.00    0.000000           0         7         7 access
  0.00    0.000000           0         1           execve
  0.00    0.000000           0         1           getrlimit
  0.00    0.000000           0         2         2 statfs
  0.00    0.000000           0         1           arch_prctl
  0.00    0.000000           0         1           set_tid_address
  0.00    0.000000           0         1           set_robust_list
------ ----------- ----------- --------- --------- ----------------
100.00    0.134351               1034177        11 total
bash-4.3$ strace -c  tail  -n +2 ./BIGFILE.txt  > /dev/null
% time     seconds  usecs/call     calls    errors syscall
------ ----------- ----------- --------- --------- ----------------
 62.30    0.148821           0    517042           write
 37.70    0.090044           0    258525           read
  0.00    0.000000           0         9         3 open
  0.00    0.000000           0         8           close
  0.00    0.000000           0         7           fstat
  0.00    0.000000           0        10           mmap
  0.00    0.000000           0         4           mprotect
  0.00    0.000000           0         1           munmap
  0.00    0.000000           0         3           brk
  0.00    0.000000           0         1         1 ioctl
  0.00    0.000000           0         3         3 access
  0.00    0.000000           0         1           execve
  0.00    0.000000           0         1           arch_prctl
------ ----------- ----------- --------- --------- ----------------
100.00    0.238865                775615         7 total

+1回答ありがとうございます。しかし、私は確かにこのコメントが....私は使うべきコマンドかを決める助けていないんだけど
WinEunuuchs2Unix

@ WinEunuuchs2Unixさて、あなたはどちらのコマンドの方が良いかを尋ねたので、私はまさにその質問に答えています。どのコマンドを選択するかはあなた次第です。あなたがtailより良く読むことができるならsed-それを使用してください。私は個人的に使用するpythonか、awkむしろsed複雑になる可能性があるためです。さらに、パフォーマンスに不安がある場合は、現実に直面しましょう。ここでは、マイクロ秒単位で結果が表示されます。あなたが
読み込も

ああ、私awkも答えをいただければ幸いです:)...私の質問は別のAU Q&A(リンク内)に基づいており、そこで言及されawkたことはありません。小さなファイルでは時間差がわずかであることに同意します。私はちょうど良い習慣を身につけようとしていました。
WinEunuuchs2Unix 16

1
@ WinEunuuchs2Unix確かに、ここにありますawk 'NR!=1' input_file.txt 。それは私に等しく同じ結果を与えます、およそ150ミリ秒、両方の同じ数tailsed。しかし、AgianはSSDを使用しているので、コマンドではなく、ハードドライブとCPUが重要だと思います。
セルギーコロディアズニー16

1
@Sergは、100万行を含む60 MBのファイルでさえ、1000 sed分で3分以上かかりtailますが、約20秒しかかかりません。それはないこと GBの範囲で間違いなく、まだ実際には大きくはありません。
バイトコマンダー

1

トップアンサーはディスクを考慮していませんでした > /dev/null

大きなファイルがあり、ディスク上に一時的な複製を作成したくない場合は、試してください vim -c

$ cat /dev/urandom | base64 -w0 | tr 'n' '\n'| head -n 10000000 > testfile
$ time sed -i '1d' testfile

real    0m59.053s
user    0m9.625s
sys     0m48.952s

$ cat /dev/urandom | base64 -w0 | tr 'n' '\n'| head -n 10000000 > testfile
$ time vim -e -s testfile -c ':1d' -c ':wq'

real    0m8.259s
user    0m3.640s
sys     0m3.093s

編集:ファイルが利用可能なメモリよりも大きい場合は動作vim -cしません、ファイルの増分ロードを行うには十分にスマートではないように見えます


0

他の答えは、最初の行が欠落している新しいファイルを作成する方が良いことを示しています。ただし、新しいファイルを作成するのではなく、ファイルを編集する場合はed、新しいファイルをまったく作成しないため、より高速になります。しかし、行をed一度だけ使用したため、行を削除する方法を検索する必要があります。

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