bash - 引数 - 子 プロセス 環境 変数 引継ぎ




シェルスクリプトは呼び出し側シェルの環境変数を設定できますか? (14)

私は実行時に、呼び出し元のシェルで設定されたままになるいくつかの環境変数を設定するシェルスクリプトを記述しようとしています。

setenv FOO foo

csh / tcshで、または

export FOO=foo

sh / bashではスクリプトの実行中にのみ設定します。

私はすでにそれを知っている

source myscript

新しいシェルを起動するのではなく、スクリプトのコマンドを実行し、その結果「呼び出し元」の環境を設定することができます。

しかしここにこすりがあります:

このスクリプトをbashまたはcshのどちらかから呼び出すことができます。 言い換えれば、いずれかのシェルのユーザーが自分のスクリプトを実行し、シェルの環境を変更できるようにしたいと思います。 だから私はcshを実行しているユーザーがbashスクリプトをソースできないし、bashを実行しているユーザーはcshスクリプトをソースできないので、 'source'は私のためには機能しません。

スクリプトに2つのバージョンを作成して管理する必要がない合理的な解決法はありますか?


$ SHELL / $ TERMが何に設定されているかに応じて、文章以外の条件文もありません。 Perlを使って何が問題になっていますか? かなり普及しています(私はそれを持っていない単一のUNIXの変種を考えることはできません)。


OS Xのbashでは、次のことができます:
変数を設定解除するためのbashスクリプト・ファイルを作成します。

#!/bin/bash
unset http_proxy

ファイルを実行可能にする

sudo chmod 744 unsetvar

エイリアスを作成する

alias unsetvar='source /your/path/to/the/script/unsetvar'

パスにスクリプトファイルが追加されているフォルダを使用している間は、使用する準備ができているはずです。


「ドットスペーススクリプト」呼び出し構文を使用します。 たとえば、スクリプトへのフルパスを使用してスクリプトを実行する方法は次のとおりです。

. /path/to/set_env_vars.sh

スクリプトと同じディレクトリにいる場合は、次のようにします。

. set_env_vars.sh

これらは、別のものをロードするのではなく、現在のシェルの下でスクリプトを実行します(これは./set_env_vars.sh実行した場合に起こります)。 同じシェルで実行されるため、設定した環境変数は終了時に使用可能になります。

これはsource set_env_vars.shを呼び出すのと同じことですが、入力するのが短く、 sourceがない場所ではうまくいくかもしれません。


あなたのbashスクリプトの上に-lフラグを追加します。

#!/usr/bin/env bash -l

...

export NAME1="VALUE1"
export NAME2="VALUE2"

NAME1NAME2の値は現在の環境にエクスポートされますが、これらの変更は永続的ではありません。 それらを永続的にしたい場合は、 .bashrcファイルやその他のinitファイルに追加する必要があります。

マニュアルページから:

-l Make bash act as if it had been invoked as a login shell (see INVOCATION below).

これはうまくいく - 私が使うものではないが、それはうまくいく。 環境変数TEREDO_WORMSを設定するスクリプトteredoを作成しましょう:

#!/bin/ksh
export TEREDO_WORMS=ukelele
exec $SHELL -i

これはKornシェルによって解釈され、環境変数をエクスポートしてから、新しい対話シェルに置き換えられます。

このスクリプトを実行する前に、環境内にシェルがシェルとして設定されており、環境変数TEREDO_WORMSが設定されていません。

% env | grep SHELL
SHELL=/bin/csh
% env | grep TEREDO
%

スクリプトを実行すると、新しいシェル、別の対話型Cシェルになりますが、環境変数が設定されます。

% teredo
% env | grep TEREDO
TEREDO_WORMS=ukelele
%

このシェルを終了すると、元のシェルが引き継ぎます:

% exit
% env | grep TEREDO
%

環境変数は元のシェルの環境では設定されていません。 exec teredoを使用してコマンドを実行すると、元の対話型シェルは環境を設定するKornシェルに置き換えられ、新しい対話型Cシェルに置き換えられます。

