1つのシェルスクリプトから別のシェルスクリプトにすべての変数を渡しますか?


192

次の名前のシェル/ bashスクリプトがあるとtest.shします。

#!/bin/bash

TESTVARIABLE=hellohelloheloo
./test2.sh

test2.shはこのように見えます:

#!/bin/bash

echo ${TESTVARIABLE}

これは動作しません。私はこれがやり過ぎなので、すべての変数をパラメーターとして渡したくありません。

別の方法はありますか?


1つのアイデアは、変数をファイルに保存してから、別のスクリプトでロードすることです。
ロドリゴ

@Rodrigo私は以前、スクリプトの実行間で値を「保存」するために同様のアプローチを使用しましたが、ある程度成功しました。覚えておくべきことの1つは、スクリプトの複数のインスタンスが実行されると、事態が不安定になる可能性があることです。しかし、それらをbash割り当て形式で保存した場合、ファイルをソースして変数をインポートすることができます
FatalError

回答:


264

基本的に2つのオプションがあります。

  1. export TESTVARIABLE2番目のスクリプトを実行する前に、変数を環境変数()にします。
  2. つまり、2番目のスクリプトを入手. test2.shします。つまり、同じシェルで実行されます。これにより、配列などのより複雑な変数を簡単に共有できるようになりますが、他のスクリプトがソースシェルの変数を変更することもできます。

更新:

を使用exportして環境変数を設定するには、既存の変数を使用できます。

A=10
# ...
export A

これはとの両方bashで機能するはずshです。 bashまた、次のように組み合わせることができます。

export A=10

これは でも機能しますsh(たまたまbash、あなたはecho $SHELLチェックに使用できます)。しかしsh、それがすべてで機能することが保証されているとは私は思わないので、安全にプレイしてそれらを分離するのが最善です。

この方法でエクスポートした変数は、実行するスクリプトで表示されます。次に例を示します。

灰:

#!/bin/sh

MESSAGE="hello"
export MESSAGE
./b.sh

b.sh:

#!/bin/sh

echo "The message is: $MESSAGE"

次に:

$ ./a.sh
The message is: hello

これらが両方ともシェルスクリプトであるという事実も、偶発的なものです。環境変数は、実行する任意のプロセスに渡すことができます。たとえば、代わりにpythonを使用した場合、次のようになります。

灰:

#!/bin/sh

MESSAGE="hello"
export MESSAGE
./b.py

b.py:

#!/usr/bin/python

import os

print 'The message is:', os.environ['MESSAGE']

ソーシング:

代わりに、次のように調達できます。

灰:

#!/bin/sh

MESSAGE="hello"

. ./b.sh

b.sh:

#!/bin/sh

echo "The message is: $MESSAGE"

次に:

$ ./a.sh
The message is: hello

これは多かれ少なかれb.sh直接の内容を「インポート」し、それを同じシェルで実行します。アクセスするために変数をエクスポートする必要がないことに注意してください。これにより、すべての変数が暗黙的に共有され、他のスクリプトがシェルで変数を追加/削除/変更できるようになります。もちろん、このモデルでは、両方のスクリプトが同じ言語(shまたはbash)である必要があります。メッセージをやり取りする方法の例を示します。

灰:

#!/bin/sh

MESSAGE="hello"

. ./b.sh

echo "[A] The message is: $MESSAGE"

b.sh:

#!/bin/sh

echo "[B] The message is: $MESSAGE"

MESSAGE="goodbye"

次に:

$ ./a.sh
[B] The message is: hello
[A] The message is: goodbye

これはでも同様に機能しbashます。また、配列や連想配列のように、環境変数として表現できなかった(少なくともユーザーの負担が大きくなければ)より複雑なデータを簡単に共有できるようになります。


1
$ 1をサブシェルに渡す必要がある場合( 'sudo sh -c ...'がスクリプトから呼び出されるため)$ 1を環境変数に押し込んでエクスポートし、コマンドで変数を使用する必要がありますか?
Urhixidur

