Temel adı üst dizinin adı olan belirli bir uzantıya sahip tüm dosyaları bulma


9

Temel adı dosyanın üst dizininin adıyla eşleşen *.pdfbir dizindeki her dosyayı özyinelemeli olarak aramak istiyorum ~/foo.

Örneğin, dizin yapısının ~/fooşöyle göründüğünü varsayın

foo
├── dir1
│   ├── dir1.pdf
│   └── dir1.txt
├── dir2
│   ├── dir2.tex
│   └── spam
│       └── spam.pdf
└── dir3
    ├── dir3.pdf
    └── eggs
        └── eggs.pdf

İstediğim komutu çalıştırmak geri dönecekti

~/foo/dir1/dir1.pdf
~/foo/dir2/spam/spam.pdf
~/foo/dir3/dir3.pdf
~/foo/dir3/eggs/eggs.pdf

Bunu kullanmak findveya başka bir temel yardımcı program mümkün mü ? Bu -regexseçeneği kullanarak yapılabilir varsayalım findama doğru desen yazmak nasıl emin değilim.


Evet, şimdi bir örnek alacağım.
Brian Fitzpatrick

1
@Inian Bir örnek ekledi. Bu yardımcı olur mu?
Brian Fitzpatrick

Yanıtlar:


16

GNU ile find:

find . -regextype egrep -regex '.*/([^/]+)/\1\.pdf'
  • -regextype egrep egrep tarzı regex kullanın.
  • .*/ büyük ebeveyn directires maç.
  • ([^/]+)/ bir gruptaki üst dir ile eşleşir.
  • \1\.pdfbackreferencedosya adını üst dizin olarak eşleştirmek için kullanın .

Güncelleme

Biri (kendim için bir tane) bunun .*yeterince açgözlü olduğunu düşünebilir /, ebeveyn eşleşmesinden hariç tutmak gereksizdir :

find . -regextype egrep -regex '.*/(.+)/\1\.pdf'

Yukarıdaki komut iyi çalışmaz, çünkü şu anlama gelir ./a/b/a/b.pdf:

  • .*/ maçlar ./
  • (.+)/ maçlar a/b/
  • \1.pdf maçlar a/b.pdf

Çok havalı. Keşke bu kadar iyi regex.
Brian Fitzpatrick

Ya find . -regex '.*/\([^/]*\)/\1\.pdf'da BSD ile bile çalışır find.
Stéphane Chazelas

7

find .. -exec sh -c ''Taban adı ve yukarıdaki acil yolla eşleşmek için kabuk yapılarını kullanmak için geleneksel döngü varyantı aşağıda yapılacaktır.

find foo/ -name '*.pdf' -exec sh -c '
    for file; do 
        base="${file##*/}"
        path="${file%/*}"
        if [ "${path##*/}" =  "${base%.*}" ]; then
            printf "%s\n" "$file" 
        fi
    done' sh {} +

Bireysel parametre genişletmelerini dökmek için

  • filekomuttan .pdfdöndürülen dosyanın tam yolunu içerirfind
  • "${file##*/}"yalnızca sondan sonraki bölümü içerir, /yani yalnızca dosyanın taban adını içerir
  • "${file%/*}"nihai /sonuca kadar olan yolu içerir, yani sonucun taban adı kısmı hariç
  • "${path##*/}"Geçen sonra bölümünü içeren /gelen pathdeğişkenin, dosyanın basename yukarıda derhal klasör yolunu yani
  • "${base%.*}"taban adının .pdfuzantısı kaldırılmış kısmını içerir

Dolayısıyla, uzantısız taban adı yukarıdaki hemen klasörün adıyla eşleşirse, yolu yazdırırız.


7

Inian'ın cevabının tersi , yani dizinleri arayın ve belirli bir ada sahip bir dosyayı tutup tutmadıklarını görün.

Aşağıdakiler, bulunan dosyaların dizine göre yol adlarını yazdırır foo:

find foo -type d -exec sh -c '
    for dirpath do
        pathname="$dirpath/${dirpath##*/}.pdf"
        if [ -f "$pathname" ]; then
            printf "%s\n" "$pathname"
        fi
    done' sh {} +

