Unix - PATTERN hariç dosya ve klasörleri sil


10

Son zamanlarda, bir dizindeki belirli bir desenle eşleşenler dışındaki tüm dosyaları / klasörleri silme göreviyle karşı karşıya kaldım. Bu yüzden işi yapmak için tek satırlık bir unix komutu hazırladım. Sadece bir satır mı olmalı? Sanmıyorum, ama kesinlikle bu şekilde daha havalı!

Sorun oldukça basit olsa da, çözümümün ne kadar karmaşık olduğuna biraz şaşırdım. İşte kullandığım komut; NOT: Bu, satır besleme karakterleri içeren dosya adlarını işlemediğinden (durumumda önemli olmayan) kötü bir çözümdür.

ls | grep -v PATTERN | xargs -n1 -IREPLACE rm -rf REPLACE

PATTERN ile eşleşen klasörlere tekrar okumak istemediğim için "find" komutunu kullanmadım. Örneğin, aşağıdaki dosya yapısını göz önünde bulundurun:

file_foo.txt
first_dir
  |
  +--> contents
  +--> ...
foo_dir
  |
  +--> anotherfile.txt
  +--> morefiles.log
foo_file.txt
somefile.txt

Desen "foo" kullanılması sadece "first_dir" (ve elbette 's içeriği) ve "somefile.txt" (kaldırmalısınız değil "anotherfile.txt" veya "morefiles.log").

Soru, bunu başarmanın daha iyi (daha zarif ve doğru) yolları var mı?


EDIT:
Son zamanlarda dikkatimi "bulmak" daha iyi bir seçenek olabilir getirildi :

find * -maxdepth 0 ! -name PATTERN -print0 | xargs -0n1 rm -rf

Bu çözüm, satır besleme karakterleri içeren yolları doğru şekilde işler.


EDIT: "first_dir" düzeltmek için hatalı "the_dir" değiştirildi.
joxl

Yanıtlar:


10

Aşağıdaki örnekler echoöneklenmiştir, böylece kalıpları gerçekte kullanmadan önce test edebilirsiniz. Öğesini echoetkinleştirmek için öğesini kaldırın rm -rf. Değiştirin rm -rionay istemi için.

ksh , globbing için negatif bir eşleme uzantısına sahiptir:

# ksh
echo rm -rf !(*foo*)

Seçeneği ayarlarsanız aynı sözdizimi bash dilinde kullanılabilir extglob:

# bash
shopt -s extglob
echo rm -rf !(*foo*)

zsh bunun için kendi sözdizimine sahiptir:

# zsh
setopt extended_glob
echo rm -rf ^*foo*

Ayrıca ksh stili sözdizimini de kullanabilir :

# zsh: ksh-style glob syntax
setopt ksh_glob no_bare_glob_qual
echo rm -rf !(*foo*)

# zsh: ksh-style glob syntax, adapted for the default bare_glob_qual option
setopt ksh_glob bare_glob_qual
echo rm -rf (!(*foo*))

Basit, zarif, kolları satır besleme karakterleri, (neredeyse) bir hat (ı ekledim shopt -s extglobşimdi çok, benim Bashrc dosyaya olan tek liner). Mükemmel! İtibarım izin verdiği anda bir oylama sözü veriyorum.
joxl

7

İşte başka bir findçözüm. Bunun sizinkine göre gerçek bir avantajı olduğundan emin değilim, ancak xargsçok fazla isme genişleyen nadir olasılıklara ihtiyaç duymuyor ve buna izin veriyor.

find . -maxdepth 1 ! -name PATTERN -type f -delete

Ayrıca -type fdizinleri silmeye çalışmaz diye ekledim .

Uyarı: -deletegüçlüdür. Test dosyalarımdan birine 0 izin verdim ve yukarıdaki komut tereddüt etmeden sildi.


6
Önce test edin. İstediğiniz dosyaları bulup bulamadığını görmek için -deleteile değiştirin -print. Her şey yolundaysa, aynı bulma filtreleriyle çalıştığınızdan emin olmak için önceki komuta geri dönmek için komut geçmişini kullanın (örn. Yukarı düğmesine basın).
Doug Harris

O notu dikkatlice okuyunuz yapmak kaldır dizinlere dileği. Ve find -deleteboş olmayan dizinleri kaldırmaz. Ayrıca find -maxdepth 1"." (geçerli dizin) ki bu gerçekten kötü. Her ne kadar ortadan kaldırma fikrinizi sevsem de xargs, find -execalternatif olarak kullanılabilir. find * -maxdepth 0 ! -name PATTERN -exec rm -rf '{}' \;
joxl

0

Bunun yerine çok daha anlaşılır olan ve klasör seçimi ve onayı gibi kullanıcı etkileşimini yönetebilen http://askcodegeneration.com/keep-subversion/ bu rebol komut dosyası örneğini kullanabilirsiniz :

delete-file: func[file][
    if/else none? find file "/.svn/" [
        delete file
    ][
        print ["keeping" file]
    ]
]
dir: request-dir
ans: ask rejoin ["Do you confirm " dir "? (Yes): "]
if (ans = "Yes") [
    foreach-file dir :delete-file
]
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.