Temukan direktori, di mana file dengan akhiran tertentu tidak ada

10

Saya ingin menampilkan semua direktori, yang tidak mengandung file dengan akhiran file tertentu. Karena itu saya mencoba menggunakan kode berikut:

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

Dalam contoh ini saya ingin menampilkan semua direktori, yang tidak berisi file dengan akhiran .ENDING, tetapi ini tidak berfungsi.

Di mana kesalahan saya?

bambu
sumber
Ini bukan duplikat direktori Daftar tidak mengandung file karena pertanyaan itu tidak berurusan dengan wildcard.
Cristian Ciupitu

Jawaban:

7

Inilah solusi dalam tiga langkah:

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 
Jenny D
sumber
2
Satu-liner tanpa file sementara jika menggunakan Bash shell:comm -3 <(find . -type f -name \*ENDING -exec dirname {} \; |sort -u) <(find . -type d |sort -u)
Cristian Ciupitu
4

Kita mulai!

#!/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)

Atau secara bergantian (dan lebih banyak pythonic):

#!/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)

Konten Bonus DLC!

Versi (sebagian besar) dari perintah find:

find . -type d \! -exec bash -c 'set nullglob; test -f "{}"/*.ENDING' \; -print
MikeyB
sumber
Saya pikir solusi temukan gagal dengan test: ...: binary operator expectedjika ada beberapa *.ENDINGfile dalam direktori.
Cristian Ciupitu
next(filter(lambda x: x.endswith('.ENDING'), filenames))bisa juga ditulis menggunakan pemahaman generator yaitu next(x for x in filenames if x.endswith('.ENDING')).
Cristian Ciupitu
@CristianCiupitu: Truth: perintah find adalah hacky dan tidak sepenuhnya diuji. Pemahaman generator - ya itu cara lain yang bagus untuk melakukannya.
MikeyB
1
Saya pikir solusi yang lebih baik akan digunakan if not any(x.endswith('.ENDING') for x in filenames)berdasarkan fakta bahwa setiap pengembalian Falseuntuk iterable kosong.
Cristian Ciupitu
3

Shell memperluas *, tetapi dalam kasus Anda tidak ada shell yang terlibat, hanya perintah uji yang dijalankan oleh find . Oleh karena itu file yang keberadaannya diuji, secara harfiah diberi nama *.ENDING.

Sebaliknya, Anda harus menggunakan sesuatu seperti ini:

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

Ini akan menghasilkan sh ekspansi *.ENDINGketika tes dijalankan.

Sumber: temukan globbing di UX.SE

Dennis Nolte
sumber
Tidak bekerja. Saya mendapatkan kesalahan berikut: sh: -c: line 0: syntax error near unexpected token ('`. Nama direktori saya memiliki format' xyz (dfdf) '. Sebenarnya ini adalah perpustakaan kaliber.
bambu
1
Ketika saya mencobanya, saya mendapatkan sh: line 0: test: foo1/bar.ENDING: binary operator expecteddirektori yang berisi file dengan akhiran ENDING.
Jenny D
Ini sepertinya bekerja untuk saya dengan nama file sederhana .ENDING
user9517
Saya memiliki struktur direktori tes berikut: test-> test (test) -> test.ending Setelah menggunakan kode ini saya mendapatkan sh: -c: line 0: syntax error near unexpected token ('sh: -c: baris 0:' test -e test (test) / *. Ending '. / test (test) `. Tapi ketika saya mengubah .ending ke .xyz saya mendapatkan hasil yang sama. Ini karena saya memiliki bracts sebagai nama direktori, kan? Bagaimana saya bisa memperbaikinya?
bamboo
3
@ Bambu Saya akan menyerah dengan utilitas shell dan mencari solusi yang berbeda pada saat ini.
user9517
2

Terinspirasi oleh jawaban Dennis Nolte dan MikeyB , saya datang dengan solusi ini:

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

Ini bekerja berdasarkan fakta bahwa

jika opsi cangkang failglob diatur, dan tidak ada kecocokan yang ditemukan, pesan kesalahan dicetak dan perintah tidak dijalankan.

Ngomong-ngomong, itu sebabnya stderr dialihkan ke /dev/null.

Cristian Ciupitu
sumber
1

Saya akan melakukannya di perl secara pribadi

#!/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, "." );

Harus melakukan trik (bekerja pada test case saya yang sangat sederhana).

Sobrique
sumber
0

Inilah satu-satunya liner.

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

Sunting : Ups, tidak akan berfungsi.

Matthew Ife
sumber
Tidak berfungsi karena Anda menguji nama direktori, bukan file di dalamnya.
Cristian Ciupitu
Saya sudah mencoba lagi. Badly
Matthew Ife
0
find . -type d '!' -exec sh -c 'ls -1 "{}"|egrep -q "*ENDING$"' ';' -print
  • q di egrep adalah untuk tenang

  • Dengan egrepAnda dapat menukar regex yang Anda butuhkan

  • ls -1 "{}" menampilkan nama file dari perintah find

sk8asd123
sumber