Seçmeli dosya listesi
Bağlam: OSX Catalina (zSh) ve Ubuntu 16.04 (Bash). OSX terminal komutları:
FILES="$PWD/*" #list of files
echo $FILES
konsola tüm dosyaların bir dizesini döndürür. Şimdilik, işlenecek dizine komut dosyasının bir kopyasını yerleştirmek niyetindeyim. Gelecekte, komut dosyasının işlenecek bir argümanı (dizin) kabul etmesini sağlamayı bekliyorum.
Çalışma dizininde dosya türlerinin (gizli dosyalar değil uzantılar) mevcut olduğunu varsayın:
- .ABC
- .ABC
- .def
- .ghi
- .jkl
- .sh
Yukarıdaki talimatların aşağıdakileri sağlayacak değiştirilmiş örnekleriyle ilgileniyorum:
- yalnızca .abc .ABC ve .def dosya türlerini (uzantıları) açıkça seçin
- .sh ve .jkl dışındaki tüm dosyaları seç
İdeal olarak, büyük / küçük harf duyarlılığını belirtmek için bir komut seçeneği olacaktır.
Yanıtlar
Bunu, bash'daki dizileri kullanarak oldukça kolay bir şekilde yapabilirsiniz (bu, Ubuntu'daki varsayılan kabuktur, macOS'ler daha yeni sürümler için bash veya zsh'dir; bu çözümler bash hakkındadır):
Tüm dosyaları seçin (orijinal komutunuz, biraz değiştirilmiş):
$ shopt -s nullglob $ files=(*) $ echo "${files[@]}" file.abc file.ABC file.def file.ghi file.jkl file.shnullglobSeçeneğin açılması, dizin boşsa boş bir liste verir. Bu seçenek olmadan, dizin boşfilesolsaydı, genişletilmemiş olan bir öğenin listesi olurdu*.Yalnızca adları
.abcveya.ABCveya ile biten dosyaları seçin.def:$ shopt -s nullglob $ files=(*.abc *.ABC *.def) $ echo "${files[@]}" file.abc file.ABC file.defAdları
.shveya ile bitenler dışındaki tüm dosyaları seçin..jkl$ shopt -s extglob nullglob $ files=(!(*.sh|*.jkl)) $ echo "${files[@]}" file.abc file.ABC file.def file.ghiBüyük / küçük harfe duyarsız eşleme
$ shopt -s nocaseglob nullglob $ files=(*abc) $ echo "${files[@]}" file.abc file.ABC
Ayrıca ne yaptığınıza dair bir not. geçerli dizininizdeki tüm dosyaların files="$PWD/*"değerini ayarlamaz $files. Değerini şu şekilde biten bir dizeye ayarlar /*:
$ cd /tmp/current_directory
$ files="$PWD/*"
$ echo "$files"
/tmp/current_directory/*
echo $filesİşe yaradığını düşünmenizin nedeni, alıntı yapılmamış , yani kabuğun genişliyor olmasıydı /tmp/current_directory/*. Ancak, daha sonra dosyaları silerseniz, aynı echokomut basitçe /tmp/current_directory/*, $PWDbunu başlangıçta çalıştırdığınız dizine genişletilmiş olarak yazdırır . Dosyaların listesi değişkenle birlikte kaydedilmez. Burada yaptığım gibi dizileri kullanmak, değişkenin, nerede kullandığınıza bağlı olarak farklı değerlere genişletilebilen glob'u değil, gerçek dosya listesini saklamasını sağlar.
İçinde zsh:
files=($PWD/*.(abc|ABC|DEF)(N))
print -rC1 -- $files # print raw, on one column.
( bu glob (N)için geçerli niteleyici ile, buna boş bir kalıp listesi olur, bir hata bildirmek yerine herhangi bir dosyayla eşleşmez).nullglob$files
Dışındaki dosyalar için .shve .jkl:
set -o extendedglob # needed for the ^ negation operator
files=($PWD/^*.(sh|jkl)(N))
Büyük .ABC/ küçük harfe duyarlı olmayan eşleştirme için ( / .abc/ .Abc...):
set -o extendedglob
files=($PWD/*.(#i)abc(N))
Sizin:
FILES="$PWD/*"
echo $FILES
birkaç hesapta yanlış:
FILES="$PWD/*"dosya listesini $FILEdeğişkende saklamaz . Bu, yalnızca bir değeri depolayabilen skaler bir atamadır. Bunun yerine , kelimenin tam anlamıyla takip edenlerin $FILESiçeriğinde depolar .$PWD/*
İçinde, alıntı yapılmadığı echo $FILESgibi $FILES, içinde bash(ama değil zsh), 'nin genişletilmesi $FILESsplit + glob'a tabidir. Ve bu noktada ve $FILESkarakterlerinin hiçbirini içermediğini $IFS( bölünmüş kısmı tetikleyecektir ) ve $PWDjoker karakterler içermediğini (bu aynı zamanda glob kısmını da tetikleyecektir), değerin listesine genişletildiğini varsayarsak . eşleşen dosyalar.
İçinde zsh, split + glob, parametre genişletme üzerine örtük olarak yapılmaz, bunları açıkça istemeniz gerekir ( $=FILESbölme $~FILESiçin, genelleme $=~FILESiçin, her ikisi için).
O zaman echokeyfi veri çıkarmak için kullanmak , echovarsayılan olarak fazladan işlemede olduğu gibi yanlıştır (içinde zsh, kullanabilir echo -E - $filesveya kullanabilirsiniz print -r -- $files).