Seçmeli dosya listesi

Oct 03 2020

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:

  1. yalnızca .abc .ABC ve .def dosya türlerini (uzantıları) açıkça seçin
  2. .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

3 terdon Oct 03 2020 at 19:50

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):

  1. 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.sh
    

    nullglobSeç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 *.

  2. 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.def
    
  3. Adları .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.ghi
    
    
  4. Bü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.

3 StéphaneChazelas Oct 03 2020 at 21:28

İç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).