% exec teredo
% env | grep TEREDO
TEREDO_WORMS=ukelele
%

exit (またはControl-D )を入力すると、シェルが終了し、おそらくそのウィンドウからログアウトしたり、実験の開始元のシェルの以前のレベルに戻ることができます。

同じメカニズムがBashシェルまたはKornシェルで機能します。 終了コマンドの後のプロンプトが面白い場所に表示されることがあります。

コメントの議論に注目してください。 これは私がお勧めする解決策ではありませんが、すべてのシェル(対話シェルを作るために-iオプションを受け入れる)で動作する環境を設定するための単一スクリプトの目的を達成しています。 他の引数を中継するオプションの後ろに"[email protected]"追加すると、シェルを一般的な '環境設定とコマンド実行'ツールとして使用できるようになります。 他の引数がある場合は、 -iを省略して、次のようにすることもできます。

#!/bin/ksh
export TEREDO_WORMS=ukelele
exec $SHELL "${@-'-i'}"

"${@-'-i'}"ビットは、引数リストに少なくとも1つの引数が含まれている場合は、元の引数リストを使用します。 それ以外の場合は、存在しない引数に-iを代入し-i


それは私が未解決と呼ぶものではありませんが、これはシェルからスクリプトを呼び出す必要がある場合にも機能します。 これは良い解決策ではありませんが、単一の静的な環境変数の場合、十分に機能します。

1.)0(成功)または1(成功していない)のいずれかを終了する条件付きのスクリプトを作成します。

if [[ $foo == "True" ]]; then
    exit 0
else
    exit 1

2.)終了コードに依存するエイリアスを作成します。

alias='myscript.sh && export MyVariable'

エイリアスを呼び出すと、スクリプトを呼び出します。このエイリアスは条件を評価します。この条件は、親シェルで環境変数を設定するために '&&'でゼロを終了する必要があります。

これは浮遊していますが、ピンチで役立つことがあります。


エイリアスはいつでも使用できます

alias your_env='source ~/scripts/your_env.sh'

モジュールを使用する必要がありますhttp://modules.sourceforge.net/参照してhttp://modules.sourceforge.net/

編集:モジュールパッケージは2012年以降に更新されていませんが、基本的にはまだ正常に動作します。 すべての新機能、鐘、笛がこの日、lmodで発生します(私はそれがもっと好きです): https://www.tacc.utexas.edu/research-development/tacc-projects/lmod ://www.tacc.utexas.edu/research-development/tacc-projects/lmod


呼び出し元のシェルは異なるプロセスコンテキストにあるため、変更することはできません。 子プロセスがあなたのシェルの変数を継承するとき、それらは自身を継承します。

あなたができることの1つは、tcshまたはshがどのように呼び出されたかに基づいて正しいコマンドを発行するスクリプトを書くことです。 スクリプトが "setit"の場合は、次のようにします。

ln -s setit setit-sh

そして

ln -s setit setit-csh

今すぐ直接またはエイリアスのいずれかで、shからこれを行います

eval `setit-sh`

これはcshからのものです

eval `setit-csh`

setitは$ 0を使用して出力スタイルを決定します。

これは、人々がTERM環境変数を設定するためにどのように使用するかを思い起こさせます。

ここでの利点は、setitはちょうど好きなシェルの中に書かれていることです。

