dosyayı kaldır ancak listedeki tüm dosyaları hariç tut


17

Bir klasörü düzenli olarak temizlemem gerekiyor. Metin içeren, hangi dosyalara izin verildiğini içeren bir dosya listesi alıyorum. Şimdi bu dosyada olmayan tüm dosyaları silmek zorundayım.

Misal:

dont-delete.txt:

dontdeletethisfile.txt
reallyimportantfile.txt
neverdeletethis.txt
important.txt

Klasör temizlemem bunu örnek olarak içerir:

ls /home/me/myfolder2tocleanup/:

dontdeletethisfile.txt
reallyimportantfile.txt
neverdeletethis.txt
important.txt
this-can-be-deleted.txt
also-waste.txt
never-used-it.txt

Bu nedenle bu dosyalar silinmelidir:

this-can-be-deleted.txt
also-waste.txt
never-used-it.txt

Dosya tarafından sağlanan bazı dosyaları hariç tutma seçeneği ile silme komutu oluşturmak için bir şey ararım.


Bu bir ödev mi?
mook765

Umarım onun öğretmeni değilsin. lol
Gujarat Santana

2
@gujarat Ücretsiz ev ödevi hizmeti değiliz, bu nedenle yorum haklı. Sorunun kendisi, başkaları için yararlı olabilir, bu yüzden şu ana kadar açık.
Sergiy Kolodyazhnyy

@Serg Sana tamamen katılıyorum
Gujarat Santana

Yanıtlar:


9

rmKomut kontrol etmek ve o kadar gerekli çalışan var olduğunu doğrulamak böylece dışarı yorum. Sonra sadece bu satırın yorumunu kaldırın.

check directoryBölüm yanlışlıkla yanlış dizinden komut dosyasını çalıştırmak etmemelerini sağlamak ve yanlış dosyaları pataklayacak.

echo deletingSessiz çalışmak için hattı kaldırabilirsiniz .

#!/bin/bash

cd /home/me/myfolder2tocleanup/

# Exit if the directory isn't found.
if (($?>0)); then
    echo "Can't find work dir... exiting"
    exit
fi

for i in *; do
    if ! grep -qxFe "$i" filelist.txt; then
        echo "Deleting: $i"
        # the next line is commented out.  Test it.  Then uncomment to removed the files
        # rm "$i"
    fi
done

Bilmeniz gereken tek şey bir eşleşme olup olmadığı olup olmadığını işe yaramaz kullanımıls ve çıkışının yararsız yakalanmasını önlemek için kodunuzu düzenledim grep. Ayrıca, kaçış sorunlarını önlemek için sabit dize desenleri kullandım.
David Foerster

@DavidFoerster Katkılarınız için teşekkür ederiz. Değiştin Ancak, whilebir döngünün fordöngü yanlışlıkla değişti iteration keygelen ietmek f. deklarasyonda, hangi kodu kırdı. Düzelttim.
LD James

Hata! Alışkanlık gücü. Dosya adları için kabuk değişkeni adlarını kısaltma eğilimindeyim f. ;-P (… ve daha önce unuttuğum cevabınız için +1.)
David Foerster

10

Bu python betiği şunları yapabilir:

#!/usr/bin/env python3
import os
no_remove = set()
with open('./dont-delete.txt') as f:
     for line in f:
         no_remove.add(line.strip())

for f in os.listdir('.'):
    if f not in no_remove:
        print('unlink:' + f ) 
        #os.unlink(f)

Önemli olan os.unlink()fonksiyonun açılmasıdır .

NOT : Bu komut dosyasını ve her ikisini de listede dont-delete.txtolacak dont-delete.txtşekilde ekleyin ve aynı dizinde tutun.


1
Kodunuzu set, ikinci bölümde O (n) arama yerine O (1) yerine liste kullanmak üzere değiştirdim .
David Foerster

yardımın için teşekkürler, ben normalde bir windows adamım, ama python dikişler de serin =)
stefan83

1
@ stefan83: Python Windows'da da çalışır.
David Foerster

3

İşte bir astar:

