
module
機能環境モジュール1パッケージはさまざまな環境変数を変更して作業を行います。現在のシェルプロセス
残念ながら、この関数は成功したかどうかにかかわらず0 2を返すので、クライアントスクリプトは失敗に適切に対応するのが困難です。
すべてのパラメータを直接渡し、失敗時にゼロ以外の値を正しく返すmymodule
関数ラッパーを実装したいと思います。module
module
module
mymodule
失敗を検出する唯一の方法は、module
出力module
関数がstderr(存在する場合)に何を書き込むかを確認することです。
問題は、ジョブをmymodule
キャンセルしないと、この出力を得るための合理的な方法を考えることができないことです。より具体的には、stderrを変数としてキャプチャするmodule
ために私が考えることができるほとんどすべての方法は子プロセスで実行する必要があります。module
module
上記の例外はstderrを一時ファイルにリダイレクトすることですが、関数が実行されるたびにファイルを生成するという考えはmodule
嫌いです。module
現在の環境でmymodule
呼び出すmodule
と同時に変数に標準エラーをキャプチャする方法はありますか?
zsh
私は両方の答えに興味がありますbash
。
1.交流しないでください。Lmod環境モジュールインターフェイスは非常に似たパッケージです。
2少なくとも私が使用しなければならなかった以前のバージョン3.2.9の場合はそうでした。私はこれを制御できません。
答え1
Bashとzshの両方共同プロセス(残念ながら少し異なります)基本的には次のように終わります。pipe
電話そして、呼び出しシェルで標準入力と標準出力を使用できるサブプロセスを作成します。デフォルトでは、シェルは現在のプロセスで実行されますが、x
すべて、実行されます。y
x | cmd | y
x
y
cmd
いいえパイプライン実行環境で。
module 2>&...
これにより、現在のシェルで何かを実行できます。セカンダリプロセスとして使用すると(たとえば)、すべてを直接再度繰り返し、後で出力を現在のシェルに読み直すことができます。...
module
cat
cmd
y <&...
別のオプションは、標準エラーを別のバックグラウンドプロセスにリダイレクトし、対応するwait
戻りコードを取得することです。以下では、これら2つの問題について議論します。
この偽の機能をテスト用に使用して、勝手にエラーをオン/オフmodule
できるようにします。 ifは私たちが見ることができるように現在のシェル環境を変更し、stderrに "err"を印刷します。必要に応じてこの行に注釈を付けます。
module() {
sleep 1
FOO=$(date)
echo err >&2
}
cat
Bash で共同プロセスを実行すると、module
の stderr をその中にリダイレクトし、cat
の stdout から読み込んで目的のタスクを実行できます。
coproc cat
module 2>&${COPROC[1]}
exec {COPROC[1]}>&-
if grep -q err <&${COPROC[0]}
then
echo got an error
else
echo no error
fi
zshでは、次のようにする必要があります。
module 2>&p
exec 4<&p
coproc :
if grep -q err <&4
代わりに、途中で。
どちらの場合も、module
現在のシェルでコマンドを実行し、そこからエラー出力を読み取ることができます。関数がif
正常に返される可能性があります。
cat
現在の実行環境で実行されている以外はすべていいえパイプラインなどの独立した環境を作成します。echo $FOO
最後にこれを確認すると、module
現在の環境で実行してから日付が更新されたことを確認できます。
または、バックグラウンドプロセスはすべての操作を実行できます。これはBashで動作します:
exec 2> >( if grep -q . ; then exit 7 ; else exit 0 ; fi )
PID=$!
module
exec 2>&-
wait $PID
echo $?
上記の内容は、トップレベルの子プロセスの内容を出力するか、または7
戻りコードを使用して必要に応じて実行するように調整できます。プロセス置換が設定されていない0
ため、zshではそうではありません。この問題は解決可能でなければなりませんが、試みを中止しました。$!
一時ファイルの代わりに固定fifoもここで動作します。
この場合、両側からFD 2を保存して復元することもできます。
答え2
「環境モジュール」がどのように機能するかはわかりませんが、説明によれば、環境変数を設定するシェル関数であり、標準エラー出力は別のプロセスで実行する必要なしにキャプチャ/一致する必要があると仮定しています。
良いか嫌いでも、信頼でき、確実な唯一の方法は、標準エラーを一時ファイルにリダイレクトすることです。名前付きパイプを使用することも同様に不便で(まだ一時ファイルを作成する必要があります!)、よりトリッキーです。コプロセスの使用は重くて面倒で持ち運びが難しい。
bash
(そして唯一のbash
)あなたは以下を利用することができます文書化されていない機能($!
プロセス交換でPIDに設定>(...)
)以下の状況を取り除いてください。
module 2> >(grep error)
wait $! && echo failed
この例では、それmodule
自体が混乱する可能性がある子孫を作成しないと仮定しています$!
。
答え3
Linuxでは、bashとzshを使用して次のことができます。
my_module() {
chmod u+w /dev/fd/3 # only needed in bash 5+
module 2> /dev/fd/3 3>&-
! grep -q err /dev/fd/3
} 3<<< ''
これは3<<< ''
最初に空行を含む文字列です。zsh
両方ともbash
ここに文字列を実装し、ここで削除された一時ファイルとして文書化します。 Linux(およびCygwinですが、通常は他のシステムではありません)でファイルを開くと、/dev/fd/3
fd 3が指すファイルが削除されても(他のシステムではfd 3をコピーします)、開かれるため、一時ファイルを処理する方法です。非常にきれいな方法があります。ファイルが削除されたため、クリーンアップについて心配する必要はなく、短時間でFSにのみ表示されます(ただし、バージョン5以降はそのファイルへの書き込みbash
権限が削除されたため、変更する必要があります)。これchmod
)。
module
ここで(別々のプロセスで並列ではなく)順次実行するには一時ファイルが必要ですgrep
。パイプ(Michaelのアプローチと似ていますが、@ mosvyのアプローチとは異なります)を使用してこれを行うと、パイプを埋めるのに十分なデータ出力があるとデッドロックが発生します。