Belirli bir sonu olan dosyaların eksik olduğu dizinleri bulun


10

Belirli bir dosya sonu olan dosyaları içermeyen tüm dizinleri görüntülemek istiyorum. Bu nedenle aşağıdaki kodu kullanmayı denedim:

find . -type d \! -exec test -e '{}/*.ENDING' \; -print

Bu örnekte, biten dosyalar içermeyen tüm dizinleri görüntülemek istedim .ENDING, ancak bu çalışmıyor.

Benim hatam nerede?


Bu, dosya içermeyen Liste dizinlerinin bir kopyası değildir, çünkü bu soru joker karakterlerle ilgilenmez.
Cristian Ciupitu

Yanıtlar:


7

İşte üç adımda bir çözüm:

temeraire:tmp jenny$ find . -type f -name \*ENDING -exec dirname {} \; |sort -u > /tmp/ending.lst
temeraire:tmp jenny$ find . -type d |sort -u > /tmp/dirs.lst
temeraire:tmp jenny$ comm -3 /tmp/dirs.lst /tmp/ending.lst 

2
Bash kabuğu kullanılıyorsa geçici dosyaları olmayan tek astar:comm -3 <(find . -type f -name \*ENDING -exec dirname {} \; |sort -u) <(find . -type d |sort -u)
Cristian Ciupitu

4

İşte başlıyoruz!

#!/usr/bin/env python3
import os

for curdir,dirnames,filenames in os.walk('.'):
  if len(tuple(filter(lambda x: x.endswith('.ENDING'), filenames))) == 0:
    print(curdir)

Veya dönüşümlü olarak (ve daha pitonik):

#!/usr/bin/env python3
import os

for curdir,dirnames,filenames in os.walk('.'):
    # Props to Cristian Cliupitu for the better python
    if not any(x.endswith('.ENDING') for x in filenames):
        print(curdir)

Bonus DLC İçeriği!

Find komutunun (çoğunlukla) düzeltilmiş sürümü:

find . -type d \! -exec bash -c 'set nullglob; test -f "{}"/*.ENDING' \; -print

Ben bir dizinde birden fazla dosya varsa bulma çözümleri ile başarısız olduğunu düşünüyorum . test: ...: binary operator expected*.ENDING
Cristian Ciupitu

next(filter(lambda x: x.endswith('.ENDING'), filenames))ayrıca jeneratör kavrayışı kullanılarak da yazılabilir next(x for x in filenames if x.endswith('.ENDING')).
Cristian Ciupitu

@CristianCiupitu: Gerçek: find komutu kibirli ve gerçekten tam olarak test edilmedi. Jeneratör kavrama - evet bunu yapmanın bir başka güzel yolu.
MikeyB

1
Bence daha güzel bir çözüm, boş bir yinelenebilir için if not any(x.endswith('.ENDING') for x in filenames)herhangi bir geri Falsedönüşe dayanarak kullanmak olacaktır .
Cristian Ciupitu

3

Kabuk genişler *, ancak sizin durumunuzda hiçbir kabuk yoktur, sadece find tarafından yürütülen test komutu . Dolayısıyla varlığı test edilen dosya tam anlamıyla adlandırılır .*.ENDING

Bunun yerine böyle bir şey kullanmalısınız:

find . -type d \! -execdir sh -c 'test -e {}/*.ENDING' \; -print

Bu neden olacaktır sh genişleyen *.ENDINGzaman testi yürütülür.

Kaynak: UX.SE'de globbing bul


Çalışmıyor. Şu hatayı alıyorum: sh: -c: line 0: syntax error near unexpected token (''. Dizin isimlerim 'xyz (dfdf)' biçiminde. Aslında bu bir calibre kütüphanesi.
bambu

1
Denediğimde sh: line 0: test: foo1/bar.ENDING: binary operator expected, biten bir dosya içeren dizin için olsun ENDING.
Jenny D

Bu benim için düz a.ENDING dosya adları ile çalışıyor gibi görünüyor
user9517

Aşağıdaki test dizini yapısına sahibim: test-> test (test) -> test.ending Bu kodu kullandıktan sonra sh: -c: line 0: syntax error near unexpected token ('sh: -c: line 0:' test -e test (test) / *. Ending '). / test (test) `Ama .xyz olarak değiştirdiğimde aynı sonucu alıyorum. Bunun nedeni dizin adı olarak parantezim olması, değil mi? Bunu nasıl düzeltebilirim?
Bambu

3
@bamboo Kabuk yardımcı programlarından vazgeçer ve bu noktada farklı bir çözüm ararım.
user9517

2

Dennis Nolte ve MikeyB'nin cevaplarından esinlenerek bu çözümü buldum:

find . -type d                                                           \
  \! -exec bash -c 'shopt -s failglob; echo "{}"/*.ENDING >/dev/null' \; \
  -print 2>/dev/null

Şu gerçeğe dayanarak çalışır:

eğer failglob kabuk seçeneği ve hiçbir eşleşme bulunamazsa, bir hata mesajı yazdırılır ve komut yürütülmez.

Bu arada, stderr'a yönlendirildi /dev/null.


1

Kişisel olarak perl'de yapardım

#!/usr/bin/perl

use strict;
use warnings;

use File::Find;


#this sub is called by 'find' on each file it traverses. 
sub checkdir {
    #skip non directories. 
    return unless ( -d $File::Find::name );

    #glob will return an empty array if no files math - which evaluates as 'false'
    if ( not glob ( "$File::Find::name/*.ENDING" ) ) {
        print "$File::Find::name does not contain any files that end with '.ENDING'\n";
    }
}

#kick off the search on '.' - set a directory path or list of directories to taste.
#  - you can specify multiple in a list if you so desire. 
find (  \&checkdir, "." );

Hile yapmalı (çok basit test durumumda çalışır).


0

Heres bulmak bir astar.

find ./ -type d ! -regex '.*.ENDING$' -printf "%h\n" | sort -u

Düzenleme : Hata!


İşe yaramaz çünkü içindeki dosyaların değil, dizinlerin adlarını test edersiniz.
Cristian Ciupitu

Bir kez daha denedim. Kötü
Matthew Ife

0
find . -type d '!' -exec sh -c 'ls -1 "{}"|egrep -q "*ENDING$"' ';' -print
  • q egrep'te sessizlik için

  • İle egrepsize gereken regex takas olabilir

  • ls -1 "{}" find komutundan dosya adlarını verir

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.