sudoアクセス権が必要な場合は、sudo -E ...を使用して環境変数を保持することを追加するだけです。
yucer

2
@FatalError「。./b.sh」を呼び出す最後のa.shの魔法について説明してください。最初のドットの意味は何ですか?それは素晴らしいところで動作します!
Deian

変数と値をファイルに設定して、そのように共有することもできます
newshorts

@Deian、ピリオド(ドット)は、「ソース」に組み込まれたbashの省略形です
Kirill Kost

27

致命的なエラーは簡単な可能性を与えました:2番目のスクリプトを入手してください!この2番目のスクリプトがいくつかの貴重な変数を変更するのではないかと心配している場合は、いつでもサブシェルで取得できます。

( . ./test2.sh )

括弧はソースがサブシェルで発生するようにするため、親シェルは変更test2.shが実行される可能性があることを認識しません。


ここで必ず参照する必要がある別の可能性がありますset -a

POSIX setリファレンスから:

-a:このオプションがオンの場合、割り当てが実行される変数ごとにエクスポート属性が設定されます。IEEE Std 1003.1-2001、Section 4.21、Variable AssignmentのBase Definitionsを参照してください。割り当てがコマンドのユーティリティ名の前にある場合、エクスポート属性は、ユーティリティが完了した後、現在の実行環境で永続化されません。ただし、特殊な組み込みユーティリティの前の1つにより、エクスポート属性がビルド後に永続化されます。で完了しました。コマンドのユーティリティ名の前に割り当てがない場合、または割り当てがgetoptsまたはreadの操作の結果である場合 ユーティリティでは、エクスポート属性は変数が設定解除されるまで持続します。

Bashマニュアルから:

-a:後続のコマンドの環境にエクスポートするために変更または作成された変数と関数をマークします。

だからあなたの場合:

set -a
TESTVARIABLE=hellohelloheloo
# ...
# Here put all the variables that will be marked for export
# and that will be available from within test2 (and all other commands).
# If test2 modifies the variables, the modifications will never be
# seen in the present script!
set +a

./test2.sh

 # Here, even if test2 modifies TESTVARIABLE, you'll still have
 # TESTVARIABLE=hellohelloheloo

仕様ではset -a、変数がエクスポート用にマークされていることのみが指定されていることに注意してください。あれは:

set -a
a=b
set +a
a=c
bash -c 'echo "$a"'

c空行ではなくエコーしますb(つまりset +a、エクスポートのマークを解除しません。また、エクスポートされた環境でのみ割り当ての値を「保存」しません)。もちろん、これは最も自然な動作です。

結論:set -a/ を使用set +aすると、すべての変数を手動でエクスポートするよりも退屈な作業になりません。同じシェル言語で記述されたものだけでなく、どのコマンドでも機能するため、2番目のスクリプトを調達するよりも優れています。


18

実際には、エクスポートして設定を解除したり、ソースを再設定したりするよりも簡単な方法があります(少なくともbashでは、環境変数を手動で渡すことができる限り)。

a.shを

#!/bin/bash
secret="winkle my tinkle"
echo Yo, lemme tell you \"$secret\", b.sh!
Message=$secret ./b.sh

そしてb.shが

#!/bin/bash
echo I heard \"$Message\", yo

観測された出力は

[rob @ Archie test] $ ./a.sh
Yo、lemmeが "winkle my tinkle"と言って、b.sh!
「ティンクルマイティンクル」と聞いたよ

最後の行のマジック嘘a.shMessage、の呼び出しの間だけ./b.sh、の値に設定されているsecretからa.sh。基本的には、名前付きパラメーター/引数に少し似ています。それ以上に、それ$DISPLAYはアプリケーションがどのXサーバーを起動するかを制御するのような変数に対しても機能します。

環境変数のリストの長さは無限ではありません。比較的バニラカーネルのあるシステムでxargs --show-limitsは、引数バッファの最大サイズは2094486バイトです。理論的には、データがそれよりも大きい場合、シェルスクリプトを間違って使用しています(パイプ、誰か?)


7

致命的なエラーの答えに加えて、変数を別のシェルスクリプトに渡す方法がもう1つあります。

