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?

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

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.


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]}`)

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

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.


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
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.