Linux Kullanıcıları için 2020 Güncellemesi:
Eğer Linux'taysanız muhtemelen yaptığınız gibi güncel bir bash sürümüne (4.4-alpha veya daha iyisi) sahipseniz, Benjamin W.'nin cevabını kullanmalısınız .
Son kontrol ettiğimde hala bash 3.2 kullanan veya daha eski bir bash kullanan Mac OS kullanıyorsanız, sonraki bölüme geçin.
Bash 4.3 veya öncesi için yanıt
Çıktıyı find
bir bash
diziye almak için bir çözüm :
array=()
while IFS= read -r -d $'\0'; do
array+=("$REPLY")
done < <(find . -name "${input}" -print0)
Bu aldatıcıdır, çünkü genel olarak dosya adlarında boşluklar, yeni satırlar ve diğer komut dosyası düşman karakterleri olabilir. find
Dosya adlarını kullanmanın ve güvenli bir şekilde birbirinden ayırmanın tek yolu -print0
, dosya adlarını bir boş karakterle ayrılmış olarak yazdıran kullanmaktır . Bash'in readarray
/ mapfile
işlevlerinin boş değerlerle ayrılmış dizgeleri desteklemesi ancak desteklememesi halinde bu pek bir rahatsızlık olmaz. Bash read
yapar ve bu bizi yukarıdaki döngüye götürür.
[Bu yanıt ilk olarak 2014'te yazılmıştır. Bash'in yeni bir sürümüne sahipseniz, lütfen aşağıdaki güncellemeye bakın.]
Nasıl çalışır
İlk satır boş bir dizi oluşturur: array=()
İfade her read
yürütüldüğünde, standart girdiden boş değerle ayrılmış bir dosya adı okunur. -r
Seçenek söyler read
yalnız ters eğik çizgi karakterleri bırakmak. , -d $'\0'
Girdinin read
null ile ayrıldığını söyler . Biz adını ihmal yana read
, kabuk varsayılan adları içine giriş koyar: REPLY
.
array+=("$REPLY")
İfadesi diziye yeni bir dosya adı ekler array
.
Son satır find
, while
döngünün standart girdisinin çıktısını sağlamak için yeniden yönlendirme ve komut ikamesini birleştirir .
Neden süreç ikamesi kullanılıyor?
Süreç ikamesi kullanmadıysak, döngü şu şekilde yazılabilir:
array=()
find . -name "${input}" -print0 >tmpfile
while IFS= read -r -d $'\0'; do
array+=("$REPLY")
done <tmpfile
rm -f tmpfile
Yukarıda find
öğesinin çıktısı geçici bir dosyada saklanır ve bu dosya while döngüsüne standart girdi olarak kullanılır. Süreç ikame fikri, bu tür geçici dosyaları gereksiz kılmaktır. Böylece, while
döngünün stdinini alması yerine, onun stdinini almasını tmpfile
sağlayabiliriz <(find . -name ${input} -print0)
.
Süreç ikamesi oldukça faydalıdır. Bir komutun bir dosyadan okumak istediği birçok yerde <(...)
, dosya adı yerine işlem ikamesi belirtebilirsiniz . >(...)
Komutun dosyaya yazmak istediği bir dosya adı yerine kullanılabilen benzer bir form vardır .
Diziler gibi, işlem ikamesi de bash ve diğer gelişmiş kabukların bir özelliğidir. POSIX standardının bir parçası değildir.
Alternatif: lastpipe
İstenirse lastpipe
proses ikamesi yerine kullanılabilir (şapka ipucu: Sezar ):
set +m
shopt -s lastpipe
array=()
find . -name "${input}" -print0 | while IFS= read -r -d $'\0'; do array+=("$REPLY"); done; declare -p array
shopt -s lastpipe
bash'a mevcut kabuktaki boru hattındaki son komutu çalıştırmasını söyler (arka planda değil). Bu şekilde, array
boru hattı tamamlandıktan sonra var olan kalıntılar. Çünkü lastpipe
sadece iş kontrolü kapatılırsa etki eder, koşarız set +m
. (Bir komut dosyasında, komut satırının aksine, iş kontrolü varsayılan olarak kapalıdır.)
Ek Notlar
Aşağıdaki komut, bir kabuk dizisi değil, bir kabuk değişkeni oluşturur:
array=`find . -name "${input}"`
Bir dizi oluşturmak istiyorsanız, find'ın çıktısının etrafına parantez koymanız gerekir. Yani, safça, biri şunları yapabilir:
array=(`find . -name "${input}"`)
Sorun, kabuğun sonuçları üzerinde kelime bölme yapmasıdır, find
böylece dizinin elemanlarının istediğiniz gibi olacağı garanti edilmez.
2019 Güncellemesi
4.4-alfa sürümünden başlayarak, bash artık -d
yukarıdaki döngüye artık gerek kalmaması için bir seçeneği desteklemektedir . Bunun yerine şu kullanılabilir:
mapfile -d $'\0' array < <(find . -name "${input}" -print0)
Bununla ilgili daha fazla bilgi için lütfen Benjamin W.'nin cevabına bakın (ve oy verin) .