Belirli bir uzantıya sahip tüm dosyalar arasında döngü yapın


110
for i in $(ls);do
    if [ $i = '*.java' ];then
        echo "I do something with the file $i"
    fi
done

Geçerli klasördeki her dosyada döngü yapmak ve belirli bir uzantıyla eşleşip eşleşmediğini kontrol etmek istiyorum. Yukarıdaki kod çalışmıyor, nedenini biliyor musunuz?


4
Peki ya for i in $(ls *.java); do echo "do something with file $i"; done?
2013

if ifadesini düzeltmenin bir yolu yok mu?
AR89

1
Sen karşılaştırdığınız $iliteral dize "* .java" için; burada desen genişletme yapılmaz.
chepner

Sahip olduğunuz if ifadesini düzeltmek için, if [[ $i == *.java ]]; then.. kullanın (çift [[]] s ve tırnaksız * .java'ya dikkat edin).
o diğer adam

2
Ayrıştırmals - kabul etme @ chepner'ın cevabını
glenn jackman

Yanıtlar:


202

Süslü numaralara gerek yok:

for i in *.java; do
    [ -f "$i" ] || break
    ...
done

Koruma, eşleşen dosya yoksa, var olmayan bir dosya adını işlemeye çalışmadan döngünün çıkmasını sağlar *.java. İçinde bash(veya benzer bir şeyi destekleyen mermilerde), nullglobbaşarısız bir eşleşmeyi basitçe yok saymak ve döngünün gövdesine girmemek için seçeneği kullanabilirsiniz .

shopt -s nullglob
for i in *.java; do
    ...
done

5
En basit yolu başka desen eklemektir: for i in *.java *.cpp; do. Eğer etkinleştirilmiş desenleri genişletilmiş varsa bashile shopt -s extglobyazabilirsiniz for i in *.@(java|cpp); do.
chepner

8
Aslında herhangi bir dosyayla eşleşirse olur. shopt -s nullglobEşleşmeyen bir desenin tam anlamıyla işlenmek yerine boş diziye genişlemesi için kullanmanız gerekir .
chepner

1
@zygimantus evet olmalı, mevcut dizin betiğin çalıştığı yer olduğu sürece. Olmak istediğiniz dizinde değilseniz cd, fordöngüye başlamadan önce o dizine
gitmelisiniz

1
@puk Bu, kabuk seçeneklerinize bağlıdır. Varsayılan olarak, eşleşmeyen bir model bir değişmez dize olarak kabul edilir. Sen ayarlayabilirsiniz nullglobboş bir dizinin veya set olarak tedavi etmiş etmek failglobo hata olarak tedavi etmiş etmek. ( failglob
İkisini

3
@chepner Birisi kopyalayıp yapıştırıp çalışmadığını bulabileceğinden, uzman olmayanlar için bunun yanıtta belirtilmesi yararlı olabilir. Mükemmel bir örnek, önemli bir işlevi yerine getirmeden önce tüm " .jpg" dosyalarını " .png" biçimine dönüştüren biri olabilir
puk

13

doğru cevap @ chepner's

EXT=java
for i in *.${EXT}; do
    ...
done

ancak, bir dosya adının belirli bir uzantıya sahip olup olmadığını kontrol etmek için küçük bir ipucu:

EXT=java
for i in *; do
    if [ "${i}" != "${i%.${EXT}}" ];then
        echo "I do something with the file $i"
    fi
done

extyerine bir değişkenle nasıl olur .java?
AR89

13

Yinelemeli olarak alt klasörler ekleyin,

for i in `find . -name "*.java" -type f`; do
    echo "$i"
done

find . -name "*.java" -type f -exec echo \{\} \; yanlış ayrıştırmak yerinefind
umläute

1
Ve yapmazsanız, en azından "$i"döngünün içinden alıntı yapmalısınız .
üçlü

2
Dosyalardan herhangi birinin adında boşluk varsa bu işe yaramaz.
codeforester

1
@codeforester Tam olarak bu sorunu yaşadım ve bu yanıttaki
fsinisi90

7

: Döngü ile biten tüm dosyaların içinden .img, .bin, .txtsonek ve dosya adını yazdırmak:

for i in *.img *.bin *.txt;
do
  echo "$i"
done

Veya yinelemeli bir şekilde (tüm alt dizinlerde de bulun):

for i in `find . -type f -name "*.img" -o -name "*.bin" -o -name "*.txt"`;
do
  echo "$i"
done

3

Dosyalarda dolaşmanın doğru yolu ile ilgili diğer yanıtlara katılıyorum. Ancak OP sordu:

Yukarıdaki kod çalışmıyor, nedenini biliyor musunuz?

Evet!

Mükemmel bir makale testi arasındaki fark nedir, [ve [[?] Diğer farklılıklar arasında, kullanmak olamayacağını ayrıntılı olarak açıklar expression matchingveya pattern matchingiçindeki testkomuta (bunlar için kısaltmadır [)

Yeni test özelliği [[eski test [Örnek

Kalıp eşleştirme = (veya ==) (mevcut değil) [[$ name = a *]] || echo "isim 'a' ile başlamıyor: $ isim"

Normal İfade = ~ (mevcut değil) [[$ (tarih) = ~ ^ Cum \ ... \ 13]] && echo "13'üncü Cuma!"
eşleştirme

Demek senaryonuzun başarısız olmasının nedeni budur. OP [[sözdizimi ile ( [komut kadar çok platformda desteklenmemesi dezavantajına sahip) bir cevapla ilgileniyorsa, cevabımı onu içerecek şekilde düzenlemekten memnuniyet duyarım.

DÜZENLEME: Yanıttaki verilerin bir tablo olarak nasıl biçimlendirileceğine dair herhangi bir açıklama yardımcı olacaktır!


2

@chepner'ın yorumunda söylediği gibi, $ i'yi sabit bir dizeyle karşılaştırıyorsunuz.

Durumu genişletmek ve düzeltmek için normal ifade operatörü = ~ ile [[]] kullanmanız gerekir

Örneğin:

for i in $(ls);do
    if [[ $i =~ .*\.java$ ]];then
        echo "I want to do something with the file $i"
    fi
done

= ~ 'nin sağındaki normal ifade, sol el operatörünün değerine göre test edilir ve tırnak içine alınmamalıdır (alıntılar hata oluşturmaz ancak sabit bir dizeyle karşılaştırılır ve bu nedenle büyük olasılıkla başarısız olur "

ancak @chepner'ın glob kullanarak yukarıdaki cevabı çok daha verimli bir mekanizmadır.


extyerine bir değişkenle nasıl olur .java?
AR89

1
ack, normal ifadeye gerek yok: if [[ $i == *.java ]]veya if [[ $i == *.$ext ]]. Ama ls ayrıştırma
glenn jackman

1

Bu çözümü oldukça kullanışlı buldum. -orSeçeneği şurada kullanır find:

find . -name \*.tex -or -name "*.png" -or -name "*.pdf"

Bu uzantılı dosyaları bulacaksınız tex, pngve pdf.

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.