#!/bin/bash
arg0=$0
arg0=${arg0##*/}
for nv in \
   NAME1=VALUE1 \
   NAME2=VALUE2
do
   if [ x$arg0 = xsetit-sh ]; then
      echo 'export '$nv' ;'
   elif [ x$arg0 = xsetit-csh ]; then
      echo 'setenv '${nv%%=*}' '${nv##*=}' ;'
   fi
done

上に与えられたシンボリックリンクとバッククォートされた式の評価で、これは望ましい結果をもたらします。

csh、tcsh、または同様のシェルの呼び出しを簡単にするには:

alias dosetit 'eval `setit-csh`'

またはsh、bashなどの場合:

alias dosetit='eval `setit-sh`'

これについての1つの良いことは、あなたは1つの場所でリストを維持する必要があるということです。 理論的には、ファイルにリストを張り、 cat nvpairfilenameを "in"と "do"の間に置くこともできます。

これは、ログインシェル端末の設定をどのようにして使用したかです:スクリプトはログインシェルで実行されるステートメントを出力します。 エイリアスは一般に "tset vt100"のように呼び出しを簡単にするために使用されます。 別の答えで述べたように、INNのUseNetニュースサーバーにも同様の機能があります。


子プロセスに( "env"を呼び出すことによって)環境変数を出力し、親プロセス内の印刷された環境変数をループし、それらの変数に対して "export"を呼び出すように指示することができます。

次のコードは、findの出力のキャプチャに基づいています。 -print0をbash配列に追加する

親シェルがbashの場合は、

while IFS= read -r -d $'\0' line; do
    export "$line"
done < <(bash -s <<< 'export VARNAME=something; env -0')
echo $VARNAME

親シェルがダッシュの場合、 readは-dフラグを提供せず、コードはより複雑になります

TMPDIR=$(mktemp -d)
mkfifo $TMPDIR/fifo
(bash -s << "EOF"
    export VARNAME=something
    while IFS= read -r -d $'\0' line; do
        echo $(printf '%q' "$line")
    done < <(env -0)
EOF
) > $TMPDIR/fifo &
while read -r line; do export "$(eval echo $line)"; done < $TMPDIR/fifo
rm -r $TMPDIR
echo $VARNAME

異なるbash_profileで別の1つのBashを呼び出すことができます。 また、マルチbashprofile環境で使用するための特別なbash_profileを作成することもできます。

bashprofileの中の関数を使うことができ、その関数はグローバルに利用可能であることを覚えておいてください。 たとえば、 "function user {export USER_NAME $ 1}"は実行時に変数を設定できます。たとえば、user olegchir && env | grep olegchir


私が言及していない別の回避策は、変数の値をファイルに書き込むことです。

私は非常に似たような問題に遭遇しました。ここでは、すべてのテストの代わりに、最後に設定されたテストを実行できるようにしたいと考えていました。 私の最初の計画は、env変数TESTCASEを設定するための1つのコマンドを書き、その後これを使ってテストを実行する別のコマンドを作成することでした。 言うまでもなく、あなたと同じ問題がありました。

しかし、私はこの単純なハックを思いついた:

最初のコマンド( testset ):

#!/bin/bash

if [ $# -eq 1 ]
then
  echo $1 > ~/.TESTCASE
  echo "TESTCASE has been set to: $1"
else
  echo "Come again?"
fi

2番目のコマンド( testrun ):

#!/bin/bash

TESTCASE=$(cat ~/.TESTCASE)
drush test-run $TESTCASE

私は、パイプ、評価と信号を使ってソリューションを作りました。

parent() {
    if [ -z "$G_EVAL_FD" ]; then
            die 1 "Rode primeiro parent_setup no processo pai"
    fi
    if [ $(ppid) = "$$" ]; then
            "[email protected]"
    else
            kill -SIGUSR1 $$
            echo "[email protected]">&$G_EVAL_FD
    fi
}
parent_setup() {
    G_EVAL_FD=99
    tempfile=$(mktemp -u)
    mkfifo "$tempfile"
    eval "exec $G_EVAL_FD<>'$tempfile'"
    rm -f "$tempfile"
    trap "read CMD <&$G_EVAL_FD; eval \"\$CMD\"" USR1
}
parent_setup #on parent shell context
( A=1 ); echo $A # prints nothing
( parent A=1 ); echo $A # prints 1

どのコマンドでも動作します。


私はこれを何年も前にやった。 私が正しく覚えていれば、パラメータを使って.bashrcと.cshrcにエイリアスを追加し、それぞれの環境を共通の形式にエイリアスしました。

次に、2つのシェルのいずれかでソースとなるスクリプトには、最後の形式のコマンドがあります。これは、各シェルに適切な別名が付けられています。

私が具体的なエイリアスを見つけたら、投稿します。





tcsh