上記の解決策にはいくつかの欠点があります。

  1. using Export :これは、変数がスコープ外に存在する原因となりますが、これは良い設計手法ではありません。
  2. using Source :別のファイルをソースとしている他のシェルスクリプトファイルで、名前の衝突や事前定義された変数の誤った上書きを引き起こす可能性があります。

私たちが使用できる別の簡単な解決策があります。あなたが投稿した例を考えると、

test.sh

#!/bin/bash

TESTVARIABLE=hellohelloheloo
./test2.sh "$TESTVARIABLE"

test2.sh

#!/bin/bash

echo $1

出力

hellohelloheloo

また、""マルチワード文字列を渡す場合は必要であることにも注意してください。もう一例

master.sh

#!/bin/bash
echo in master.sh
var1="hello world"
sh slave1.sh $var1
sh slave2.sh "$var1"
echo back to master

slave1.sh

#!/bin/bash
echo in slave1.sh
echo value :$1

slave2.sh

#!/bin/bash
echo in slave2.sh
echo value : $1

出力

in master.sh
in slave1.sh
value :"hello
in slave2.sh
value :"hello world"

このリンクで適切に説明されている理由により発生します


6
使用sourceは実際には良いことです。あなたの心配に関して:事前定義された変数の偶発的な上書き、あなたはいつでもサブシェルでソースすることができます。これで問題は完全に解決します。
gniourf_gniourf 2015

@gniourf_gniourfサブシェルにソースする方法?
Toskan、2015

@Toskanこれは私の回答で述べられています:( . ./test2.sh )。括弧は、Bashがその内容をサブシェルで実行するようにします。
gniourf_gniourf

7

Bashでは、次のように括弧を使用してサブシェル内で変数をエクスポートすると、エクスポートされた変数のリークを回避できます。

#!/bin/bash

TESTVARIABLE=hellohelloheloo
(
export TESTVARIABLE    
source ./test2.sh
)

ここでの利点は、コマンドラインからスクリプトを実行した後、$ TESTVARIABLEが環境にリークされないことです。

$ ./test.sh
hellohelloheloo
$ echo $TESTVARIABLE
                            #empty! no leak
$

私はそれを使用しましたが、動作しないようです-私は書きました:#!/ bin / bash for((i = 1; i <= 3; i ++))do(export i source ./script2.sh)done ERROR it言う:./script2.sh:そのようなファイルやディレクトリはあり
ません

トップレベル環境(コマンドライン$プロンプト)にはエクスポートされ$TESTVARIABLEたが表示されないため、サブシェルは実際には必要ありません。エクスポートは、変数のコピー後続の子プロセスに渡すだけです。値をストレージに保存し、後で親プロセススクリプトでそのストレージを読み取る場合を除いて、チェーンをバックアップして変数を親プロセスに渡すことはできません。親スクリプトの2番目のコピーへのパイプは可能ですが、これは同じプロセスではありません。優れた説明はここにあります
DocSalvager 2018

2

別のオプションはを使用することevalです。これは、文字列が信頼できる場合にのみ適しています。最初のスクリプトは変数の割り当てをエコーできます。

echo "VAR=myvalue"

次に:

eval $(./first.sh) ./second.sh

この方法は、環境変数を設定する2番目のスクリプトがbashになく、変数も使用したくない場合に特に重要です。これはexport、変数が機密であり、永続化したくないためと考えられます。


1

もう1つの方法は、名前付きパイプを使用することです。名前付きパイプは、異なるプロセス間でメッセージを同期して送信する方法を提供しました。

A.bash:

#!/bin/bash
msg="The Message"
echo $msg > A.pipe

B.bash:

#!/bin/bash
msg=`cat ./A.pipe`
echo "message from A : $msg"

使用法:

$ mkfifo A.pipe #You have to create it once
$ ./A.bash & ./B.bash # you have to run your scripts at the same time

B.bashはメッセージを待ち、A.bashがメッセージを送信するとすぐに、B.bashは処理を続行します。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.