Diğer cevaplar komutunun çıktısı boşluk içeriyorsa (oldukça sık olan) kırmak ya da benzeri karakterler topak olacaktır *, ?, [...].
Öğe başına bir satır olacak şekilde dizideki bir komutun çıktısını elde etmek için esasen 3 yol vardır:
Bash≥4 kullanımıyla mapfile— bu en verimli:
mapfile -t my_array < <( my_command )
Aksi takdirde, çıktıyı okuyan bir döngü (daha yavaş, ancak güvenli):
my_array=()
while IFS= read -r line; do
my_array+=( "$line" )
done < <( my_command )
Charles Duffy'nin yorumlarda önerdiği gibi (teşekkürler!), Aşağıdakiler 2 numaralı döngü yönteminden daha iyi performans gösterebilir:
IFS=$'\n' read -r -d '' -a my_array < <( my_command && printf '\0' )
Lütfen tam olarak bu formu kullandığınızdan emin olun, yani aşağıdakilere sahip olduğunuzdan emin olun:
IFS=$'\n' aynı satırda readaçıklamada: bu sadece ortam değişkeni koyacaktır IFS için readdeyimi sadece. Yani betiğinizin geri kalanını hiç etkilemeyecek. Bu değişkenin amacı read, akışı EOL karakterinde kesmeyi söylemektir \n.
-r: bu önemli. Ters eğik çizgileri kaçış dizileri olarak yorumlamamayı söyler read .
-d '': Lütfen -dseçenek ve argümanı arasındaki boşluğa dikkat edin ''. Burada boşluk bırakmazsanız, Bash ifadeyi ayrıştırdığında alıntı kaldırma adımında ''kaybolacağı için hiçbir zaman görülmez . Bu sıfır baytta okumayı durdurmanızı söyler . Bazıları bunu şöyle yazıyor , ama gerçekten gerekli değil. daha iyi.read-d $'\0'-d ''
-a my_arrayakışı okurken readdiziyi doldurmayı söyler my_array.
- Sen kullanmalıdır
printf '\0'deyimi sonra my_command böylece readgetiri 0; Bunu yapmazsanız aslında önemli bir şey değil (sadece bir dönüş kodu alırsınız 1, ki bu kullanmazsanız sorun olmaz set -e- ki yine de yapmamalısınız), ancak bunu aklınızda bulundurun. Daha temiz ve anlamsal olarak daha doğru. Bunun, printf ''herhangi bir çıktı vermeyen durumdan farklı olduğunu unutmayın . orada okumayı mutlu bir şekilde durdurmak için printf '\0'gereken boş bir bayt yazdırır read( -d ''seçeneği hatırlıyor musunuz?).
Yapabiliyorsanız, yani kodunuzun Bash≥4 üzerinde çalışacağından eminseniz, ilk yöntemi kullanın. Ve daha kısa olduğunu da görebilirsiniz.
Kullanmak istiyorsanız read, satırlar okunurken bazı işlemler yapmak istiyorsanız, döngü (yöntem 2) yöntem 3'e göre bir avantaja sahip olabilir: ona doğrudan erişiminiz var ( $lineverdiğim örnekteki değişken aracılığıyla ) ve zaten okunan satırlara da erişebilirsiniz ( ${my_array[@]}verdiğim örnekteki dizi aracılığıyla ).
Not mapfileHer satırda eval'd bir geri arama için bir yol sağlar okumak ve aslında hatta sadece her Bu geri arama aramak için bunu söyleyebilirim N hatları okumak; help mapfileseçeneklere -Cve -coraya bir göz atın . (Bu konudaki fikrim biraz hantal, ancak bazen sadece yapacak basit işleriniz varsa kullanılabilir - bunun neden ilk başta uygulandığını gerçekten anlamıyorum!).
Şimdi size neden aşağıdaki yöntemi anlatacağım:
my_array=( $( my_command) )
boşluk olduğunda bozulur:
$ # I'm using this command to test:
$ echo "one two"; echo "three four"
one two
three four
$ # Now I'm going to use the broken method:
$ my_array=( $( echo "one two"; echo "three four" ) )
$ declare -p my_array
declare -a my_array='([0]="one" [1]="two" [2]="three" [3]="four")'
$ # As you can see, the fields are not the lines
$
$ # Now look at the correct method:
$ mapfile -t my_array < <(echo "one two"; echo "three four")
$ declare -p my_array
declare -a my_array='([0]="one two" [1]="three four")'
$ # Good!
Sonra bazı insanlar IFS=$'\n'düzeltmek için kullanmanızı tavsiye edecek :
$ IFS=$'\n'
$ my_array=( $(echo "one two"; echo "three four") )
$ declare -p my_array
declare -a my_array='([0]="one two" [1]="three four")'
$ # It works!
Ama şimdi kürelerle başka bir komut kullanalım :
$ echo "* one two"; echo "[three four]"
* one two
[three four]
$ IFS=$'\n'
$ my_array=( $(echo "* one two"; echo "[three four]") )
$ declare -p my_array
declare -a my_array='([0]="* one two" [1]="t")'
$ # What?
Bunun nedeni t, geçerli dizinde çağrılan bir dosyam olması… ve bu dosya adı glob ile eşleşiyor [three four]… bu noktada bazı insanlar set -fgenellemeyi devre dışı bırakmak için kullanmanızı tavsiye eder: ama buna bakın: düzeltmek için değiştirmeniz IFSve kullanmanız set -fgerekir. kırık teknik (ve bunu gerçekten düzeltmiyorsunuz bile)! bunu yaparken gerçekten kabuğa karşı savaşıyoruz , kabukla çalışmıyoruz .
$ mapfile -t my_array < <( echo "* one two"; echo "[three four]")
$ declare -p my_array
declare -a my_array='([0]="* one two" [1]="[three four]")'
burada kabuk ile çalışıyoruz!