comm -2 -3 <(ls) <(sort dont_delete) | tail +2 | xargs -p rm
  1. ls geçerli dizindeki tüm dosyaları yazdırır (sıralı olarak)
  2. sort dont_delete silmek istemediğimiz tüm dosyaları sıralı olarak yazdırır
  3. <()Operatör bir dosya benzeri nesnesine bir dize döner
  4. commKomutlar bunlar farklılık hangi hatlar üzerinden iki önceden sıralanmış dosya ve baskılar karşılaştırır
  5. -2 -3bayrakların kullanılması, commyalnızca ilk dosyada bulunan satırların yazdırılmasına neden olur , ikincisinin değil, silinmesi güvenli dosyaların listesi olacaktır
  6. tail +2Çağrı sadece başlığını kaldırmaktır commgiriş dosyasının adını içeren çıkışı,
  7. Şimdi standart çıkışta silinecek dosyaların bir listesini alıyoruz. xargsÇıkış akışını için bir argüman listesine dönüştürecek olan bu çıktıyı oluşturuyoruz rm. -pSeçenek kuvvetleri xargsçalıştırmadan önce onay isteyecek.

yardımın için teşekkürler, şimdi benim çözümüm var!
stefan83

@gardenhead, ben kodunuzu yorgun ama dizindeki tüm dosyaları kaldırır ve sadece ilk ve son dosyayı dont-delete listesinde tutmak. bu sorun hakkında bir fikrin var mı? şimdiden teşekkürler.
Negar

1

FWIW, bunu yerel olarak zsh,(+cmd) glob niteleyicisini .

Açıklamak için bazı dosyalarla başlayalım

 % ls
bar  baz  bazfoo  keepfiles.txt  foo  kazoo

ve bir beyaz liste dosyası

 % cat keepfiles.txt
foo
kazoo
bar

İlk olarak, beyaz listeyi bir dizi halinde okuyun:

 % keepfiles=( "${(f)$(< keepfiles.txt)}" )

ya da belki daha iyi

 % zmodload zsh/mapfile
 % keepfiles=( ${(f)mapfile[./keepfiles.txt]} )

(bash mapfileyerleşiminin eşdeğeri - veya eşanlamlısı readarray). Şimdi dizide ${keepfiles[(I)filename]}, eşleşme bulunmazsa 0 döndüren bir anahtarın (dosya adı) var olup olmadığını kontrol edebiliriz :

 % print ${keepfiles[(I)foo]}
1
 % print ${keepfiles[(I)baz]}
0
 %

Dizide trueeşleşme yoksa geri dönen bir işlev yapmak için bunu kullanabiliriz $REPLY:

% nokeep() { (( ${keepfiles[(I)$REPLY]} == 0 )); }

Son olarak, bu işlevi komutumuzda niteleyici olarak kullanıyoruz:

 % ls *(+nokeep)
baz  bazfoo  keepfiles.txt

veya senin durumunda

 % rm -- *(+nokeep)

(Büyük olasılıkla beyaz liste dosyasının adını beyaz listeye eklemek isteyeceksiniz.)


0

Bash kabuğunuzun açık olduğu varsayılırsa extglob shopt, burada biraz daha muhafazakar bir alternatif var:

rm !($(tr \\n \| < keep.txt))

