tarファイルの抽出の混乱を元に戻す


34

整理整頓されたディレクトリに大量のファイルを生成するアーカイブを展開しました。例えば:

user@comp:~/tidy$ tar xvf myarchive.tar
file1
file2
dir1/
dir1/file1
dir1/subdir1/
dir1/subdir1/file1
dir2/
dir2/file1
...

私は、tarファイルが単一のフォルダー(つまりmyarchive/)に整理されることを期待していましたが、そうではありませんでした!今、私は組織化されたディレクトリであったものにデジタル的にfされた190のファイルとディレクトリを持っています。これらの解凍されたファイルはクリーンアップする必要があります。

これを「取り消し」、このアーカイブから抽出されたファイルとディレクトリを削除する方法はありますか?


以下の優れた回答をありがとう。要約すると、2つのステップ(1)ファイルの削除、(2)空のディレクトリ構造の逆パッキング順での削除(最初に外部ディレクトリを削除する)で機能するものは次のとおりです。

tar tf myarchive.tar | xargs -d'\n' rm
tar tf myarchive.tar | tac | xargs -d'\n' rmdir

さらに安全なのは、echoafter を追加してコマンドのドライランをプレビューすることxargsです。


アーカイブ内のファイルを一覧表示して現在のディレクトリから削除することはできますが、データが破壊される可能性があると感じます(保持するデータ)。また、bashスクリプトの書き方もわからないので、そこでは仕方がありません。
ボブ

幸いなことに、何も上書きされませんでした!
マイクT

私は担当者の後ではなく、これをどのように置いても不機嫌そうに聞こえますが、私はそうではありません(私はshlckの答えも好きで、それを+1しました、そして正直に:±15担当者は私の世界ではありません)、しかし、あなたはパイプで私の提案された答えを使用することになりますxargs(単なる化粧品のtac代わりにsort -r)が、コメントで説明したように、あなたに合わなかったプロセス置換で答えを受け入れますか?また、xargs -d'\n'将来のユーザーのために要約したい場合は、投稿でスイッチを指定してください。そうすれば、ファイル名にスペースが含まれることはありません。
ダニエルアンダーソン

@DanielAndersson、私は-d'\n'今までの必要性を理解していませんでしたが、さらに分析すると、あなたの答えは実際に私が使用したものに近くなります。
マイクT

@Danielのソリューションも気に入っています:)改行の引数を分割する-d'\n'ように指示しない場合xargs(これがフィードの内容です)、スペースの場合は、名前はfolder1/some fileとして読まれますfolder1/somename
-slhck

回答:


36
tar tf archive.tar

コンテンツを1行ずつリストします。

これはxargs直接パイプすることができますが、注意してください:削除は慎重に行ってください。あなたはしていないだけにしたいrm -rすべてのものtar tf、それは開梱する前に空にされていないディレクトリが含まれる場合がありますので、あなたに伝えます!

できる

tar tf archive.tar | xargs -d'\n' rm -v
tar tf archive.tar | sort -r | xargs -d'\n' rmdir -v

最初にアーカイブ内のすべてのファイルを削除し、次に空のままのディレクトリを削除します。

