Linux bash: Çoklu değişken atama


121

Linux bash'da PHP'de aşağıdaki koda benzer bir şey var:

list($var1, $var2, $var3) = function_that_returns_a_three_element_array() ;

yani bir cümlede 3 farklı değişkene karşılık gelen bir değer atarsınız.

Diyelim ki myBashFuntion, "qwert asdfg zxcvb" dizesini standart olarak yazan bash işlevine sahibim. Şunun gibi bir şey yapmak mümkün mü:

(var1 var2 var3) = ( `myBashFuntion param1 param2` )

Eşittir işaretinin solundaki kısım elbette geçerli sözdizimi değildir. Sadece ne istediğimi açıklamaya çalışıyorum.

İşe yarayan şey şudur:

array = ( `myBashFuntion param1 param2` )
echo ${array[0]} ${array[1]} ${array[2]}

Ancak, dizinlenmiş bir dizi, düz değişken adları kadar açıklayıcı değildir.
Ancak şunu yapabilirim:

var1 = ${array[0]} ; var2 = ${array[1]} ; var3 = ${array[2]}

Ancak bunlar kaçınmayı tercih ettiğim 3 ifade daha.

Sadece bir kısayol sözdizimi arıyorum. Mümkün mü?

Yanıtlar:


222

Aklıma gelen ilk şey:

read -r a b c <<<$(echo 1 2 3) ; echo "$a|$b|$c"

çıktı, şaşırtıcı olmayan bir şekilde

1|2|3

4
İlk değişken bir boşluk içeriyorsa, bunu çalıştırmanın bir yolu var mı?
Rucent88

8
@Michael read -d "\n" v1 v2 <<<$(cmd)mükemmel çalışıyor. Teşekkür ederim!
Rucent88

1
@LeeNetherton, iyi bir nokta, ancak birinin echo komutunun dönüş durumuna ihtiyaç duyup duymadığından emin değilim :-) Sanırım bu sözdizimini destekleyen bash yanıtını yazarken daha az yaygındı (varsayılan olarak kurulduğu gibi), gerçi % 100 emin değilim.
Michael Krelin - Hacker

4
@ MichaelKrelin-hacker elbette, dönüş durumu echoanlamsız, ancak bu tekniği, dönüş durumunu önemsediğim bir komut dosyasından birden çok değer döndürmek için kullanıyordum. Bulgularımı paylaşacağımı düşündüm.
Lee Netherton

1
Güvenliğiniz için kullanmalısınız: read -r:do not allow backslashes to escape any characters
Tom Hale

18

Değerleri bir diziye atamak istedim. Yani, genişleyen Michael Krelin'in yaklaşımını yaptım:

read a[{1..3}] <<< $(echo 2 4 6); echo "${a[1]}|${a[2]}|${a[3]}"

hangi sonuç:

2|4|6 

beklenildiği gibi.


2
Değerleri bir diziye yerleştirmek için, soruda bahsettiğim basit bir çözüm var:a=( $(echo 2 4 6) ) ; echo ${a[0]} ${a[1]} ${a[2]}
GetFree

Evet, bunu gözden kaçırmıştım. Yine de, önerimin daha büyük diziler atamak için daha uygun olduğunu iddia ediyorum.
soundray

@soundray Çözümünüz genişletme ve bir ringa balığı kullanıyor, bash bu senaryoda iyi performans göstereceğinden şüpheliyim (ama kontrol etmedim).
Camilo Martin

Güvenliğiniz için kullanmalısınız: read -r:do not allow backslashes to escape any characters
Tom Hale

5

Bunun yardımcı olabileceğini düşünüyorum ...

Komut dosyalarımda kullanıcı tarafından girilen tarihleri ​​(aa / gg / yyyy) ayırmak için, günü, ayı ve yılı bir dizide saklarım ve ardından değerleri aşağıdaki gibi ayrı değişkenlere koyarım:

DATE_ARRAY=(`echo $2 | sed -e 's/\// /g'`)
MONTH=(`echo ${DATE_ARRAY[0]}`)
DAY=(`echo ${DATE_ARRAY[1]}`)
YEAR=(`echo ${DATE_ARRAY[2]}`)

Neden 4 alt kabuk ve fazladan sed işleminden kaçınmıyorsunuz ve hepsini tek bir satırda yapıyorsunuz:IFS=/ read -r m d y < <(echo 12/29/2009)
Amit Naidu

5

Bazen korkak bir şeyler yapmalısın. Diyelim ki bir komuttan okumak istiyorsunuz (örneğin SDGuero'nun verdiği tarih örneği), ancak birden fazla çataldan kaçınmak istiyorsunuz.

read month day year << DATE_COMMAND
 $(date "+%m %d %Y")
DATE_COMMAND
echo $month $day $year

Ayrıca okuma komutuna da yön verebilirsiniz, ancak daha sonra değişkenleri bir alt kabuk içinde kullanmanız gerekir:

day=n/a; month=n/a; year=n/a
date "+%d %m %Y" | { read day month year ; echo $day $month $year; }
echo $day $month $year

sonuç ...

13 08 2013
n/a n/a n/a

readEğer borunun sağ tarafında okuma komutu var çünkü kuşaklar değil, bunun nedeni komut bir kabuktaki olmaz. Şu readanki kabukta komutu çalıştırmanız gerekiyor , bunu beğenebilirsinizread day month year <<< `date "+%d %m %Y"`
pneumatics

Hayır - read olur, ancak okuduğu değişkenlerin kapsamı, boru hattının alt kabuğu sona erdiğinde kapsam dışında kalır.
Otheus

1
Yorumum , okumanın neden bir alt kabuğun içinde olduğuyla ilgiliydi ve şimdi yazdıklarınızı yanlış anladığımı anlıyorum. Alt kabuğun, bileşik ifadenin etrafındaki kaşlı ayraçları kullandığınız için yaratıldığını kastettiğinizi sanıyordum. Fakat! Bu örneği vermenizin nedeni çatallanmayı önlemekti, ama alt kabuk çatalı da olmayacak mı?
pneumatics

İlk örnek tam olarak bir çatal gerektirir: böylece bash, date komutunu başlatabilir. İkinci örnekte, tarih ve alt kabuğunuz arasında bir ardışık düzen kurarsınız. Bence bugünlerde bash, aslında alt kabuğa ayrılmayacak kadar akıllıca, ama bundan emin değilim. Her halükarda, öyle görünüyor :)
Otheus

0

O'Reilly tarafından yazılan Bash Cookbook'un 5. Bölümü , değişken bir atamadaki '=' işaretinin etrafında boşluk olmaması gerekliliğinin nedenlerini (biraz uzun uzadıya) tartışmaktadır.

MYVAR="something"

Açıklamanın, bir komutun adı ile bir değişkeni ayırt etmekle ilgisi vardır (burada '=' geçerli bir argüman olabilir).

Bunların hepsi biraz olaydan sonra haklı çıkarmaya benziyor, ancak her durumda bir değişkenler listesine atama yönteminden söz edilmiyor.


Evet biliyorum. Okunabilirlik uğruna buraya ve oraya fazladan boşluk ekledim
GetFree

Gerçekten de bu zayıf bir motivasyon: Ya eğer ' ;' geçerli bir argümansa? Yazdığımda ls ; cdhala arar lsve cdboşluklara rağmen. Aradım liste dizinlere istiyorsanız ;ve cdben sadece yazabilirsiniz ls ';' cd.
PieterNuyts
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.