(... eşlik eden gardenhead'in mükemmel iletişim önerisi!)


0

Çıktı, Ubuntu için yaklaşık 2 MB olan maksimum kabuk bağımsız değişkeni sınırınıls /home/me/myfolder2tocleanup/ aşmadığı sürece, aşağıdakileri öneririm. ARG_MAX


İşi yapacak tek satırlık bir komut uygulaması aşağıdaki gibi olacaktır:

  1. dont-delete.txtDosyayı şu şekilde silinecek dosyaları içeren dizine kopyalayın :
cp dont-delete.txt /home/me/myfolder2tocleanup/
  1. cd aşağıdaki gibi silinecek dosyaları içeren dizine kopyalayın:
cd /home/me/myfolder2tocleanup/
  1. Komutu sınamak için kuru bir çalışma gerçekleştirin ve silineceği algılanan dosyaların adlarını gerçekten silmeden yazdırmasını sağlayın:
ls -p | grep -v / | sed 's/\<dont-delete.txt\>//g' | sort | comm -3 - <(sort dont-delete.txt) | xargs echo | tr " " "\n"
  1. Çıktıdan memnunsanız, komutu aşağıdaki gibi çalıştırarak dosyaları silin:
ls -p | grep -v / | sed 's/\<dont-delete.txt\>//g' | sort | comm -3 - <(sort dont-delete.txt) | xargs rm

Açıklama:

  • ls -pgeçerli dizindeki tüm dosyaları ve dizinleri listeler ve seçenek dizin adlarına -pbir ekler /.
  • grep -v //adlarında a içeren tüm öğeleri kaldırarak dizinleri hariç tutar .
  • sed 's/\<dont-delete.txt\>//g'dont-delete.txtdosyayı hariç tutar , böylece işlem sırasında silinmez.
  • sortemin olmak için, kalan çıktıyı sıralar ls.
  • comm -3 - <(sort dont-delete.txt)dont-delete.txtdosyayı sıralar, sıralı çıktıyla karşılaştırır lsve her ikisinde bulunan dosya adlarını hariç tutar.
  • xargs rm, zaten işlenmiş çıktısında kalan tüm dosya adlarını kaldıracak ls. Tüm geçerli dizinde ürün haricinde silinecektir Bu araçlar dizinleri , listelenen dosyalar dont-delete.txtdosyanın ve dosyanın kendisindedont-delete.txt

Kuru çalışma bölümünde:

  • xargs echo kaldırılması gereken dosyaları yazdırır.
  • tr " " "\n" daha kolay okunabilmesi için boşlukları yeni satırlara çevirecektir.

0

rsyncBurada yayınlanan çözümü kullanmanızı şiddetle tavsiye ediyorum ; aksi takdirde belirtilen istisnai bir durumla aşağıdaki çözümü kullanın.

Dosyalarınızda adlı bir dosyada listelenen boşluk (Boşluk / Sekme) olmadığı varsayılarak excludelist, şunu yaparsınız:

find /path/to -type f \( ! -name "excludelist" $(printf ' -a ! -name %s\n' $(< excludelist)) \)

Dışlayıcı dosyada -deletebulunmayan dosyaları silmek için yukarıdaki komuta ekleyin . Bulunuzun seçeneği yoksa, aşağıdakilerle birlikte kullanabilirsiniz :-deleterm-exec

find /path/to -type f \( ! -name "excludelist" $(printf ' -a ! -name %s\n' $(< excludelist)) \) -exec echo rm {} \;

Ya kullanarak -execile +terminatör yerine.

find /path/to -type f \( ! -name "excludelist" $(printf ' -a ! -name %s\n' $(< excludelist)) \) -exec echo rm {} +

echo sadece kuru çalışma için kullanılır.


-1

Benim önerim:

sed -e 's/^/\.\//' dont-delete.txt > dont-delete-relative-path.txt
find . -type f -print | grep -Fxvf dont-delete-relative-path.txt | xargs -d'\n' rm

Güncelleme 2018-08-07

Misal:

1: mkdir /tmp/delete-example && cd /tmp/delete-example
2: touch a b c d
3: echo "./a\n./b\n./dont-delete.txt\n" > dont-delete.txt
4: find . -type f -print | grep -Fxvf dont-delete.txt | xargs -d'\n' rm

3. satırdan sonra dont-delete.txtiçeriği içeren bir dosyaya sahip olacağınızı unutmayın :

./a
./b
./dont-delete.txt

(lider ./olduğu çok önemli )

Dosyalar cve dsilinecek.


Bunu bir satırsonu ile ayrılmış dosya adlarının bir metin dosyası ile denedim. Dizindeki tüm dosyaları sildi.
Jacques MALAPRADE

Sanırım "tutma listeniz" yanlıştı.
nyxz

Örnek kullanım ekledim.
nyxz
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.