Linux-Bash: Zuweisung mehrerer Variablen

120

Gibt es in Linux Bash etwas Ähnliches wie den folgenden Code in PHP:

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

dh Sie weisen 3 verschiedenen Variablen in einem Satz einen entsprechenden Wert zu.

myBashFuntionAngenommen , ich habe die Bash-Funktion , die schreibt, um die Zeichenfolge "qwert asdfg zxcvb" zu stdouten. Ist es möglich, etwas zu tun wie:

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

Der Teil links vom Gleichheitszeichen ist natürlich keine gültige Syntax. Ich versuche nur zu erklären, wonach ich frage.

Was jedoch funktioniert, ist Folgendes:

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

Ein indiziertes Array ist jedoch nicht so beschreibend wie einfache Variablennamen.
Ich könnte jedoch einfach Folgendes tun:

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

Aber das sind 3 weitere Aussagen, die ich lieber vermeiden würde.

Ich suche nur nach einer Verknüpfungssyntax. Ist es möglich?

GetFree
quelle

Antworten:

221

Das erste, was mir in den Sinn kommt:

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

Ausgabe ist nicht überraschend

1|2|3
Michael Krelin - Hacker
quelle
4
Gibt es überhaupt eine Möglichkeit, dies zum Laufen zu bringen, wenn die erste Variable ein Leerzeichen enthält?
Rucent88
7
@ Michael Using read -d "\n" v1 v2 <<<$(cmd)funktioniert perfekt. Danke dir!
Rucent88
1
@LeeNetherton, guter Punkt, obwohl ich nicht sicher bin, ob man den Rückgabestatus des Echo-Befehls benötigt :-) Ich denke, zum Zeitpunkt des Schreibens war die Antwort-Bash, die diese Syntax unterstützt, weniger verbreitet (wie standardmäßig installiert), obwohl ich bin mir nicht 100% sicher.
Michael Krelin - Hacker
4
@ MichaelKrelin-Hacker sicher, der Rückgabestatus von echoist sinnlos, aber ich habe diese Technik verwendet, um mehrere Werte aus einem Skript zurückzugeben, bei dem mir der Rückgabestatus wichtig war. Ich dachte, ich würde meine Erkenntnisse teilen.
Lee Netherton
1
Aus Sicherheitsgründen sollten Sie verwenden: read -r:do not allow backslashes to escape any characters
Tom Hale
18

Ich wollte die Werte einem Array zuweisen. Als ich Michael Krelins Ansatz erweiterte , tat ich Folgendes:

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

was ergibt:

2|4|6 

wie erwartet.

Soundray
quelle
2
Um die Werte in ein Array zu setzen, gibt es bereits eine einfache Lösung, die ich in der Frage erwähnt habe:a=( $(echo 2 4 6) ) ; echo ${a[0]} ${a[1]} ${a[2]}
GetFree
Ja, das hatte ich übersehen. Ich würde jedoch argumentieren, dass mein Vorschlag besser für die Zuweisung größerer Arrays geeignet ist.
Soundray
@soundray Ihre Lösung verwendet Expansion und einen Herestring. Bash ist das, was es ist. Ich bezweifle, dass es in diesem Szenario gut funktioniert (aber ich habe es nicht überprüft).
Camilo Martin
Aus Sicherheitsgründen sollten Sie verwenden: read -r:do not allow backslashes to escape any characters
Tom Hale
5

Ich denke, das könnte helfen ...

Um vom Benutzer eingegebene Daten (MM / TT / JJJJ) in meinen Skripten aufzuschlüsseln, speichere ich Tag, Monat und Jahr in einem Array und füge die Werte dann wie folgt in separate Variablen ein:

DATE_ARRAY=(`echo $2 | sed -e 's/\// /g'`)
MONTH=(`echo ${DATE_ARRAY[0]}`)
DAY=(`echo ${DATE_ARRAY[1]}`)
YEAR=(`echo ${DATE_ARRAY[2]}`)
SDGuero
quelle
Warum vermeiden Sie nicht 4 Unterschalen plus einen zusätzlichen Sedierungsprozess und machen Sie das alles in einer Zeile:IFS=/ read -r m d y < <(echo 12/29/2009)
Amit Naidu
5

Manchmal muss man etwas Funky machen. Angenommen, Sie möchten aus einem Befehl lesen (z. B. das Datumsbeispiel von SDGuero), möchten jedoch mehrere Gabeln vermeiden.

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

Sie könnten auch in den Befehl read einleiten, müssten dann aber die Variablen in einer Subshell verwenden:

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

führt zu ...

13 08 2013
n/a n/a n/a
Otheus
quelle
Der readBefehl kommt aufgrund der geschweiften Klammern nicht in einer Unterschale vor, sondern weil Sie den Lesebefehl auf der rechten Seite der Pipe haben. Sie müssen den readBefehl in der aktuellen Shell ausführen , was Sie tun könnenread day month year <<< `date "+%d %m %Y"`
Pneumatik
Nein - das read passiert, aber der Bereich der Variablen, in die es eingelesen wird, fällt aus dem Bereich heraus, wenn die Unterschale der Pipeline endet.
Otheus
1
In meinem Kommentar ging es um den Grund, warum das Lesen in einer Unterschale stattfindet, und mir ist jetzt klar, dass ich falsch verstanden habe, was Sie geschrieben haben. Ich dachte, Sie meinten, dass die Unterschale erstellt wurde, weil Sie die geschweiften Klammern um die zusammengesetzte Anweisung verwendet haben. Aber! Der Grund, warum Sie dieses Beispiel gegeben haben, war, das Gabeln zu vermeiden, und wird die Subshell-Gabel nicht auch?
Pneumatik
Das erste Beispiel erfordert genau eine Gabelung: Damit bash den Befehl date starten kann. Im zweiten Beispiel richten Sie eine Pipeline zwischen Datum und Ihrer Sub-Shell ein. Ich denke, Bash ist heutzutage klug genug, um nicht wirklich in die Subshell einzudringen, aber da bin ich mir nicht sicher. Auf jeden Fall sieht es so aus, als würde es :)
Otheus
0

In Kapitel 5 des Bash Cookbook von O'Reilly werden (ausführlich) die Gründe für die Anforderung in einer Variablenzuweisung erörtert, dass um das Zeichen '=' keine Leerzeichen vorhanden sind

MYVAR="something"

Die Erklärung hat etwas mit der Unterscheidung zwischen dem Namen eines Befehls und einer Variablen zu tun (wobei '=' ein gültiges Argument sein kann).

Dies alles scheint ein wenig wie eine Rechtfertigung nach dem Ereignis zu sein, aber auf jeden Fall wird keine Methode zum Zuweisen zu einer Liste von Variablen erwähnt.

Pavium
quelle
Ja, ich weiß. Ich habe nur hier und da zusätzliche Leerzeichen hinzugefügt, um die Lesbarkeit zu
gewährleisten
In der Tat ist das eine schlechte Motivation: Was ist, wenn ' ;' ein gültiges Argument ist? Wenn ich schreibe ls ; cd, ruft es immer noch lsund cdtrotz der Leerzeichen. Wenn ich aufgerufene Verzeichnisse auflisten möchte ;und cdeinfach tippen kann ls ';' cd.
PieterNuyts