sort -r(最も深いディレクトリを最初に削除するには、受け入れられた回答へのコメントのtac代わりにglennjackmanが提案しsort -rましたtar。それ以外の場合、削除される前に空ではなかったためdir1、単一の空のディレクトリdir2が含まれる場合dir1rmdirパスの後に残ります。dir2

これにより、多くの

rm: cannot remove `dir/': Is a directory

そして

rmdir: failed to remove `dir/': Directory not empty
rmdir: failed to remove `file': Not a directory

この黙れ2>/dev/null、それはあなたを不愉快にさせる場合を、私はできるだけプロセスに関する多くの情報として維持することを好むだろう。

そして、あなたが正しいファイルにマッチすることを確信するまで、それをしないでください。そしておそらくrm -iすべてを確認してみてください。バックアップを取り、朝食を食べ、歯を磨きます。


はい、-d'\n'オプションをに渡すことをお勧めしますxargs
ステファンギ

@slhckとStéphane:ああ、はい、更新します。小さなテストケースを実行しましたが、ファイルにはスペースがありませんでした。
ダニエルアンダーソン

1
BSDにxargsはがありませ-dんので、私のような貧しい人ならGNUバリアントが必要です。
slhck

10

次のようにtarファイルの内容をリストします。

tar tzf myarchive.tar

次に、そのリストを反復処理してそれらのファイル名を削除します。

while IFS= read -r file; do echo "$file"; done < <(tar tzf myarchive.tar.gz)

これは、削除されるファイルをリストするだけです。これらが削除したいものであることが確かな場合は、echoと置き換えrmます。そして、おそらくバックアップを作成してください。

2番目のパスで、残っているディレクトリを削除します。

while IFS= read -r file; do rmdir "$file"; done < <(tar tzf myarchive.tar.gz)

これにより、以前に存在していたディレクトリが削除されなくなります。


@glennjackmanによるもう1つのすばらしいトリックは、ファイルの順序を保持し、最も深いものから始めます。繰り返しますが、echo完了したら削除します。

tar tvf myarchive.tar | tac | xargs -d'\n' echo rm

その後、通常のrmdirクリーンアップを実行できます。


パイプを書く奇妙な方法。
ステファンギ

それはだないパイプ。それはプロセス置換でありwhile、レコードのセットをループするために組み合わせて使用​​される場合、単純なパイピングよりもこれを好む。慣れました。STE @
slhck

1
少し遅れて申し訳ありませんが、使用rm -rfすると、アーカイブからではなく、アーカイブと同じ名前のディレクトリ内にあるファイルを削除できることに気付きました。ここで注意rmdirして、2回目のパスで使用することをお勧めします。
ステファンギメネス

1
実際にはrmdir、ディレクトリのネストの各レベルで2番目のパスを実行する必要があります。したがってsubdir1、最初のパスで消去されdir1ますが、その時点で空ではなかったときに最初に削除しようとしたため、そのままにします。このコマンドは、ファイルリストを逆ソートできる場合に1回実行できます。
マイクT

3
を逆の順序で削除する場合:(tar tvf arch.tar | tac | xargs echo rm自信があるときにエコーを削除します)
グレンジャックマン

2

抽出されたファイルを取得して、サブフォルダーに移動し、メインフォルダーをクリーンアップする可能性があります。

    #!/usr/bin/perl -w

    use strict;
    use Getopt::Long;

    my $clean_folder = "clean";
    my $DRY_RUN;
    die "Usage: $0 [--dry] [--clean=dir-name]\n"
        if ( !GetOptions("dry!" => \$DRY_RUN,
                         "clean=s" => \$clean_folder));

    # Protect the 'clean_folder' string from shell substitution
    $clean_folder =~ s/'/'\\''/g;

    # Process the "tar tv" listing and output a shell script.
    print "#!/bin/sh\n" if ( !$DRY_RUN );
    while (<>)
    {
        chomp;

        # Strip out permissions string and the directory entry from the 'tar' list
        my $perms = substr($_, 0, 10);
        my $dirent = substr($_, 48);

        # Drop entries that are in subdirectories
        next if ( $dirent =~ m:/.: );

        # If we're in "dry run" mode, just list the permissions and the directory
        # entries.
        #
        if ( $DRY_RUN )
        {
            print "$perms|$dirent\n";
            next;
        }

        # Emit the shell code to clean up the folder
        $dirent =~ s/'/'\\''/g;
        print "mv -i '$dirent' '$clean_folder'/.\n";
    }

これをファイルに保存し、fix-tar.pl次のように実行します。

$ tar tvf myarchive.tar | perl fix-tar.pl --dry

これにより、tarリストが私のリストに似ていることが確認されます。次のような出力が得られます。

-rw-rw-r--|batch
-rw-rw-r--|book-report.png
-rwx------|CaseReports.png
-rw-rw-r--|caseTree.png
-rw-rw-r--|tree.png
drwxrwxr-x|sample/

それがよければ、次のように再度実行します。

$ mkdir cleanup
$ tar tvf myarchive.tar | perl fix-tar.pl --clean=cleanup > fixup.sh

このfixup.shスクリプトは、トップレベルのファイルとディレクトリを「クリーン」フォルダー(この例では、というフォルダーcleanup)に移動するシェルコマンドになります。このスクリプトを覗いて、すべてコーシャであることを確認してください。もしそうなら、あなたは今あなたの混乱をきれいにすることができます:

$ sh fixup.sh

イニシャルによって上書きされることによってまだ破壊されていないものを破壊しないので、私はこの種のクリーンアップを好みますtar xv

注:最初のドライラン出力が正しくない場合は、2つのsubstr関数呼び出しの数値が適切に見えるまで調整する必要があります。$perms変数は、その実際には唯一の予行演習のために使用されている$dirent部分文字列が適切である必要があります。

もう1つ:リスト内のユーザー名またはグループ名、あるいはその両方が予測不能な列で名前を開始する場合、tarオプションを使用する必要があるかもしれません。--numeric-ownertar


1

この種の(非公式)アーカイブは、その機能からタール爆弾と呼ばれます。これらのいずれかがあなたに「爆発」すると、他の答えの解決策は、私が提案したものよりもはるかに優れています。

しかし、最善の「解決策」は、そもそも問題を防ぐことです。

これを行う最も簡単な(最も遅い)方法は、tarアーカイブを常に空のディレクトリに展開することです。トップレベルのディレクトリが含まれている場合は、目的の場所に移動するだけです。そうでない場合は、作業ディレクトリ(空だったディレクトリ)の名前を変更して、目的の場所に移動します。

初めて正しく実行したい場合は、tar -tvf archive-file.tar |を実行できます。アーカイブの内容が一覧表示されるため、アーカイブの構造を確認し、最初に目的の場所にアーカイブを抽出するために必要なことを実行できます。

tオプションは、アーカイブの内容を調べて、探しているものがあるかどうかを確認する場合にも便利です。存在する場合は、必要に応じて、必要なファイルを抽出するだけです。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.