「tar」コマンドと「find」を組み合わせる方法


31

findコマンドは次の出力を提供します。

[root @ localhost /]#find var / log / -iname anaconda。*
var / log / anaconda.log
var / log / anaconda.xlog
var / log / anaconda.yum.log
var / log / anaconda.syslog
var / log / anaconda.program.log
var / log / anaconda.storage.log

tarと組み合わせると、次の出力が表示されます。

[root @ localhost /]#find var / log / -iname anaconda。* -exec tar -cvf file.tar {} \;
var / log / anaconda.log
var / log / anaconda.xlog
var / log / anaconda.yum.log
var / log / anaconda.syslog
var / log / anaconda.program.log
var / log / anaconda.storage.log

ただし、tarファイルを一覧表示している間、単一のファイルのみが表示されます

[root @ localhost /]#tar -tvf file.tar
-rw ------- root / root 208454 2012-02-27 12:01 var / log / anaconda.storage.log

ここで私が間違っているのは何ですか?

xargsを使用すると、この出力が得られます。

[root @ localhost /]#find var / log / -iname anaconda。* | xargs tar -cvf file1.tar

二番目の質問

varの前に/を入力find /var/logしているときに、このメサージュtarを与える理由を意味します:メンバー名から先頭の `/ 'を削除する

[root @ localhost /]#find / var / log / -iname anaconda。* -exec tar -cvf file.tar {} \;
tar:メンバー名から先頭の「/」を削除します
/var/log/anaconda.log
tar:メンバー名から先頭の「/」を削除します
/var/log/anaconda.xlog
tar:メンバー名から先頭の「/」を削除します
/var/log/anaconda.yum.log
tar:メンバー名から先頭の「/」を削除します
/var/log/anaconda.syslog
tar:メンバー名から先頭の「/」を削除します
/var/log/anaconda.program.log
tar:メンバー名から先頭の「/」を削除します
/var/log/anaconda.storage.log

簡単な形式では、次の2つの違いは何ですか?

find var/log そして find /var/log


これはセミ+オフトピックですが、findコマンドを進めていくには、検索語を引用する必要があります。時々ではなく常に機能します。
オタクウォーラー

1
あなたが使用している場合{} +の代わりに{} \;1つの引数に発見することでしょうグループの結果
ジェイソンS

回答:


39

注:やや効率的なソリューションについては、@ Iainの回答を参照してください。

見つかったすべてのファイルに対してアクションをfind呼び出すことに注意してください。-exec

tar -cvf file.tar {}単一のファイルfind出力ごとに実行する場合、これはfile.tar毎回上書きすることを意味します。これはanaconda.storage.log、最後のファイルfind出力のみを含む1つのアーカイブが残る理由を説明します。

今、あなたは実際にファイルを毎回作成するのではなく、アーカイブに追加したい(これが-cオプションの役割です)。したがって、次を使用します。

find var/log/ -iname "anaconda.*" -exec tar -rvf file.tar {} \;

この-rオプションは、毎回アーカイブを再作成するのではなく、アーカイブに追加します。

注意:交換してください-iname anaconda.*-iname "anaconda.*"。アスタリスクはワイルドカードであり、シェルによって表示れる前に展開できますfind。この展開を防ぐには、引数を二重引用符で囲みます。


tar先頭を削除する場合/:アーカイブには相対ファイル名のみを含める必要があります。先頭にを付けてファイルを追加した場合/、それらは絶対的なファイル名として保存されます/var/…。たとえば、コンピューター上での文字通りの意味です。

IIRCこれはtar、GNU以外の実装に対する単なる予防措置であり/var/…、アーカイブに相対ファイル名が含まれている場合、アーカイブを抽出するときに実際のデータを上書きしないため、この方法の方が安全です。


6
ただしtar、この方法で実際のテープアーカイブにアクセスして、一度に1つのファイルを追加し、テープを巻き戻し、最後にすべてを再読み込みすると、全体が途方もなく遅くなることに注意してください。ソリューションは、tarファイルをディスクに書き込む場合にのみ適しています。
ニコールハミルトン

2
本当ですが、この状況を安全に無視できると思います;)
slhck

@slhck *は、すべての可能性に一致するワイルドカードですか?しかし、ここではfind /var/log/ -iname anaconda*何もfind /var/log/ -iname anaconda.*出力せず、なぜ出力しますか?
最大

ワイルドカードが消費されると、それはfindもう見られなくなります。したがってanaconda*、現在のフォルダーに、たとえばanaconda5(このワイルドカードに一致する)という名前のフォルダーがある場合、ワイルドカードは展開され、代わりにfindが表示さ-iname anaconda5-iname anaconda*ます。1つ目が機能せず、2つ目が機能しない理由は、現在のディレクトリにあるファイルによって異なります。@max
slhck

2
あなたは使用することができます{} +代わりに{} \;それ意志グループ1つの引数に検索した結果
ジェイソンS

41

次のようなものを使用できます。

find var/log -iname 'anaconda.*' -print0 | tar -cvf somefile.tar --null -T -

一緒に作業スペースを改行を含むファイル名をできるようにする、など最終的には、標準入力からの入力ファイル名を読み取るためにタールを伝えます。-print0-T-

この答え-print0に従って、あなたの声明の最後に来なければならないことに注意してください。そうしないと、予想よりも多くのファイルが取得される可能性があります。


2
-nameオプションを省略したためtar、ディレクトリ全体に対するソリューションが発生しました。それがあなたが望むものであるなら、あなたはまったくtar -cvf file.tar var/log使わずに、より簡単にそれをすることができますfind
ニコールハミルトン

2
+1リストのパイピングはtar良い考えです。パス名にスペースが含まれている可能性がある場合は、間違いなく最良のソリューションです。信頼性と効率性の両方を兼ね備えているため、技術的には最高だとさえ言えます。しかし、それは両方の追加の特別な知識を必要findtar。コマンド置換がより一般的なツールであるという理由だけで、コマンド置換を好みます。一度使用する方法を学び、それをどこでも使用します。(しかし、私はWindowsでシェルを使用しているので、常に動作します。)失礼に思えた場合はおologiesび申し上げます。
ニコールハミルトン

2
既に+1を取得しています。幸せになる。:)長いコマンドラインは、どのOSでも常にプロセス作成の悩みの種です。90年代前半にMicrosoftのMark LucovskyとNTでの32K Unicode文字の制限が小さすぎると主張したことを覚えています。 。ため息。argリストが長すぎる場合のより一般的なケースの解決策は、シェル(可能であれば、私の場合はそうです)でさらに処理することxargsです。
ニコールハミルトン

9
findの-print0オプションを使用する場合は、tarの--nullオプションも必要です。
mivk 14

2
また、--no-unquoteバックスラッシュを含むファイル名は誤って処理される可能性があります。(いいえ、これは架空のものではありません。名前にバックスラッシュを含むファイル名を含む、誰かのコードからtarアーカイブを実際に作成しています。これが私が見つけた方法です。)
hvd

12

これを試して:

tar -cvf file.tar `find var/log/ -iname "anaconda.*"`

を使用しようとしていfindました-exec tar。しかし、-execオプションの動作方法は、見つかった一致するファイルごとにそのコマンドを1回実行し、そのたびtarに生成されるtarファイルを上書きします。だからこそ、最後の1つだけになってしまったのです。また、findシェルがに渡す前にシェルが展開しないように、指定するパターンを引用符で囲む必要がありますfind

バッククォートを使用したコマンド置換を使用する(または必要に$(...)応じて表記を使用する)と、によって生成される名前のリスト全体がのfind引数としてコマンドラインに貼り付けられtar、一度にすべてが書き込まれます。


2
名前にスペースが含まれている出力ファイル、改行、またはグロビング文字がある場合、find出力ファイルが不良になる可能性があります。これは失敗するはずです-stdoutからのパイプfindは、めったに良いアイデアではありません。mywiki.wooledge.org/ParsingLs
slhck

3
@ slhck、findからstdoutをパイプすることは、コメントでリンクしたページで非常に明確に説明されているように、実際には通常良いアイデアです:)。実際、これが推奨される方法です。あなただけ(のようないくつかのトリックを使用する必要がありread -rのを-print0、私は私の答えで行ったように)。
テルドン

4
@slhckこれが、UnixおよびLinuxのファイル名とディレクトリ名が伝統的に名前のスペースを避ける理由です。また、スペースを含む名前が一般的なWindowsでは、行全体(スペースを含む可能性がある)をコマンドに貼り付ける単一の単語として扱うダブルバックティックを使用して、ハミルトンCシェルにコマンド置換表記を追加しました。ライン。残念ながら、どのUnixシェルにもその機能はありません。
ニコールハミルトン

1
彼らは伝統的にそれを避けていたかもしれませんが、GUIを介してユーザー空間にファイルが作成されると、スペースのあるファイルをもう無視することはできず、それを2番目のクラスの市民として扱うことはできません(Unixであるという理由だけで)。それをシェルに含めてくれてうれしいですが、Windows用です。正しい構文を使用して適切な予防措置を講じるだけであれば、Unixシェルはその機能を特に必要としません。それが私が最初に私のコメントを投稿した理由です。
slhck

2
いいえ、しかし、他の場所では非常によく起こるかもしれません。だからこそ、防御的にプログラムすることをお勧めします。後悔するよりも安全であるべきです。また、この質問を見つけた訪問者は、必ずしもまったく同じ問題を抱えているとは限らず、ここで見つけたコマンドがこのケースでは機能しているように見えても失敗したのではないかと思うかもしれません。コマンドを修正するのはあなたにお任せします。多くの人が遅かれ早かれこの問題に遭遇するので、それを言及することが重要だと思いました。
slhck

6

質問1

tar見つかった各ファイルを取得し、それらをアーカイブしてfile.tarいるため、コマンドは失敗します。そうするたびに、以前に作成されたが上書きされfile.tarます。

必要なものがすべてのファイルを含む1つのアーカイブであり、単純にtar直接実行する場合、必要はありませんfind(そして、はい、名前にスペースが含まれるファイルに対して機能します)。

tar -vcf file.tar /var/log/anaconda*   

質問2

2つのコマンドは完全に異なります。

  • find var / logはvar/log 、現在のディレクトリのサブディレクトリであるというディレクトリを検索します。これはfind ./var/log(に注意./)と同等です。

  • find / var / logは/var/log 、ルートのサブディレクトリであるというディレクトリを/検索します。

主要な/メッセージはからでありtar、ではありませんfind。これは、絶対パスを相対パスに/するために最初のファイル名を削除することを意味します。これは、アーカイブを展開するときにからファイルが抽出されることを意味します。/var/log/anaconda.error./var/log/anaconda.error


1

-exec動作する方法は2つあります。1つの方法でコマンドを何度も実行します-各ファイルに1回。他の方法では、すべてのファイルをパラメーターのリストとして含めて、コマンドを1回実行します。

  • -exec tar -cvf file.tar {} ';'tar各ファイルに対してコマンドを実行し、毎回アーカイブを上書きします。
  • -exec tar -cvf file.tar {} '+'tarコマンドを1回実行し、見つかったすべてのファイルのアーカイブを作成します。

1

多くのファイルがある場合、各ファイルに-execを使用すると、tar圧縮が非常に遅くなると思います。私はコマンドを使用することを好みます:

find . -iname "*.jpg" | cpio -ov -H tar -F jpgs.tar

失敗し始めるまで/bin/cpio: xxx: Cannot open: Too many open files
SYN
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.