結論としては、以下のコマンドを使用します。
find . -name "log*" -print0 | tar -cvz -T - --null -f /tmp/log01.tar.gz
大量ファイルをtar化するときに、よく困るのはコマンド内のワイルドカードを展開した文字列が長すぎて、コマンドラインのバッファがオーバーフローして、コマンドを実行できないというもの。
例えば、
tar cvzf /hoge.tar.gz log*
などとしても、ファイル名がlogで始まるファイルが大量にあると、実行できない。list too long みたいなことを言われます。これは、ワイルドカードが展開されると、
tar cvzf /hoge.tar.gz log00001.html log00002.html ・・・・・・
などとなって、コマンド長の制限を超えるためです。
そこで、xargsコマンドを使って回避しようとするんですが、単純にはできない。
xargsコマンドは、バッファに収まる範囲にわけてコマンドを実行してくれるというもので、例えば、
find . -name "log*" | xargs tar cvzf /hoge.tar.gz
などとして利用したとします。
これは、findで引っ掛けた文字列を、バッファをオーバーしないようにtarに渡すことを期待しているんですが、これでは上手くいかない。
なぜなら、展開されると、
tar cvzf /hoge.tar.gz log00001.html log00002.html log00003.html ・・・・・
tar cvzf /hoge.tar.gz log10001.html log10002.html log10003.html ・・・・・
のようなイメージになるので、結果的に一部のファイルのみがtarで纏められてしまい、全ファイルを対象とできないんです。
ちょっと話がそれますが、findでひっかかった大量ファイルを削除するときは、上記のxargsでrmに渡せば問題ないんです。コマンドがわかれても問題ないですからね。でも、すべてのファイルを1つに纏めたいtarだと上手くいかないのです。
そこで、この問題も解決するためには、
find . -name "log*" -print0 | tar -cvz -T - --null -f /tmp/log01.tar.gz
とします。
まず、tar コマンドの -T オプションで対象ファイルの一覧を、指定したファイルから読み込むように指定します。ここでは、-T オプションの後に - を指定しているので、ファイルではなく標準入力から受け取るようにします。これはよくありますね。
で、対象ファイルの一覧を find コマンドで作るのですが、find コマンドに -print0 オプションをつけて、'\0'区切りでリストを作成します。
受け取り側の tar コマンドでは --null オプションをつけて、'\0'区切りと認識して受け取ります。
これで、find コマンドの結果を、一気に tar コマンドに渡すことができます。
人狼のログバックアップで実際に使用したときは、
find ./log \( -name "log1????.*" -o -name "log1????_?.*" \) -print0 | tar -cvz -T - --null -f /tmp/log01.tar.gz
こんな感じです。
find は ()と -o オプションで、複数条件を指定することができます。
- 関連記事
-