${dirpath##*/}dizin yolunun dosya adı bölümü ile değiştirilir ve ile değiştirilebilir $(basename "$dirpath").

Kısa devre sözdizimini sevenler için:

find foo -type d -exec sh -c '
    for dirpath do
        pathname="$dirpath/${dirpath##*/}.pdf"
        [ -f "$pathname" ] && printf "%s\n" "$pathname"
    done' sh {} +

Bu şekilde yapmanın yararı, dizinlerden daha fazla PDF dosyanızın olmasıdır. Biri sorguyu daha küçük sayıyla (dizin sayısı) sınırlandırırsa, testlerin sayısı azalır.

Örneğin, tek bir dizin 100 PDF dosyası içeriyorsa, bu 100 dosyanın adlarını dizinin dizinine karşı test etmek yerine yalnızca birini algılamaya çalışır.


3

ile zsh:

printf '%s\n' **/*/*.pdf(e@'[[ $REPLY:t = $REPLY:h:t.pdf ]]'@)

**/Simgelerini takip etmeyecek, dikkat edin */.


2

Belirtilmedi, ancak ilgilenen varsa düzenli ifadeleri olmayan bir çözüm.

Biz kullanabilirsiniz find . -type fyararlanmak o zaman, sadece dosyaları elde etmek dirnameve basenamekoşullu yazmak için. Yardımcı programlar aşağıdaki davranışa sahiptir:

$ find . -type f
./dir2/spam/spam.pdf
./dir2/dir2.tex
./dir3/dir3.pdf
./dir3/eggs/eggs.pdf
./dir1/dir1.pdf
./dir1/dir1.txt

basenameyalnızca sondan sonraki dosya adını döndürür /:

$ for file in $(find . -type f); do basename $file; done
spam.pdf
dir2.tex
dir3.pdf
eggs.pdf
dir1.pdf
dir1.txt

dirnametüm yolu finale kadar verir /:

$ for file in $(find . -type f); do dirname $file; done
./dir2/spam
./dir2
./dir3
./dir3/eggs
./dir1
./dir1

Bu nedenle, basename $(dirname $file)dosyanın üst dizinini verir.

$ for file in $(find . -type f); do basename $(dirname $file) ; done
spam
dir2
dir3
eggs
dir1
dir1

Çözüm

Koşullu oluşturmak için yukarıdakileri birleştirin "$(basename $file)" = "$(basename $(dirname $file))".pdf, ardından her bir sonucu yalnızca findo koşul doğru döndürürse yazdırın .

$ while read file; do if [ "$(basename "$file")" = "$(basename "$(dirname "$file")")".pdf ]; then echo $file; fi done < <(find . -type f)
./dir2/spam/spam.pdf
./dir3/dir3.pdf
./dir3/eggs/eggs.pdf
./dir1/dir1.pdf
./Final Thesis/grits/grits.pdf
./Final Thesis/Final Thesis.pdf

Yukarıdaki örnekte, bu davayı ele almak için adında boşluklar içeren bir dizin / dosya ekledik (yorumlardaki @Kusalananda sayesinde)


Bu maalesef Final Thesis.pdf(boşluklu) gibi dosya adlarını kıracaktır .
Kusalananda

@Kusalananda Sabit.
user1717828

0

Her gün Find programında bash globbing, basit döngü üzerinden string testleri alıyorum Bana mantıksız olarak adlandırın ve bu kadar basit bir kod iyi olmasa da benim için hile yapar: okunabilir ve tekrar kullanılabilir, hatta tatmin edici !. Bu nedenle aşağıdakilerin bir kombinasyonunu önermeme izin verin:

Bash globstar : for f in ** ; do ... ** geçerli oturumunuzdaki globstar durumunu kontrol etmek için geçerli dizindeki her dosyaya ve tüm alt klasörlere döner shopt -p globstar. Etkinleştirmek globstar için: shopt -s globstar.

• "dosya" özelliği : pdfif [[ $(file "$f") =~ pdf ]]; then ... için gerçek dosya biçimini kontrol etmek için - sadece dosyanın uzantısı için test etmekten daha sağlam

• basename, dirname : dosya adını, hemen üstündeki dizinin adıyla karşılaştırmak için. basenamedosya adını dirnamedöndürür - tüm dizin yolunu döndürür - iki işlevi birleştirerek yalnızca eşleşen dosyayı içeren bir dizini döndürür. Her birini bir değişkene ( _mydir ve _myf ) koyduktan sonra dize eşleşmesi için = ~ kullanarak basit bir test yaptım .

Bir incelik: Dosya adını, kısayolu "" olan geçerli dizine eşleştirmekten kaçınmak için dosya adındaki "nokta" ları kaldırın. - _myf değişkeninde doğrudan string ikamesi kullandım : ${_myf//./}- çok şık değil ama işe yarıyor. : İle çıkışını önceki geçerli klasörün tam yolu ile birlikte - Pozitif maçlar her dosyanın yolunu döndürür $(pwd)/.

kod

for f in ** ; do
  if [[ $(file "$f") =~ PDF ]]; then
    _mydir="$(basename $(dirname $f))" ; 
    _myf="$(basename $f)" ; 
    [[ "${_myf//./}" =~ "$_mydir" ]] && echo -e "$(pwd)/$f" ; 
  fi ; 
done
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.