Dizindeki, adı dosya listesindeki bir satırla eşleşmeyen tüm dosyaları silme


9

1000'den fazla dosya içeren bir dizin var. Bir metin dosyasında, her satıra bir tane olmak üzere yaklaşık 50 dosya adım var. Dosya adları listedeki bir girdiye karşılık gelmeyen dizindeki tüm dosyaları silmek istiyorum. Bunu yapmanın en iyi yolu nedir? Bir kabuk komut dosyası başlattım, ancak dosya adında listede belirlemek için uygun komutu belirleyemedim. Teşekkürler.

Yanıtlar:


8

Dosyaların nasıl silineceğini soran herhangi bir sorunun büyük bir dikkatle alınması gerektiğini anlıyorum. İlk cevabım çok aceleci oldu. Bu riski azaltmak için cevabı düzenledim.

Bu, adında boşluk olmayan dosyalar için çalışmalıdır:

Önce dosya adınızla tam olarak eşleştiğinden emin olmak için dosya listenizi yeniden oluşturun:

sed -e 's,^,^,' -e 's,$,$,'  filelist  > newfilelist 

rm komutlarını oluşturma

cd your_directory
ls | egrep -vf newfilelist   | xargs -n 1 echo rm  >  rmscript

Rm betiğinin size uygun olup olmadığını kontrol edin ("vim" veya "less" ile yapabilirsiniz).
Ardından işlemi gerçekleştirin:

sh -x rmscript

