Hoàn tác lộn xộn tập tin tar


34

Tôi chỉ mở một kho lưu trữ tạo ra một mớ hỗn độn các tập tin vào thư mục gọn gàng của tôi. Ví dụ:

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

Tôi đã hy vọng rằng tập tin tar sẽ được tổ chức trong một thư mục duy nhất (nghĩa là myarchive/), nhưng không phải vậy! Bây giờ tôi có khoảng 190 tệp và thư mục đã được mã hóa kỹ thuật số trong thư mục có tổ chức. Những tập tin chưa được chỉnh sửa này cần được dọn sạch.

Có cách nào để "hoàn tác" cái này và xóa các tập tin và thư mục được trích xuất từ ​​kho lưu trữ này không?


Cảm ơn các câu trả lời tuyệt vời dưới đây. Tóm lại , đây là những gì hoạt động với hai bước (1) xóa tệp và (2) xóa cấu trúc thư mục trống theo thứ tự đóng gói ngược (để xóa các thư mục bên ngoài trước):

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

Và an toàn hơn nữa, để xem trước một lệnh khô bằng cách nối thêm echosau xargs.


Tôi đoán bạn có thể liệt kê các tệp trong kho lưu trữ và xóa chúng khỏi thư mục hiện tại, nhưng điều đó cảm thấy có khả năng phá hủy dữ liệu (dữ liệu bạn muốn giữ). Tôi cũng không biết làm thế nào để viết một kịch bản bash, vì vậy tôi không thể giúp đỡ ở đó.
Bob

May mắn thay, không có gì được ghi đè!
Mike T

Tôi không theo đuổi đại diện và tôi sợ rằng tôi sẽ cáu kỉnh cho dù tôi có nói thế nào đi chăng nữa, tôi cũng vậy (tôi cũng thích câu trả lời của slhck và tôi +1: ed, và thành thật: ± 15 rep là không phải thế giới của tôi), nhưng cuối cùng bạn sử dụng câu trả lời được đề xuất của tôi bằng đường ống và xargs( tacthay vì sort -rchỉ là mỹ phẩm), nhưng bạn chấp nhận câu trả lời với sự thay thế quy trình, như bạn đã giải thích trong các bình luận, không phù hợp với bạn? Ngoài ra, vui lòng cung cấp công xargs -d'\n'tắc trong bài đăng của bạn nếu bạn muốn tóm tắt cho người dùng trong tương lai, vì vậy họ sẽ không bị cắn bởi khoảng trắng trong tên tệp.
Daniel Andersson

@DanielAndersson, tôi chưa bao giờ hiểu sự cần thiết -d'\n'cho đến bây giờ, và khi phân tích sâu hơn, câu trả lời của bạn thực sự gần với những gì tôi đã sử dụng.
Mike T

Hoàn toàn tốt với điều đó, cũng thích giải pháp của @ Daniel :) Sự cần thiết của sự -d'\n'dối trá trong thực tế là nếu bạn không yêu xargscầu phân chia các đối số trên các dòng mới (đó là những gì bạn đang cho ăn) nhưng trên một khoảng trắng, thì một tệp có Tên folder1/some filesẽ được đọc là folder1/somename.
slhck

Câu trả lời:


36
tar tf archive.tar

sẽ liệt kê các nội dung theo từng dòng.

Điều này có thể được dẫn đến xargstrực tiếp, nhưng hãy cẩn thận : xóa rất cẩn thận. Bạn không muốn chỉ rm -rmọi thứ tar tfnói với bạn, vì nó có thể bao gồm các thư mục không trống trước khi giải nén!

Bạn có thể làm

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

để đầu tiên xóa tất cả các tệp trong kho lưu trữ, và sau đó các thư mục còn trống.

sort -r(glennjackman đề xuất tacthay vì sort -rtrong các nhận xét cho câu trả lời được chấp nhận, cũng hoạt động vì tarđầu ra của nó đủ thường xuyên) là cần thiết để xóa các thư mục sâu nhất trước tiên; mặt khác, một trường hợp dir1chứa một thư mục trống dir2sẽ để lại dir1sau khi rmdirvượt qua, vì nó không trống trước khi dir2bị xóa.

Điều này sẽ tạo ra rất nhiều

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

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

Hãy tắt 2>/dev/nullnó đi nếu điều đó làm bạn khó chịu, nhưng tôi muốn giữ càng nhiều thông tin về quy trình càng tốt.

Và đừng làm điều đó cho đến khi bạn chắc chắn rằng bạn khớp đúng tệp. Và có lẽ cố gắng rm -ixác nhận mọi thứ. Và có bản sao lưu, ăn sáng, đánh răng, v.v.


Vâng, nó sẽ tốt hơn để vượt qua -d'\n'tùy chọn để xargs.
Stéphane Gimenez

@slhck và Stéphane: À, vâng, tôi sẽ cập nhật. Tôi chỉ làm một trường hợp thử nghiệm nhỏ, nhưng các tập tin không có khoảng trắng.
Daniel Andersson

1
Cần lưu ý rằng BSD xargskhông có -d, vì vậy bạn cần biến thể GNU nếu bạn là người có tâm hồn nghèo nàn như tôi.
slhck

10

Liệt kê nội dung của tệp tar như vậy:

tar tzf myarchive.tar

Sau đó, xóa các tên tệp đó bằng cách lặp qua danh sách đó:

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

