Linux bash:複数の変数の割り当て


120

Linuxのbashには、PHPの次のコードに似たものが存在しますか。

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

つまり、1つの文で3つの異なる変数に対応する値を割り当てます。

myBashFuntion文字列「qwert asdfg zxcvb」をstdoutに書き込むbash関数があるとします。次のようなことは可能ですか?

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

もちろん、等号の左側の部分は有効な構文ではありません。私が求めていることを説明しようとしているだけです。

ただし、機能するのは次のとおりです。

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

ただし、インデックス付き配列は、単純な変数名ほど説明的ではありません。
しかし、私はただ行うことができました:

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

しかし、これらは、私が避けたい3つのステートメントです。

ショートカット構文を探しています。出来ますか?

回答:


221

私の頭に浮かぶ最初のもの:

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

当然、出力は

1|2|3

4
最初の変数にスペースが含まれている場合にこれを機能させる方法はありますか?
Rucent88 2014年

7
@Michael Using read -d "\n" v1 v2 <<<$(cmd)は完璧に動作します。ありがとうございました!
Rucent88 2014年

1
@LeeNetherton、良い点ですが、echoコマンドの戻りステータスが必要かどうかはわかりません:-)回答を書いている時点では、この構文をサポートするbashはそれほど一般的ではなかったと思います(デフォルトでインストールされている場合と同様)。 100%確実ではありません。
Michael Krelin-ハッカー、2015年

4
@ MichaelKrelin-hacker確かに、戻りステータスechoは無意味ですが、私はこのテクニックを使用して、戻りステータスに関心のあるスクリプトから複数の値を返していました。私の発見を共有したいと思いました。
Lee Netherton、2015年

1
安全のためには、使用する必要がありますread -rdo not allow backslashes to escape any characters
トム・ヘイル

18

値を配列に割り当てたかった。そこで、Michael Krelinのアプローチを拡張して、次のようにしました。

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

これにより、

2|4|6 

予想通り。


2
配列の値を入れるためには、私が質問に記載されたシンプルなソリューションは、すでに存在している:a=( $(echo 2 4 6) ) ; echo ${a[0]} ${a[1]} ${a[2]}
GetFree

はい、見落としました。ただし、私の提案は、より大きな配列を割り当てる方が適していると主張します。
サウンドレイ

@soundrayソリューションは拡張とヘレストリングを使用します。bashは、そのシナリオでうまく機能するとは思えません(ただし、確認しませんでした)。
Camilo Martin

安全のためには、使用する必要がありますread -rdo not allow backslashes to escape any characters
トム・ヘイル

5

これは役立つと思います...

スクリプトでユーザーが入力した日付(mm / dd / yyyy)を分解するために、日、月、年を配列に格納し、次のように値を別々の変数に入れます。

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

なぜ4つのサブシェルプラス余分なsedのプロセスを回避し、そしてちょうど1行ですべてのことをしない:IFS=/ read -r m d y < <(echo 12/29/2009)
アミットNaidu

5

ファンキーなことをしなければならないこともあります。コマンド(たとえば、SDGueroによる日付の例)から読み取りたいが、複数のフォークを避けたいとしましょう。

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

パイプでreadコマンドに渡すこともできますが、サブシェル内で変数を使用する必要があります。

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

結果は...

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

readあなたは、パイプの右側に読み取りコマンドを持っているので、中括弧で、それはだから、コマンドはサブシェルでは発生しません。read現在のシェルでコマンドを実行する必要があります。これは、次のように実行できますread day month year <<< `date "+%d %m %Y"`
ニュー

いいえ- read 起こりますが、パイプラインのサブシェルが終了すると、読み込まれる変数のスコープはスコープから外れます。
Otheus

1
私のコメントは、読み取りがサブシェルで行われる理由についてでしたが、今私はあなたが書いたものを誤って読んだことに気づきました。複合ステートメントの前後に中括弧を使用したため、サブシェルが作成されたのではないかと思いました。だが!その例を挙げたのはフォークを回避するためでしたが、サブシェルフォークもしないのですか?
空気圧

最初の例では、bashがdateコマンドを起動できるように、正確に1つのforkが必要です。2番目の例では、日付とサブシェルの間にパイプラインを設定します。最近のbashは、サブシェルに実際に分岐しないように十分賢いと思いますが、それについてはよくわかりません。とにかく、それはそうであるように見えます :)
Otheus

0

O'ReillyによるBashクックブックの第5章では、「=」記号の前後にスペースを入れないという変数割り当ての要件の理由を(ある程度)議論しています

MYVAR="something"

説明は、コマンドの名前と変数を区別することと関係があります( '='は有効な引数である場合があります)。

これはすべて、イベント後の正当化に少し似ていますが、いずれの場合も、変数のリストに割り当てる方法については言及されていません。


はい、知っています。読みやすさのために、あちこちに余分なスペースを追加しました
GetFree

確かにそれは悪い動機です: ' ;'が有効な引数である場合はどうなりますか?私が書くときls ; cd、それはまだ呼び出すlscd、スペースにもかかわらず。呼び出されたディレクトリを一覧表示したい場合は;cdと入力するだけですls ';' cd
PieterNuyts
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.