döngü için bash cinsinden çoklu dosya türlerini listeler


4

Görüntüleri bir klasöre dönüştüren bir komut dosyası yazdım. Betik bir for döngüsü kullanır:

i = "1"
* .jpg dosyasındaki dosyalar için; yap
     outputFile = $ (echo "image" $ (eko $ i))
     "$ dosya" dönüştürmek -resize 50x50 $ outputFile
     i = $ [i 1 +]
tamam

Yapmak istediğim komut dosyasının birden fazla dosya türü uzantısında çalışmasına izin vermek. Şimdi yapmaya çalıştım:

* .jpg * .JPG * .jpeg içindeki dosyalar için; yap
....
tamam

Bununla ilgili sorun şu ki, * .JPG ve no * .jpg içeren bir klasörün içindeyseniz, betiğin hiçbir resim olmamasına rağmen i + 1 ile çarpışıyor olması, çünkü for döngüsünü zaten bulmaz Herhangi bir * .jpg * üzerine gider.

Birden çok dosya uzantısını, tür başına kendisini çalıştırmadan nasıl hedefleyebilirim? Örnek, onların sözdizimi böyle bir şeydir:

dosya için [* .jpg | * .Jpg]; yap
...

?
: Bu şekilde benim çıkış klasörü hep böyle etiketlenmiş görüntülerini içerir
image1.jpg
image2.jpg
image3.jpg
.. vb

Bunun yerine ilk çalıştırmak için hiçbir * .jpg çünkü bir klasör eksik image1.jpg ile biten.


... peki ya if [ -e "$file" ]... kullanmak ve ... fisadece dosya varken dönüşüm ve artış yapmak? (Vb bağlantı vb kontrol etmek için diğer testleri kullanabilirsiniz). Jpg adlı bir diziniz olsa bile korumalıdır.
Hastur

Yanıtlar:


6

Çözüm

Nullglob kullanın. Aşağıdaki satırı fordöngüden önce koyun :

shopt -s nullglob

nullglobBu tür bir dosya yoksa, kürenin listeden çıkarıldığı anlamına gelir. Nullglob olmadan gözlemleyin:

$ echo  *.jpg *.JPG *.jpeg
test.jpg *.JPG *.jpeg

Şimdi, nullglob ile:

$ shopt -s nullglob
$ echo  *.jpg *.JPG *.jpeg
test.jpg

Yenilenmiş Komut Dosyası

Komut dosyası tam olabilir:

i=1
shopt -s nullglob
for file in *.jpg *.JPG *.jpeg; do
     convert "$file" -resize 50x50 "image$i.jpg"
     i=$((i+1))
done

Üç not:

  1. Tanımında outputFile, tüm bu echoifadeler gereksizdi.

  2. Kongre sonrasında, .jpgçıktı dosya adınıza bir uzantı ekledim . Uzantıyı gerçekten istemiyorsanız, kaldırın.

  3. Ben yerine $[...]onun daha standart form ile: $((...)).


1
Geçerli dizindeki tüm JPEG'leri bulmanın daha güvenilir bir yolu :file * | grep 'JPEG image data' | cut -d: -f1
Dummy00001

3
  1. Birden fazla farklı (büyük küçük harf duyarsız) aramak istediğiniz için shopt -s nullglobcevap, kullanımı çok iyi bir cevaptır.
  2. Sadece aradığını olursa *.jpg, *.JPGve büyük harf ve küçük harf diğer altı değişik kombinasyonlar yapmak için en kolay şey olurdu

    for file in *.[Jj][Pp][Gg]

    hangi isimleri olan dosyaları arar

    • (bir şey), ardından
    • . (bir süre), ardından
    • Jveya j, ardından
    • Pveya p, ardından
    • G veya g

    Diğer bir deyişle,

    • (bir şey), ardından
    • . (bir süre), ardından
    • "jpg", büyük ve küçük harflerin bir kombinasyonunda
  3. Yani probleminizi çözmenin bir yolu

    shopt -s nullglob
    for file in *.[Jj][Pp][Gg] *.[Jj][Pp][Ee][Gg]
    do …
    
  4. İşin […]püf noktası bilmek iyi bir şey ama daha iyi bir yol var. Size bir kabuk seçeneği olduğunu söyleseydim nocaseglob, ne olduğunu tahmin edebilir misiniz?

    shopt -s nullglob nocaseglob
    for file in *.jpg *.jpeg
    do …
    

    yani şimdi *.jpgdemek

    • (bir şey), ardından
    • . (bir süre), ardından
    • "jpg", büyük ve küçük harflerin bir kombinasyonunda

    ve bu nedenle yukarıdaki komut maç olacak *.jpg, *.JPG, *.Jpg, *.jpeg, *.jPeG, vb

  5. Başka bir yol da extglobgenişletilmiş desen eşleştirme işleçlerini etkinleştirmek için kabuk seçeneğini kullanmaktır . Hala isteyeceksin nullglobve nocaseglob. Genişletilmiş desen eşleştirme operatörleri, hepsi benziyor

    (some_special_character)   (   kalıp listesi   )

    alanlarda açıklık için ilave edilir ve burada pattern-listbir listesi patterns ayrılmış | karakter (ler). Amaçlarınız için en ilginç görünen

    @ ( kalıp listesi )

    bu, listelenen modellerden biriyle eşleşmesi anlamına gelir. Yani şimdi senaryo

    shopt -s nullglob nocaseglob extglob
    for file in *.@(jpg|jpeg)
    do …
    

    Bu biraz daha tipik bir yazı gibi görünebilir, ancak uzantı sayısı arttıkça tradeoff kaymaktadır. Düşünmek,

    for file in *.@(jpg|jpeg|jfif|exif|tif|tiff|gif|bmp|png|svg)

    biraz daha kısa

    for file in *.jpg *.jpeg *.jfif *.exif *.tif *.tiff *.gif *.bmp *.png *.svg
  6. Nerede yapmayı öğrendin $(echo …)? Tabii ki, kesinlikle faydalı olabilir ve hatta bazen de olabilir, ama aşırı kullanıyorsunuz. Söylemesi çok iyi$(some_command(s) …)$(echo …)

    outputFile="image$i"

    ve muhtemelen alıntılara bile ihtiyacınız kalmaz ( atama ifadesinde ).

  7. Tamam, sadece bir kez mazeret alınabilir , çünkü değerinin outputFileiyi huylu olduğunu bildiğiniz için, boş olmayan, özel olmayan karakterlerin ( image) sabit bir dizesinden artı sabit bir dize olarak ayarladığınız bir diziden ayarladığınızdan boş olmayan, özel olmayan karakterler ( 1) ve üzerinde yalnızca önemsiz aritmetik işlemler yaptı. Ancak, genel bir kural olarak, yapmamak için çok iyi bir nedeniniz olmadığı ve ne yaptığınızı bildiğinizden emin olmadığınız sürece, her zaman kabuk değişkenlerine referans vermelisiniz. Bu yüzden convertemriniz, ideal olarak

    convert "$file" -resize 50x50 "$outputFile"

    (etrafında tırnak ile $outputFile.)


-1

Bu kısmı değiştirmek istersiniz:

for file in *.jpg; do

Bundan:

for file in $(ls *.jpg *.JPG); do

4
lsböyle bir for döngüsü içinde kullanılması önerilmez. Neden
ls'in
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.