bashでグローバル変数を子プロセスにエクスポートする方法

bashでグローバル変数を子プロセスにエクスポートする方法

私はOpenboxウィンドウマネージャでArchとbashを使用しています。
すべてが最新の状態です。
Openboxは次のように構成されています。rc.xml

内部的には、通常、必要な一連の便利なコマンドをショートカットに接続するためrc.xmlに呼び出します。bash -c 'command1; command2; etc'

rc.xml次のように定義されたショートカットがあります

<keybind key="1"><action name="Execute"><command>bash -c '
command1;
command2;
etc;
yad --timeout=1 --text="$pos_x x $pos_y";
'</command></action></keybind>

$pos_xグローバルに定義されて表示されない変数を除いて、すべてが期待どおりに機能し、完全に機能します$pos_y

これは.bashrc次のように定義されます。

export pos_x=1000  
export pos_y=500  

新しいbashシェルターミナルウィンドウを開いて入力すると、予想される1000 x 500が
echo "$pos_x x $pos_y"
表示されます。

ただし、この新しい端末ウィンドウに入力すると、 bash -c 'echo "$pos_x x $pos_y"'
子プロセスはグローバル変数を継承しないため、何も表示されません。

入力すると bash -c 'source ~/.bashrc; echo "$pos_x x $pos_y"'
何も表示されないため、子プロセスから.bashrcをインポートすることは役に立ちません。

定義されたグローバル変数を.bashrc子プロセスに渡すには?

私は周りを見回したが、答えが見つかりませんでした。

答え1

Archのデフォルト設定には、~/.bashrcファイルの上部に次の行が含まれています。

# If not running interactively, don't do anything
[[ $- != *i* ]] && return

これにより、非対話型シェルはその行からファイルの読み取りを停止します。bash -c非対話型シェルが起動されるため、ファイル~/.bashrc全体を読み取ることができないため、変数は定義されません。

したがって、次のことを試すことができます。

  1. ~/.profile代わりに変数を入れてください~/.bashrc。とにかく、これはグローバル変数の自然な場所です。ログイン管理者がこの内容を読む限り、/.profile機能します。

  2. 別のファイルを使用してください。そこに変数定義を入れる必要はありません~/.bashrc。変数定義を入れて~/fooからコマンドを実行するだけですbash -c '. ~/foo; echo "$pos_x x $pos_y"

  3. 読み取りを停止する最初の部分に表示された行の上に変数定義を配置します~/.bashrc

答え2

~からGNU Bash マニュアル、6.2 Bash 起動ファイル:

Bashが対話型ログインシェルとして呼び出される場合/etc/profile、またはファイルが存在する場合は、最初にファイルからコマンドを読み込んで実行する --login オプションを持つ非対話型シェルとして使用されます。ファイルを読み込んだ後~/.bash_profile、、~/.bash_login順に探して~/.profile命令を読み出して実行する。 最初存在し、読むことができます。 ...

Bashが非対話式で始まるときたとえば、シェルスクリプトを実行するには、環境でBASH_ENV変数を見つけてその値が表示されたら拡張し、拡張値を読み取って実行するファイル名として使用します。

したがって、環境を正しく設定するには、Bashがインタラクティブになっているのか非対話式になっても、単に持つだけでは不十分であり、変数を設定してそれを指して~/.bash_env対話BASH_ENVモードで明示的にインポートする必要があります。

Bash関連のエントリをBash関連のファイルに入れ、~/.profile他のシェルで動作し続ける一般設定を維持します(いつかログインシェルを変更することにした場合)。

まず、~/.bash_profile次の内容でファイルを作成します。

 [ -f "$HOME/.profile" ] && source "$HOME/.profile"

 if [ -z "$POSIXLY_CORRECT" ]; then
     [ -z "$BASH_ENV" ] && export BASH_ENV="$HOME/.bash_env"
     source "$BASH_ENV"
 fi

"$HOME/.bash_env"次に、すべてのBash関連の変数と関数を含むファイルを作成します。

順序が重要です。ソース行を~/.profile一番上に置くと、~/.bash_profileBashの実行時にそこに定義されている変数をオーバーライドできます。

BASH_ENV変数が参照するファイルが、リモートシェルデーモン(通常rshd)またはセキュアシェルデーモンによって呼び出されたときに取得されたものであることを確認していませんsshd。 Bashのマニュアルを再び引用するには、

Bashがこのように非対話型で実行されていると判断した場合、コマンドを読み込んで実行します~/.bashrc(ファイルが存在して読み取れる場合)。

以下を含むものを作成することをお勧め~/.bashrcします。

 if [ -z "$POSIXLY_CORRECT" ]; then
     [ -z "$BASH_ENV" ] && export BASH_ENV="$HOME/.bash_env"
     source "$BASH_ENV"
 fi

この場合、以下を簡素化できます~/.bash_profile

 [ -f "$HOME/.profile" ] && source "$HOME/.profile"
 [ -f "$HOME/.bashrc" ] && source "$HOME/.bashrc"

最後に、次の項目に複数の項目が含まれないように保護したいと思います~/.bash_env

[ -n "$BASH_ENV_VERSION" ] && return 0
BASH_ENV_VERSION=.....

...

export~/.bash_env注:現在のシェルから関数定義にアクセスできるようにするには、スクリプトをインポートする必要があるため、変数(またはファイル全体のすべての変数)を指定することは意味がありません。同じ理由で、私たちが作成するファイルにshebang行は必要ありません。

対話型ログインシェルと非対話型シェルの両方を扱いました。注意深い読者は、不足している部分がログインではなく対話型シェルであることに反対する可能性があります。幸いなことに、上記の手順では次の手順を実行します。

ログインシェルではなく対話型シェルを起動すると、Bash はファイルが存在する場合は ~/.bashrc からコマンドを読み込み実行します。

関連情報