Linux bash: przypisanie wielu zmiennych

121

W linux bash istnieje coś podobnego do następującego kodu w PHP:

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

tj. przypisujesz w jednym zdaniu odpowiednią wartość do 3 różnych zmiennych.

Powiedzmy, że mam funkcję bash, myBashFuntionktóra zapisuje na stdout łańcuch „qwert asdfg zxcvb”. Czy można zrobić coś takiego:

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

Część po lewej stronie znaku równości nie jest oczywiście poprawną składnią. Próbuję tylko wyjaśnić, o co proszę.

Co jednak działa, to:

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

Ale tablica indeksowana nie jest tak opisowa, jak zwykłe nazwy zmiennych.
Mogłem jednak po prostu zrobić:

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

Ale to są jeszcze 3 stwierdzenia, których wolałbym uniknąć.

Szukam tylko składni skrótu. Czy to możliwe?

Uwolnić się
źródło

Odpowiedzi:

222

Pierwsza rzecz, która przychodzi mi do głowy:

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

nie jest zaskoczeniem

1|2|3
Michael Krelin - haker
źródło
4
Czy jest w ogóle, aby to zadziałało, jeśli pierwsza zmienna zawiera spację?
Rucent88,
7
@Michael Using read -d "\n" v1 v2 <<<$(cmd)działa doskonale. Dziękuję Ci!
Rucent88
1
@LeeNetherton, słuszna uwaga, chociaż nie jestem pewien, czy potrzebny jest status zwrotu polecenia echo :-) Myślę, że w momencie pisania odpowiedzi bash obsługujący tę składnię był mniej powszechny (jak w instalowanym domyślnie), chociaż ja Nie jestem pewien w 100%.
Michael Krelin - haker
4
@ MichaelKrelin-hacker oczywiście, status zwrotu echojest bezcelowy, ale używałem tej techniki do zwracania wielu wartości ze skryptu, który zwracał mi uwagę na status zwrotu. Pomyślałem, że podzielę się swoimi odkryciami.
Lee Netherton
1
Ze względów bezpieczeństwa należy używać: read -r:do not allow backslashes to escape any characters
Tom Hale
18

Chciałem przypisać wartości do tablicy. Tak więc, rozszerzając podejście Michaela Krelina , zrobiłem:

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

co daje:

2|4|6 

zgodnie z oczekiwaniami.

soundray
źródło
2
Aby umieścić wartości w tablicy jest już proste rozwiązanie, o którym wspomniałem w pytaniu:a=( $(echo 2 4 6) ) ; echo ${a[0]} ${a[1]} ${a[2]}
GetFree
Tak, przeoczyłem to. Twierdziłbym jednak, że moja sugestia lepiej nadaje się do przypisywania większych tablic.
soundray
@soundray Twoje rozwiązanie wykorzystuje rozszerzenie i ciąg znaków, a bash jest tym, czym jest, wątpię, czy będzie dobrze działać w tym scenariuszu (ale nie sprawdziłem).
Camilo Martin,
Ze względów bezpieczeństwa należy używać: read -r:do not allow backslashes to escape any characters
Tom Hale
5

Myślę, że to może pomóc ...

Aby rozbić daty wprowadzone przez użytkownika (mm / dd / rrrr) w moich skryptach, przechowuję dzień, miesiąc i rok w tablicy, a następnie umieszczam wartości w oddzielnych zmiennych w następujący sposób:

DATE_ARRAY=(`echo $2 | sed -e 's/\// /g'`)
MONTH=(`echo ${DATE_ARRAY[0]}`)
DAY=(`echo ${DATE_ARRAY[1]}`)
YEAR=(`echo ${DATE_ARRAY[2]}`)
SDGuero
źródło
Dlaczego nie uniknąć 4 podpowłok i dodatkowego procesu seda i zrobić to wszystko w jednej linii:IFS=/ read -r m d y < <(echo 12/29/2009)
Amit Naidu
5

Czasami trzeba zrobić coś fajnego. Powiedzmy, że chcesz czytać z polecenia (na przykład data przez SDGuero), ale chcesz uniknąć wielu rozwidleń.

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

Możesz również przesłać potokiem do polecenia odczytu, ale wtedy musiałbyś użyć zmiennych w podpowłoce:

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

prowadzi do...

13 08 2013
n/a n/a n/a
Otheus
źródło
readKomenda się nie dzieje w podpowłoce powodu szelki, to dlatego, że masz polecenie odczytu po prawej stronie rury. Musisz uruchomić readpolecenie w bieżącej powłoce, co możesz zrobić jakread day month year <<< `date "+%d %m %Y"`
pneumatyka
Nie - read zdarza się, ale zakres zmiennych, do których wczytuje, wykracza poza zakres, gdy kończy się podpowłoka potoku.
Otheus
1
Mój komentarz dotyczył powodu, dla którego odczyt następuje w podpowłoce i teraz zdaję sobie sprawę, że źle odczytałem to, co napisałeś. Myślałem, że chodziło Ci o to, że podpowłoka została utworzona, ponieważ użyłeś nawiasów klamrowych wokół instrukcji złożonej. Ale! Powodem, dla którego podałeś ten przykład, było uniknięcie rozwidlenia, ale czy też nie widelec podpowłoki?
pneumatyka
Pierwszy przykład wymaga dokładnie jednego rozwidlenia: aby bash mógł uruchomić polecenie date. W drugim przykładzie konfigurujesz potok między datą a podpowłoką. Myślę, że w dzisiejszych czasach bash jest na tyle sprytny, że nie rozwidla się do podpowłoki, ale nie jestem tego pewien. W każdym razie tak wygląda :)
Otheus
0

Rozdział 5 książki kucharskiej Bash autorstwa O'Reilly omawia (dość obszernie) powody, dla których w przypisaniu zmiennej nie ma spacji wokół znaku „=”

MYVAR="something"

Wyjaśnienie ma coś wspólnego z rozróżnieniem między nazwą polecenia a zmienną (gdzie „=” może być prawidłowym argumentem).

To wszystko wydaje się trochę jak uzasadnianie po zdarzeniu, ale w każdym razie nie ma wzmianki o sposobie przypisywania do listy zmiennych.

pavium
źródło
Tak, wiem. Po prostu dodałem dodatkowe spacje tu i tam ze względu na czytelność
GetFree
Rzeczywiście, jest to słaba motywacja: a co, jeśli „ ;” jest ważnym argumentem? Kiedy piszę ls ; cdto nadal dzwoni lsi cdmimo spacji. Jeśli chcę wyświetlić listę nazwanych katalogów ;i cdmogę po prostu wpisać ls ';' cd.
PieterNuyts