web-dev-qa-db-ja.com

Bash/sedスクリプトを使用してテキストファイルの最初の行を削除する方法を教えてください。

Bashスクリプトを使って巨大なテキストファイルから最初の行を繰り返し削除する必要があります。

今私はsed -i -e "1d" $FILEを使用しています - しかし削除には1分ほどかかります。

これを達成するためのより効率的な方法はありますか?

470
Brent

tail :を試してください。

tail -n +2 "$FILE"

-n x:最後のx行を印刷するだけです。 tail -n 5はあなたに入力の最後の5行を与えるでしょう。 +記号は引数を反転し、tailに最初のx-1行以外のものを表示させます。 tail -n +1はファイル全体を印刷し、tail -n +2は最初の行を除くすべてを印刷します。

GNU tailsedよりはるかに速いです。 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が呼び出される前にリダイレクト(>)が行われるためです。

  1. シェルはファイル$FILEを切り捨てます
  2. シェルがtailの新しいプロセスを作成します
  3. シェルはtailプロセスの標準出力を$FILEにリダイレクトします
  4. tailは今空の$FILEから読み込みます

ファイル内の最初の行を削除したい場合は、次のようにします。

tail -n +2 "$FILE" > "$FILE.tmp" && mv "$FILE.tmp" "$FILE"

&&は問題があるときにファイルが上書きされないようにします。

891
Aaron Digulla

'>'演算子を使用せずにファイルを更新するには、-iを使用できます。次のコマンドは、ファイルから最初の行を削除してファイルに保存します。

sed -i '1d' filename
130
amit

非GNUのSunOSを使っている人のために、以下のコードが役立ちます。

sed '1d' test.dat > tmp.dat 
69
Nasri Najib

いいえ、それはあなたが得ようとしているのと同じくらい効率的です。あなたは少し速く仕事をすることができるCプログラムを書くことができます(より少ない起動時間と処理引数)しかしそれはおそらくファイルが大きくなるにつれてsedと同じ速度に向かうでしょう).

しかし、あなたの質問はそれが解決策を前提としているという点で他の多くの人と同じ問題に苦しんでいます。 how ではなく what で詳細を教えてもらえれば、より良いオプションを提案できるかもしれません。

たとえば、これが他のプログラムBが処理するファイルAである場合、1つの解決策は最初の行を削除せずにプログラムBを変更して別の方法で処理することです。

すべてのプログラムがこのファイルAに追加され、プログラムBが現在最初の行を読み込んで処理してから削除するとします。

最初の行を削除するのではなく、ファイルAへの永続的な(おそらくファイルベースの)オフセットを維持するようにプログラムBを再設計することができます。その行をクリックし、オフセットを更新します。

それから、静かな時間(真夜中?)に、現在処理されているすべての行を削除してオフセットを0に戻すためにファイルAの特別な処理を行うことができます。

プログラムが開いて書き換えるよりもファイルを開いて探す方が確実に速いでしょう。この議論はもちろんあなたがプログラムBを管理していると仮定します。それが当てはまるかどうかはわかりませんが、さらに情報を提供していただければ、他に解決策があるかもしれません。

17
paxdiablo

あなたは can ファイルを適切に編集することができます:Perlの-iフラグを使うだけです。

Perl -ni -e 'print unless $. == 1' filename.txt

あなたが尋ねるように、これは最初の行を消します。 Perlはファイル全体を読み込んでコピーする必要がありますが、出力が元のファイルの名前で保存されるようにします。

11
alexis

Paxが言ったように、あなたはおそらくこれ以上速くなることはないでしょう。その理由は、ファイルの先頭からの切り捨てをサポートするファイルシステムがほとんどないため、これがO(n)操作になることです。ここで、nはファイルのサイズです。あなたができること ずっと より速いですが、正確にあなたがやろうとしていることに依存してあなたのために働くかもしれない同じバイト数で最初の行を上書きする(多分スペースまたはコメント)。方法?)。

9
Robert Gamble

ファイルを所定の場所で変更する場合は、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編集セッション。

8
Mark Reed

spongeutil は一時ファイルをジャグリングする必要性を回避します。

tail -n +2 "$FILE" | sponge "$FILE"
7
agc

これを行うにはvimを使用できます。

vim -u NONE +'1d' +'wq!' /tmp/test.txt

Vimは処理時にファイル全体を読み込まないので、これはもっと速いはずです。

5
Hongbo Liu

Csplitはどうですか?

man csplit
csplit -k file 1 '{1}'
4
crydo

最初の行以外の行を表示します。

cat textfile.txt | tail -n +2
3
serup

あなたは簡単にこれを行うことができます:

cat filename | sed 1d > filename_without_first_line

コマンドラインで。ファイルの最初の行を完全に削除するには、-iフラグを付けてsedのインプレースモードを使用します。

sed -i 1d <filename>
3
Ingo Baab

削除のスピードを上げることはできないようですが、ファイルを次のようにまとめて処理することをお勧めします。

While file1 not empty
  file2 = head -n1000 file1
  process file2
  sed -i -e "1000d" file1
end

この欠点は、プログラムが途中で強制終了された場合(またはそこに何らかの悪いSQLがあり、 "process"部分が消滅したりロックされたりする)、行がスキップされるか2回処理されることです。 。

(file1はSQLコードの行を含みます)

1
Brent

あなたがしたいことが失敗の後に回復することであるならば、あなたは今までのところあなたがしたことを持っているファイルを構築することができます。

if [[ -f $tmpf ]] ; then
    rm -f $tmpf
fi
cat $srcf |
    while read line ; do
        # process line
        echo "$line" >> $tmpf
    done
0
Tim