Dosyaların adında boşluklar varsa (dosya adında ise, "bu çalışmaz):

ls | egrep -vf newfilelist  | sed 's,^\(.*\)$,rm "\1",' > rmscript

Tabii ki filelist aynı dizinde olmamalı!

DÜZENLENMİŞ:

Nathan'ın dosya listesinde, dizindeki tüm dosyalarla eşleşen adlar vardı ("html", "bob.html" ile eşleşir). Böylece hiçbir şey silinmedi çünkü egrep -vftüm akışı emdi. Her dosya adının etrafına "^" ve "$" eklemek için bir komut ekledim. Burada Nathan'ın dosya listesinin doğru olduğu için şanslıydım. DOS, CR-LF uçlu çizgilerle veya ek boşluklarla biçimlendirilmiş olsaydı, hiçbir dosya egrep tarafından korunmazdı ve hepsi silinirdi.


Önizleme komutunu çalıştırdığımda "rm" ile bir satır alıyorum. Gerçek komutu çalıştırdığımda, rm için eksik argümanlar hakkında bir hata mesajı alıyorum. Ls sonuçlarını kullanmak için özel sözdizimine ihtiyacım var mı | xargs girişindeki egrep?
Nathan

@Nathan önce dizininize cd gerekir. Özel bir sözdizimi yok. lsdizin dosya adlarını sağlar, egrep -vf filelist50 dosya adlarınızı filtreleyin. Korkarım tüm dosyalarınızı sildiniz.
Emmanuel

@Emamanuel Silinecek dosyaları içeren dizinden komutu çalıştırıyorum.
Nathan

@Nathan tüm dosyalarınız silindi mi?
Emmanuel

Hayır, hala oradalar.
Nathan

1

Argümanları şu şekilde önceden oluşturun find:

{
  read -r
  keep=( -name "$REPLY" ) # no `-o` before the first one.
  while read -r; do
    keep+=( -o -name "$REPLY" )
  done
} < file_list.txt
find . -type f ! \( "${keep[@]}" \) -exec echo rm {} +

echoNelerin inşa edileceğini görmek için parçaları kullanın . echoGerçekten çalıştırmak için parçaları çıkarın .

Güncelleme: Gösteri:

##
# Demonstrate what files exist for testing.
# Show their whitespace:
~/foo $ printf '"%s"\n' *
" op"
" qr"
"abc"
"def"
"gh "
"ij "
"k l"
"keep"
"m n"

##
# Show the contents of the "keep" file,
# Including its whitespace:
~/foo $ cat -e keep
keep$
abc$
gh $
k l$
 op$

##
# Execute the script:
~/foo $ { read -r; keep=( -name "$REPLY" ); while read -r ; do keep+=( -o -name "$REPLY" ); done } < keep
~/foo $ find . -type f ! \( "${keep[@]}" \) -exec rm {} +

##
# Show what files remain:
~/foo $ printf '"%s"\n' *
" op"
"abc"
"gh "
"k l"
"keep"

I like this filelist
eyoung100

Boşluklarla çok iyi ilgilenmese de benden +1. Belki bazı tek tırnak ( ') eklenmelidir, yani keep=( -name \'"$REPLY"\' )ve keep+=( -o -name \'"$REPLY"\' ).
Cristian Ciupitu

yukarıdakiler tehlikelidir, çünkü yanlışlıkla dosyaları silebilirsiniz.
davidva

@CristianCiupitu değil mi? Beyaz alanla çok iyi başa çıktığını gösteren bir demo ekledim.
kojiro

@davidva Hangi koşullar altında? Herhangi bir şeyi silmeyi otomatikleştirdiğinizde, hata yapma riskiyle karşı karşıya kalırsınız, ancak soru parametreleri dahilinde, demomun bu yaklaşımın sağlam olduğunu kanıtladığını düşünüyorum.
kojiro

1

İle zsh:

mylist=(${(f)"$(<filelist)"})
print -rl -- *(.^e_'(($mylist[(Ie)$REPLY]))'_)

filelistBir dizideki satırları okur ve daha sonra yalnızca dizide bulunmayan dosya adlarını glob / seçmek için glob niteleyicileri / edizesi kullanır : .yalnızca normal dosyaları seçer ( Dlisteniz dotfiles içeriyorsa ekle) ve reddedilenler ^e_'expression'_yalnızca ifadesi false değerini döndürür; yani, adları ( $REPLY) dizinin bir öğesi değilse .
Sonuçtan memnunsanız , dosyaları gerçekten kaldırmak için print -rlile değiştirin rm:

rm -- *(.^e_'(($mylist[(Ie)$REPLY]))'_)

Dosyaları özyinelemeli olarak seçmek ve kaldırmak */**için ${REPLY:t}glob değiştiricili glob'u kullanın :

rm -- */**(.^e_'(($mylist[(Ie)${REPLY:t}]))'_)

0

Dizinin içeriğini şöyle bir dosyaya koyarsanız:

cd <somedirectory>
ls >> filelist

Bir metin düzenleyicisiyle dosya listesini açın ve SİLMEK İSTEDİKLERİNİZ dışındaki tüm dosyaları kaldırın . Bu cesur çünkü yukarıdaki cevaba zıt bir yaklaşım

Bunu dene:

while read p || [[ -n $p ]]; 
echo $p
done < filelist

Ekrana çıkan dosya listenizi görürseniz yankı ile aşağıdaki rm -vgibi değiştirin :

while read p || [[ -n $p ]]; 
rm -v $p
done < filelist

0

Aşağıdaki komut dosyasını çalıştırın.

  1. Başlangıçta dizinde bulunan tüm dosyaları buluyorum ve çıktıyı başka bir dosyaya kaydediyorum all_files.
  2. Biz gereken dosyaların listesini içeren bir dosya var DEĞİL silinebilir ( not_to_be_deleted_files).
  3. Dosya adlarını ekliyorum not_to_be_deleted_filesve files_to_be_deletedsonuna not_to_be_deleted_fileskadar bu 2 dosyaya ihtiyacımız var.
  4. Şimdi, linux joinkomutunu kullanarak silinmesi gereken dosyaları bulup çıktıyı files_to_be_deleted dosyaya yönlendiriyorum .
  5. Şimdi, son while döngüsünde tüm dosya adlarını okuyorum files_to_be_deletedve o dosya adında belirtilen dosyaları kaldırıyorum.

Komut dosyası aşağıdaki gibidir.

find /home/username/directory -type f | sed 's/.*\///' > all_files
echo all_files >> not_to_be_deleted_files
echo not_to_be_deleted_files >> not_to_be_deleted_files
echo files_to_be_deleted >> not_to_be_deleted_files
join -v 1 <(sort all_files_listed) <(sort files_not_to_be_deleted) >   files_to_be_deleted
while read file
rm  "$file"
done < files_to_be_deleted

PS : Muhtemelen, bunun bir komut dosyası olarak kaydedilmesini ve çalıştırılmasını istiyorsanız, komut dosyası adını da kullanarak ekleyebilirsiniz echo scriptname >> not_to_be_deleted_files.

Gerekli olmasa da, bunu yapmayı tercih ederim çünkü daha sonra pişman olmayacaksınız. Küçük bir dosya grubunu test ettim ve sistemimde çalıştı. Ancak, emin olmak istiyorsanız, önce bir testdizinde deneyin ve ardından orijinal dizindeki dosyaları kaldırın.


0
  • Listedeki tüm dosyaları yeni, yeni ve boş bir kayıt dizinine taşımak için listeyi kaynak olarak kullanın.
  • Listedeki dosya sayısını ve kaydedilen dosya sayısını karşılaştırın.
  • Her ikisi de eşleşiyorsa, kaydedilmemiş tüm dosyaları favori yönteminizle silin.
  • Kayıtlı dosyaları geri taşıyın.

0

Listede 18.000 dosyam olduğu için daha güvenli ve çok daha hızlı bir yaklaşıma gittim! Büyük bir Drupal kurulumunda görüntüleri temizlemem gerekiyordu.

Listede olmayan tüm dosyaları silmek, yalnızca listede bulunan dosyaları tutmakla aynıdır. Bu yüzden dosyaları listeden başka bir yere kopyalamaya karar verdim, ancak 20 GB'lık dosyaları kopyalamak çok fazla yer kaplayacak ve çok yavaş olacaktır. Bu yüzden hile dosyaları hardlinksyerine -lseçeneğini kopyalamaktır cp. Bu neredeyse hiç yer kaplamaz ve çok hızlıdır. Ayrıca, dizin yapısını korumak gerektiğinden, --parentsseçeneği kullandım .

İşte dosya listemden bir alıntı:

1px.png
misc/feed.png
modules/file/icons/x-office-presentation.png
modules/file/icons/x-office-spreadsheet.png
newsletter.png
sites/all/libraries/ckeditor/plugins/smiley/images/devil_smile.png
sites/all/libraries/ckeditor/plugins/smiley/images/regular_smile.png
sites/default/files/009313_PwC_banner_CBS_Observer_180x246px.jpg

Örnek bir hedef, temp hedef olacaktı:

cp -l --parents 'misc/feed.png' temp

Bu şu yapıyı yaratacaktır:

temp
  misc
    feed.png

Sabit bağlantıların çalışması için hedefin kaynakla aynı dosya sisteminde olması gerektiğini unutmayın.

Bir sonraki adım betiği oluşturmaktır:

sed -e "s,^,cp -l --parents '," -e "s,$,' /some/where/temp," filelist > newfilelist

Şimdi, zaten boş dir / some / where / temp dosyasını oluşturduğunuzu varsayarak, dosyaları şu şekilde kopyalayabilirsiniz:

sh newfilelist 2> missing_files

Hataların nasıl ortaya çıktığını not edin missing_files. Bu yaklaşımın ek bonusu, orijinal listeden aslında var olmayan dosyaların bir listesini almanızdır!

Komut dosyasını çalıştırdıktan sonra, temp yalnızca dosya listesindeki dosyaları içerir, ancak hiçbir şey silmeden ve ek yer kaplamadan. Sonuçtan memnunsanız, alt klasörler dahil tüm orijinal dosyaları silebilirsiniz.

Son olarak, dosya ve klasörleri geçici olarak orijinal konumuna geri taşıyın.

18.000 dosya için sadece birkaç saniye sürdü.


0

Güvenli, basit.

cd dizinine.

Bir geçici dizin oluşturun.

mv *.yourExlusionSelector.* ./temp
rm *
mv ./temp ./
rm -rf ./temp

yapılır.


Siteye hoş geldiniz. OP tarafından belirtilen listedeki adlar basit bir desen eşleşmesinin sonucuysa (ki bu durum çok iyi olabilir) yaklaşımınız işe yarayacaktır, ancak OP'nin hariç tutulacak dosya adlarının belirli bir dosyada saklandığını belirtti; tek bir statik desene güvenmek veya konsola potansiyel olarak birden çok deseni yazmak zorunda kalmak yerine, o dosyadaki hariç tutma şablonlarını okumak için yanıtınızı genişletmek isteyebilirsiniz.
AdminBee
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.