次の名前のシェル/ bashスクリプトがあるとtest.sh
します。
#!/bin/bash
TESTVARIABLE=hellohelloheloo
./test2.sh
私test2.sh
はこのように見えます:
#!/bin/bash
echo ${TESTVARIABLE}
これは動作しません。私はこれがやり過ぎなので、すべての変数をパラメーターとして渡したくありません。
別の方法はありますか?
次の名前のシェル/ bashスクリプトがあるとtest.sh
します。
#!/bin/bash
TESTVARIABLE=hellohelloheloo
./test2.sh
私test2.sh
はこのように見えます:
#!/bin/bash
echo ${TESTVARIABLE}
これは動作しません。私はこれがやり過ぎなので、すべての変数をパラメーターとして渡したくありません。
別の方法はありますか?
回答:
基本的に2つのオプションがあります。
export TESTVARIABLE
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
ます。また、配列や連想配列のように、環境変数として表現できなかった(少なくともユーザーの負担が大きくなければ)より複雑なデータを簡単に共有できるようになります。
致命的なエラーは簡単な可能性を与えました:2番目のスクリプトを入手してください!この2番目のスクリプトがいくつかの貴重な変数を変更するのではないかと心配している場合は、いつでもサブシェルで取得できます。
( . ./test2.sh )
括弧はソースがサブシェルで発生するようにするため、親シェルは変更test2.sh
が実行される可能性があることを認識しません。
ここで必ず参照する必要がある別の可能性がありますset -a
。
-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番目のスクリプトを調達するよりも優れています。
実際には、エクスポートして設定を解除したり、ソースを再設定したりするよりも簡単な方法があります(少なくとも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.sh
、Message
、の呼び出しの間だけ./b.sh
、の値に設定されているsecret
からa.sh
。基本的には、名前付きパラメーター/引数に少し似ています。それ以上に、それ$DISPLAY
はアプリケーションがどのXサーバーを起動するかを制御するのような変数に対しても機能します。
環境変数のリストの長さは無限ではありません。比較的バニラカーネルのあるシステムでxargs --show-limits
は、引数バッファの最大サイズは2094486バイトです。理論的には、データがそれよりも大きい場合、シェルスクリプトを間違って使用しています(パイプ、誰か?)
致命的なエラーの答えに加えて、変数を別のシェルスクリプトに渡す方法がもう1つあります。
上記の解決策にはいくつかの欠点があります。
using Export
:これは、変数がスコープ外に存在する原因となりますが、これは良い設計手法ではありません。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"
source
は実際には良いことです。あなたの心配に関して:事前定義された変数の偶発的な上書き、あなたはいつでもサブシェルでソースすることができます。これで問題は完全に解決します。
( . ./test2.sh )
。括弧は、Bashがその内容をサブシェルで実行するようにします。
Bashでは、次のように括弧を使用してサブシェル内で変数をエクスポートすると、エクスポートされた変数のリークを回避できます。
#!/bin/bash
TESTVARIABLE=hellohelloheloo
(
export TESTVARIABLE
source ./test2.sh
)
ここでの利点は、コマンドラインからスクリプトを実行した後、$ TESTVARIABLEが環境にリークされないことです。
$ ./test.sh
hellohelloheloo
$ echo $TESTVARIABLE
#empty! no leak
$
$
プロンプト)にはエクスポートされ$TESTVARIABLE
たが表示されないため、サブシェルは実際には必要ありません。エクスポートは、変数のコピーを後続の子プロセスに渡すだけです。値をストレージに保存し、後で親プロセススクリプトでそのストレージを読み取る場合を除いて、チェーンをバックアップして変数を親プロセスに渡すことはできません。親スクリプトの2番目のコピーへのパイプは可能ですが、これは同じプロセスではありません。優れた説明はここにあります。
別のオプションはを使用することeval
です。これは、文字列が信頼できる場合にのみ適しています。最初のスクリプトは変数の割り当てをエコーできます。
echo "VAR=myvalue"
次に:
eval $(./first.sh) ./second.sh
この方法は、環境変数を設定する2番目のスクリプトがbashになく、変数も使用したくない場合に特に重要です。これはexport
、変数が機密であり、永続化したくないためと考えられます。
もう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は処理を続行します。