Tar dosyası ayıklama karmaşasını geri al


34

Ben sadece düzenli dizine dosya karmaşası üreten bir arşivi kaldırdım. Örneğin:

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

Tar dosyasının tek bir klasörde (yani myarchive/) organize edileceğini umuyordum , ama değildi! Şimdi organize bir dizinde neyin dijital olarak engellendiği 190 dosya ve dizine sahibim. Bu düzensiz dosyaların temizlenmesi gerekiyor.

Bunu geri almanın ve bu arşivden çıkarılan dosyaları ve dizinleri silmenin bir yolu var mı?


Aşağıdaki mükemmel cevaplar için teşekkürler. Özetle , işte iki adımla çalışan şey (1) dosyaları sil ve (2) boş dizin yapısını ters paketleme sırasına göre sil (ilk önce dış dizinleri silmek için):

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

Ve daha da güvenli, echosonradan ekleyerek komutların kuru çalışmasını önizlemek için xargs.


Sanırım arşivdeki dosyaları listeleyebilir ve bunları geçerli dizinden silebilirsiniz, ancak bu potansiyel olarak verileri yıkıcı (saklamak istediğiniz verileri) hissettirir. Ayrıca bir bash betiği nasıl yazacağımı bilmiyorum, o yüzden orada yardım edemem.
Bob

Neyse ki, hiçbir şeyin üzerine yazılmadı!
Mike T

