Bashスクリプトを使って巨大なテキストファイルから最初の行を繰り返し削除する必要があります。
今私はsed -i -e "1d" $FILE
を使用しています - しかし削除には1分ほどかかります。
これを達成するためのより効率的な方法はありますか?
tail :を試してください。
tail -n +2 "$FILE"
-n x
:最後のx
行を印刷するだけです。 tail -n 5
はあなたに入力の最後の5行を与えるでしょう。 +
記号は引数を反転し、tail
に最初のx-1
行以外のものを表示させます。 tail -n +1
はファイル全体を印刷し、tail -n +2
は最初の行を除くすべてを印刷します。
GNU tail
はsed
よりはるかに速いです。 tail
はBSDでも利用可能で、-n +2
フラグは両方のツールで一貫しています。詳しくは FreeBSD または OS X のmanページをチェックしてください。
BSD版はsed
よりずっと遅くなる可能性があります。彼らがどうやってそれを管理したのかしら。 tail
はファイルを1行ずつ読み込むだけですが、sed
はスクリプトの解釈、正規表現の適用など、かなり複雑な操作を行います。
注意:あなたは使いたくなるかもしれません
# THIS WILL GIVE YOU AN EMPTY FILE!
tail -n +2 "$FILE" > "$FILE"
しかしこれはあなたに 空のファイル を与えるでしょう。これは、シェルによってtail
が呼び出される前にリダイレクト(>
)が行われるためです。
$FILE
を切り捨てますtail
の新しいプロセスを作成しますtail
プロセスの標準出力を$FILE
にリダイレクトしますtail
は今空の$FILE
から読み込みますファイル内の最初の行を削除したい場合は、次のようにします。
tail -n +2 "$FILE" > "$FILE.tmp" && mv "$FILE.tmp" "$FILE"
&&
は問題があるときにファイルが上書きされないようにします。
'>'演算子を使用せずにファイルを更新するには、-iを使用できます。次のコマンドは、ファイルから最初の行を削除してファイルに保存します。
sed -i '1d' filename
非GNUのSunOSを使っている人のために、以下のコードが役立ちます。
sed '1d' test.dat > tmp.dat
いいえ、それはあなたが得ようとしているのと同じくらい効率的です。あなたは少し速く仕事をすることができるCプログラムを書くことができます(より少ない起動時間と処理引数)しかしそれはおそらくファイルが大きくなるにつれてsedと同じ速度に向かうでしょう).
しかし、あなたの質問はそれが解決策を前提としているという点で他の多くの人と同じ問題に苦しんでいます。 how ではなく what で詳細を教えてもらえれば、より良いオプションを提案できるかもしれません。
たとえば、これが他のプログラムBが処理するファイルAである場合、1つの解決策は最初の行を削除せずにプログラムBを変更して別の方法で処理することです。
すべてのプログラムがこのファイルAに追加され、プログラムBが現在最初の行を読み込んで処理してから削除するとします。
最初の行を削除するのではなく、ファイルAへの永続的な(おそらくファイルベースの)オフセットを維持するようにプログラムBを再設計することができます。その行をクリックし、オフセットを更新します。
それから、静かな時間(真夜中?)に、現在処理されているすべての行を削除してオフセットを0に戻すためにファイルAの特別な処理を行うことができます。
プログラムが開いて書き換えるよりもファイルを開いて探す方が確実に速いでしょう。この議論はもちろんあなたがプログラムBを管理していると仮定します。それが当てはまるかどうかはわかりませんが、さらに情報を提供していただければ、他に解決策があるかもしれません。
あなたは can ファイルを適切に編集することができます:Perlの-i
フラグを使うだけです。
Perl -ni -e 'print unless $. == 1' filename.txt
あなたが尋ねるように、これは最初の行を消します。 Perlはファイル全体を読み込んでコピーする必要がありますが、出力が元のファイルの名前で保存されるようにします。
Paxが言ったように、あなたはおそらくこれ以上速くなることはないでしょう。その理由は、ファイルの先頭からの切り捨てをサポートするファイルシステムがほとんどないため、これがO(n
)操作になることです。ここで、n
はファイルのサイズです。あなたができること ずっと より速いですが、正確にあなたがやろうとしていることに依存してあなたのために働くかもしれない同じバイト数で最初の行を上書きする(多分スペースまたはコメント)。方法?)。
ファイルを所定の場所で変更する場合は、s treaming successor ed
の代わりに、常に元のsed
を使用できます。
ed "$FILE" <<<$'1d\nwq\n'
ed
コマンドはオリジナルのUNIXテキストエディターでしたが、以前はフルスクリーン端末でさえあり、グラフィカルワークステーションはほとんどありませんでした。 ex
のコロンプロンプトで入力する際に使用するものとして最もよく知られているvi
エディターは、extendedバージョンのed
です。同じコマンドが機能します。 ed
は対話的に使用することを目的としていますが、コマンド文字列を送信することでバッチモードで使用することもできます。これがこのソリューションの機能です。
シーケンス<<<$'1d\nwq\n'
は、ヒア文字列(<<<
)およびPOSIX引用符($'
...'
)に対するBashのサポートを利用して、入力からed
コマンドに入力します。 2行:1d
、これはd eletes行1、そしてwq
、これはwファイルをディスクに書き込み、その後、q uits編集セッション。
sponge
util は一時ファイルをジャグリングする必要性を回避します。
tail -n +2 "$FILE" | sponge "$FILE"
これを行うにはvimを使用できます。
vim -u NONE +'1d' +'wq!' /tmp/test.txt
Vimは処理時にファイル全体を読み込まないので、これはもっと速いはずです。
Csplitはどうですか?
man csplit
csplit -k file 1 '{1}'
最初の行以外の行を表示します。
cat textfile.txt | tail -n +2
あなたは簡単にこれを行うことができます:
cat filename | sed 1d > filename_without_first_line
コマンドラインで。ファイルの最初の行を完全に削除するには、-i
フラグを付けてsedのインプレースモードを使用します。
sed -i 1d <filename>
削除のスピードを上げることはできないようですが、ファイルを次のようにまとめて処理することをお勧めします。
While file1 not empty
file2 = head -n1000 file1
process file2
sed -i -e "1000d" file1
end
この欠点は、プログラムが途中で強制終了された場合(またはそこに何らかの悪いSQLがあり、 "process"部分が消滅したりロックされたりする)、行がスキップされるか2回処理されることです。 。
(file1はSQLコードの行を含みます)
あなたがしたいことが失敗の後に回復することであるならば、あなたは今までのところあなたがしたことを持っているファイルを構築することができます。
if [[ -f $tmpf ]] ; then
rm -f $tmpf
fi
cat $srcf |
while read line ; do
# process line
echo "$line" >> $tmpf
done