web-dev-qa-db-ja.com

巨大なファイルの最初と最後に行を追加します

巨大なファイルの最初と最後に行を追加するシナリオがあります。

以下のようにしてみました。

  • 最初の行:

    sed -i '1i\'"$FirstLine" $Filename
    
  • 最後の行:

    sed -i '$ a\'"$Lastline" $Filename  
    

しかし、このコマンドの問題は、ファイルの最初の行を追加し、ファイル全体をトラバースすることです。最後の行では、再びファイル全体を走査し、最後の行を追加しています。非常に大きなファイル(14GB)なので、これには非常に長い時間がかかります。

ファイルを1回だけ読み取るときに、ファイルの最初と最後に行を追加するにはどうすればよいですか?

24
UNIXbest

sed -iは、実装の詳細として一時ファイルを使用しています。これは、実際に発生していることです。ただし、既存のコンテンツを上書きせずにデータストリームの先頭にデータを追加するには、ファイルを書き換える必要があります。sed -iを回避したとしても、それを回避する方法はありません。

ファイルの再書き込みができない場合は、次のように、ファイルを読み取るときに操作することを検討してください。

{ echo some prepended text ; cat file ; } | command

また、sedはストリームの編集用です-ファイルはストリームではありません。 edやexなど、この目的のためのプログラムを使用してください。 sedの-iオプションは移植性が高いだけでなく、基本的にファイルを削除して再作成するため、ファイルへのシンボリックリンクも破壊されますが、これは無意味です。

次のように、edを使用して単一のコマンドでこれを行うことができます。

ed -s file << 'EOF'
0a
prepend these lines
to the beginning
.
$a
append these lines
to the end
.
w
EOF

Edの実装によっては、ページングファイルを使用する場合があるため、少なくとも使用可能なスペースを確保する必要があることに注意してください。

22
Chris Down

ファイルのコピー全体をディスクに割り当てないようにする場合は、次のようにすることができます。

sed '
1i\
begin
$a\
end' < file 1<> file

これは、そのstdin/stdoutがファイルの場合、sedがブロックごとに読み書きするという事実を利用しています。したがって、ここでは、追加する最初の行がsedのブロックサイズ(4kまたは8kのようなもの)より小さい限り、読み取っているファイルを上書きしても問題ありません。

なんらかの理由でsedが失敗した場合(強制終了、マシンクラッシュ...)、ファイルが半分処理されることに注意してください。これは、途中のどこかで最初の行のサイズのデータ​​が欠落していることを意味します。

また、sedがGNU sedでない限り、バイナリデータでは機能しません(ただし、-i、GNU sed)を使用しています。

9

ここにいくつかの選択肢があります(すべてがファイルの新しいコピーを作成するので、そのための十分なスペースがあることを確認してください):

  • シンプルなエコー/猫

    echo "first" > new_file; cat $File >> new_file; \
      echo "last" >> new_file; 
    
  • awk/gawkなど

    gawk 'BEGIN{print "first\n"}{print}END{print "last\n"}' $File > NewFile 
    

    awkとそのilkは、ファイルを1行ずつ読み取ります。 BEGIN{}ブロックは最初の行の前に実行され、END{}ブロックは最後の行の後に実行されます。したがって、上記のコマンドはprint "first" at the beginning, then print every line in the file and print "last" at the endを意味します。

  • Perl

    Perl -ne 'BEGIN{print "first\n"} print;END{print "last\n"}' $File > NewFile
    

    これは基本的に、Perlで記述された上記のgawkと同じです。

4
terdon

私はずっと単純なほうを好みます:

gsed -i '1s/^/foo\n/gm; $s/$/\nbar/gm' filename.txt

これはファイルを変換します:

asdf
qwer

ファイルへ:

foo
asdf
qwer
bar
3
CommaToast

ファイルの先頭にデータを挿入する方法はありません。新しいファイルを作成し、追加のデータを書き込んで、古いデータを追加するだけです。したがって、最初の行を挿入するには、ファイル全体を少なくとも1回書き換える必要があります。ただし、ファイルを書き換えずに最後の行を追加できます。

sed -i '1i\'"$FirstLine" $Filename
echo "$LastLine" >>$Filename

または、sedの1回の実行で2つのコマンドを組み合わせることができます。

sed -i -e '1i\'"$FirstLine" -e '$ a\'"$Lastline" $Filename

sed -iは新しい出力ファイルを作成し、それを古いファイルの上に移動します。これは、sedが動作している間、スペースを使い切ったファイルの2番目のコピーがあることを意味します。これは ファイルを上書きする で回避できますが、大きな制限があります。追加する行はsedのバッファーよりも小さくする必要があり、システムがクラッシュした場合、結果として破損します。ファイルと一部のコンテンツが途中で失われるので、これはお勧めしません。

¹ Linuxにはデータをファイルに挿入する方法はありますが、挿入できるのはファイルシステムブロックの整数だけであり、任意の長さの文字列を挿入することはできません。データベースや仮想マシンなどの一部のアプリケーションには役立ちますが、テキストファイルには役に立ちません。

VimはExモードで使用できます。

ex -sc '1i|ALFA' -c '$a|BRAVO' -cx file
  1. 1最初の行を選択

  2. iテキストと改行を挿入

  3. $最後の行を選択

  4. aテキストと改行を追加

  5. x保存して閉じる

2
Steven Penny
$ (echo "Some Text" ; cat file1) > file2
0