Temsilciden sonra değilim ve korkarım ki, nasıl koyduğumdan bağımsız olarak kulağa gelmeyecek, ki değil (slhck'in cevabını da sevdim ve I +1: ed ve dürüstçe: ± 15 rep; benim dünyam değil ), ama benim önerdiğim cevabı borularla ve xargs( sadece kozmetikler tacyerine sort -r) kullanmaya başladın, ama yorumlarda açıkladığın gibi sana uygun olmayan proses ikamesini kabul ettin? Ayrıca, xargs -d'\n'gelecekteki kullanıcılar için özetlemek istiyorsanız , lütfen geçişi veriniz , böylece dosya adlarındaki boşluklara göre ısırılmayacaklar.
Daniel Andersson

@DanielAndersson, -d'\n'şu ana kadar gerekliliği hiç anlamadım ve daha fazla analiz üzerine cevabınız aslında kullandıklarımdan daha yakın.
Mike T

Bu konuda da gayet iyiyim, @ Daniel'in çözümünü sevdim :) Yeni gerekçelerle (beslediğiniz şeydir) argümanları bölmemeyi -d'\n'söylemezseniz xargs, boşluklarda, sonra bir dosyayı isim ve folder1/some fileolarak okunacaktır . folder1/somename
slhck

Yanıtlar:


36
tar tf archive.tar

içeriği satır satır listeler.

Bu xargsdoğrudan boruya bağlanabilir , fakat dikkat : Silme işlemini çok dikkatli yapın. Sen yok sadece istediğiniz rm -rher şeyi tar tfo açmadan önce boş değildi dizinleri içerebilir beri, sen söyler!

Yapabilirsin

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

önce arşivdeki tüm dosyaları ve ardından boş bırakılan dizinleri kaldırmak için.

sort -r(glennjackman , yorumları tacyerine, çıktısı yeterince düzenli olduğu için sort -rçalışan kabul edilen cevabın yerine önerildi tar) önce en derin dizinleri silmek gerekiyor; Aksi bir durum dir1, tek boş bir dizin içeren dir2bırakacaktır dir1sonra rmdiro beri, pas değil önce boşaltmak dir2çıkarıldı.

Bu çok üretecek

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

ve

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

2>/dev/nullSizi sinirlendirirse bunu kapatın , ancak süreç hakkında mümkün olduğunca fazla bilgi edinmeyi tercih ederim.

Doğru dosyaları eşleştirdiğinizden emin olana kadar bunu yapmayın. Ve belki de rm -iher şeyi onaylamaya çalışın . Yedekler alın, kahvaltınızı yapın, dişlerinizi fırçalayın, vb.


Evet, -d'\n'seçeneğe geçmek daha iyi olur xargs.
Stéphane Gimenez

@slhck ve Stéphane: Ah, evet, güncelleyeceğim. Sadece küçük bir test davası yaptım, fakat dosyalarda boşluk yoktu.
Daniel Andersson

1
BSD'nin xargssahip olmadığı belirtilmelidir -d, bu yüzden benim gibi fakir bir ruhsanız GNU varyantına ihtiyacınız var.
slhck

10

Tar dosyasının içeriğini şöyle sıralayın:

tar tzf myarchive.tar

Ardından, bu listeyi yineleyerek bu dosya adlarını silin:

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

Bu sadece silinecek dosyaları listeleyecektir . Değiştir echoile rmgerçekten emin bunlar kaldırmak istediğiniz olanlardır iseniz. Ve belki emin olmak için bir yedekleme yapın.

İkinci geçişte, kalan dizinleri kaldırın:

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

Bu, daha önce mevcutsa, dizinlerin silinmesini önler.


En sıradan olanlardan başlayarak, dosyaların sırasını koruyan @glennjackman'ın bir başka güzel hilesi. Yine, echobittiğinde kaldırın .

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

Bu daha sonra normal rmdirtemizleme tarafından takip edilebilir .


Bir boru yazmak için garip bir yol.
Stéphane Gimenez

Bu bir boru değil . Bu işlem ikamedir ve bunu whilebir dizi kayıt üzerinde döngü yapmak için birlikte kullanıldığında basit borulara tercih ederim . Sadece alıştım. @ sté
slhck

1
Küçük gecikme için üzgünüm, kullanmanın rm -rf, arşivden değil, arşivden aynı adı taşıyan bir dizinin içindeki dosyaları silebileceğini fark ettim . Dikkatli ol ve rmdirikinci seferde kullansan iyi olur .
Stéphane Gimenez

1
Aslında ikinci geçişte, rmdirher bir dizin iç içe geçme düzeyi için çalıştırılması gerekir. Böylece subdir1ilk geçişte temizlenir , ancak dir1o zaman boş olmadığında ilk önce onu silmeye çalıştığından ayrılın . Dosya listesi tersine sıralanabilirse bu komut bir kez yapılabilir.
Mike T

3
Tersini sırayla silmek istiyorsanız: tar tvf arch.tar | tac | xargs echo rm(kendinize güvendiğiniz zaman yankıyı kaldırın)
glenn jackman

2

İşte ayıklanan dosyaları alıp bir alt dizine taşıyacak ve ana klasörünüzü temizleyebilecek bir olasılık.

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

Bunu dosyaya kaydedin ve bu şekilde fix-tar.plçalıştırın:

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

Bu, tarlistenizin benimki gibi olduğunu doğrular. Gibi çıktı almalısınız:

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

Eğer iyi görünüyorsa, tekrar şöyle çalıştırın:

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

fixup.shKomut dosyası "temiz" klasörüne üst düzey dosyaları ve dizinleri hareket edecek kabuk komutları olacaktır (bu örnekte, klasör olarak adlandırılır cleanup). Bunların hepsinin koşut olduğunu doğrulamak için bu betiğe bir göz atın. Öyleyse, şimdi durumunuzu şu şekilde temizleyebilirsiniz:

$ sh fixup.sh

Bu tür bir temizliği tercih ederim çünkü o ilk tarafından üzerine yazılarak tahrip edilmemiş hiçbir şeyi yok etmiyor tar xv.

Not: eğer bu ilk kuru çalıştırma çıkışı düzgün görünmüyorsa, iki substrfonksiyon çağrısındaki sayılarla uygun görünene kadar dolaşabilmelisiniz. $permsDeğişken sadece bu gerçekten sadece çalıştırmak kuru kullanılır $direntalt dize ihtiyaçları uygun olması.

Başka bir şey: listedeki kullanıcı adları ve / veya grup adları , adları öngörülemeyen bir sütunda başlatırsa tarseçeneği kullanmanız gerekebilir .--numeric-ownertar


1

Bu tür (antisosyal) arşive, yaptıklarından dolayı katran bombası denir. Bunlardan biri size “patladı” mı, diğer cevaplardaki çözümler önerdiğimden çok daha iyi.

Ancak en iyi "çözüm" sorunu en başta önlemektir.

Bunu yapmanın en kolay (en tembel) yolu, her zaman bir tar arşivini boş bir dizine açmaktır. Bir üst seviye dizini içeriyorsa, bunu sadece istediğiniz hedefe taşıyabilirsiniz. Değilse, çalışma dizininizi (boş olanı) yeniden adlandırın ve istediğiniz yere taşıyın.

İlk seferinde doğru yapmak istiyorsanız, tar -tvf archive-file.tar | daha az ve arşivin içeriğini listeleyecek, böylece nasıl yapılandırıldığını görebilecek ve daha sonra başlamak için istenen yere çıkarmak için gerekli olanı yapabileceksiniz.

Ayrıca, aradığınız bir şey olup olmadığını görmek için bir arşivin içeriğini incelemek isterseniz de t seçeneği kullanışlıdır. Varsa, isteğe bağlı olarak, istediğiniz dosyaları çıkarmanız yeterlidir.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.