撤消 tar 文件提取混乱

撤消 tar 文件提取混乱

我刚刚解压了一个存档,它产生了一堆乱七八糟的文件,并将其放入我的整洁目录中。例如:

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

我原本以为 tar 文件会被组织在一个文件夹中(即myarchive/),但事实并非如此!现在我有大约 190 个文件和目录,它们以数字方式杂乱无章地存在于一个有组织的目录中。这些解压后的文件需要清理。

有什么方法可以“撤消”此操作并删除从该档案中提取的文件和目录?


感谢以下的精彩回答。总之,下面分为两个步骤(1)删除文件,(2)按相反的顺序删除空目录结构(先删除外部目录):

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

echo更安全的是,通过在后面附加来预览命令的试运行xargs

答案1

tar tf archive.tar

将逐行列出内容。

这可以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(glennjackman 建议在对已接受答案的评论中tac使用,因为的输出足够规则,所以 也有效)需要先删除最深的目录;否则,包含单个空目录的情况将在传递后离开,因为它是sort -rtardir1dir2dir1rmdir不是被删除之前为空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确认所有内容。然后备份、吃早餐、刷牙等。

答案2

列出 tar 文件的内容,如下所示:

tar tzf myarchive.tar

然后,通过迭代该列表来删除这些文件名:

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

这仍然只是列表将被删除的文件。如果您确实确定这些是您要删除的文件,请将其替换echorm。也许可以进行备份以确保万无一失。

第二遍,删除剩余的目录:

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

如果目录之前已经存在,这可以防止其被删除。


@glennjackman 的另一个巧妙技巧是,它可以保留文件的顺序,从最深的文件开始。echo完成后再次删除。

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

然后就可以进行正常的rmdir清理了。

答案3

这是一种可能性,即将提取的文件移动到子目录,从而清理主文件夹。

    #!/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)的 shell 命令。查看一下此脚本以确认一切正常。如果一切正常,您现在可以使用以下方法清理您的混乱局面:

$ sh fixup.sh

我更喜欢这种清理,因为它不会破坏任何尚未被初始覆盖破坏的东西tar xv

注意:如果初始试运行输出看起来不正确,您应该能够调整两个substr函数调用中的数字,直到它们看起来正确为止。该$perms变量仅用于试运行,因此实际上只有子$dirent字符串需要正确。

还有一件事:如果列表中的用户名和/或组名以不可预测的列开头,则可能需要使用该tar选项。--numeric-ownertar

答案4

tar -tf fly.tar | cut -d"/" -f1 | uniq | xargs rm -rf

相关内容