Điều này sẽ vẫn chỉ liệt kê các tập tin sẽ bị xóa. Thay thế echobằng rmnếu bạn thực sự chắc chắn đây là những cái bạn muốn loại bỏ. Và có thể tạo một bản sao lưu để chắc chắn.

Trong một lần thứ hai, loại bỏ các thư mục còn sót lại:

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

Điều này ngăn các thư mục bị xóa nếu chúng đã tồn tại trước đó.


Một thủ thuật hay khác của @glennjackman, giúp duy trì thứ tự các tệp, bắt đầu từ những tệp sâu nhất. Một lần nữa, loại bỏ echokhi thực hiện.

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

Điều này sau đó có thể được theo sau bởi rmdirdọn dẹp bình thường .


Cách lạ để viết một đường ống.
Stéphane Gimenez

Đó không phải là một đường ống. Đó là quá trình thay thế và tôi thích điều này hơn các đường ống đơn giản khi được sử dụng kết hợp với whilelặp qua một tập hợp các bản ghi. Chỉ cần quen với nó. @ sté
slhck

1
Xin lỗi vì sự chậm trễ nhỏ, tôi nhận thấy rằng việc sử dụng rm -rfcó thể xóa các tệp không phải từ kho lưu trữ mà bên trong một thư mục có cùng tên với một tệp từ kho lưu trữ. Tốt hơn nên cẩn thận ở đây và sử dụng rmdirtrong một lần thứ hai.
Stéphane Gimenez

1
Trên thực tế, lần thứ hai với rmdirnhu cầu được chạy cho từng cấp độ lồng của các thư mục. Vì vậy, nó sẽ dọn sạch subdir1trên đường chuyền đầu tiên, nhưng hãy rời đi dir1vì nó đã cố gắng xóa cái này trước khi nó không trống vào thời điểm đó. Lệnh này có thể được thực hiện một lần nếu danh sách tệp có thể được sắp xếp ngược lại.
Mike T

3
Nếu bạn muốn xóa theo thứ tự ngược lại: tar tvf arch.tar | tac | xargs echo rm(loại bỏ tiếng vang khi bạn tự tin)
glenn jackman

2

Đây là một khả năng sẽ lấy các tệp được giải nén và chuyển chúng sang thư mục con, dọn sạch thư mục chính của bạn.

    #!/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";
    }

Lưu cái này vào tập tin fix-tar.plvà sau đó thực hiện nó như thế này:

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

Điều này sẽ xác nhận rằng tardanh sách của bạn giống như của tôi. Bạn sẽ nhận được đầu ra như:

-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/

Nếu nó có vẻ tốt, thì hãy chạy lại như thế này:

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

Các fixup.shkịch bản sẽ là các lệnh shell mà sẽ di chuyển các tập tin top-level và thư mục vào một thư mục "sạch" (trong trường hợp này, các thư mục có tên cleanup). Hãy xem qua kịch bản này để xác nhận rằng đó là tất cả. Nếu có, bây giờ bạn có thể dọn dẹp mớ hỗn độn của mình bằng:

$ sh fixup.sh

Tôi thích kiểu dọn dẹp này vì nó không phá hủy bất cứ thứ gì chưa bị phá hủy bằng cách bị ghi đè bởi chữ cái đầu tiên đó tar xv.

Lưu ý: nếu đầu ra chạy khô ban đầu đó không đúng, bạn sẽ có thể sử dụng các số trong hai substrlệnh gọi cho đến khi chúng trông phù hợp. Các $permsbiến được sử dụng chỉ cho khô chạy như vậy thực sự chỉ có $direntnhu cầu substring là thích hợp.

Một điều khác: bạn có thể cần sử dụng tartùy chọn --numeric-ownernếu tên người dùng và / hoặc tên nhóm trong tardanh sách làm cho tên bắt đầu trong một cột không thể đoán trước.


1

Loại lưu trữ (chống xã hội) đó được gọi là bom tar vì những gì nó làm. Khi một trong những "phát nổ" này vào bạn, các giải pháp trong các câu trả lời khác sẽ tốt hơn những gì tôi đã đề xuất.

"Giải pháp" tốt nhất, tuy nhiên, là ngăn chặn vấn đề ngay từ đầu.

Cách dễ nhất (lười nhất) để làm điều đó là luôn luôn giải nén một kho lưu trữ tar vào một thư mục trống. Nếu nó bao gồm một thư mục cấp cao nhất, thì bạn chỉ cần di chuyển nó đến đích mong muốn. Nếu không, sau đó chỉ cần đổi tên thư mục làm việc của bạn (thư mục trống) và di chuyển nó đến vị trí mong muốn.

Nếu bạn chỉ muốn làm cho đúng ngay lần đầu tiên, bạn có thể chạy tar -tvf archive-file.tar | ít hơn và nó sẽ liệt kê các nội dung của kho lưu trữ để bạn có thể thấy nó được cấu trúc như thế nào và sau đó làm những gì cần thiết để trích xuất nó đến vị trí mong muốn để bắt đầu.

Tùy chọn t cũng có ích nếu bạn muốn kiểm tra nội dung của kho lưu trữ chỉ để xem liệu nó có thứ gì bạn đang tìm kiếm trong đó không. Nếu có, bạn có thể, tùy ý, chỉ cần giải nén (các) tệp bạn muốn.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.