1

Perl からシステム コマンドの動的リストを実行しています。これらのコマンドは、環境変数に (一時的/処理中の) 変更を加えるスクリプトである場合があります。たとえば、次の単純なスクリプトを考えてみましょう (現在は Windows 用に作成されています)。

Script-A-pl:

use strict;
use warnings;
use feature ':5.16';

$ENV{NEW_VAR} = 'this is new var';
say "Script-A.pl can read the new var: ", `echo %NEW_VAR%`;

Output: Script-A.pl can read the new var: this is new var

ここで、 から を呼び出し、後でParent.plを呼び出す必要があると想像してください。これは、環境変数 に依存します。したがって、これが実行される方法です。Script-A.plScript-B.plNEW_VAR

Parent.pl:

use strict;
use warnings;
use feature ':5.16';

my @commands = ('perl Script-A.pl', 'perl Script-B.pl');

for my $i (@commands) {
    system($i);
}

Script-A.plこれは、 によって行われた環境変数の変更が では見えないという事実を除いては機能しScript-B.plます。

IPC::Open3 でシェルを開き、そこでコマンドのリストを 1 つずつ実行しても、スクリプトを呼び出すさまざまな方法を試しましたが、それもうまくいきませんでした。

Parent.pl から、これらの変更を後続のシステム コールに表示する方法はありますか?

コメントありがとうございます!

フランシスコ

4

1 に答える 1

0

%ENV永続的なシステム環境ではなく、Perl スクリプトのシステム環境を表します。それに加えられた変更は、スクリプトのプロセス (およびすべての子プロセス) に対してのみ有効です。を使用してすべてのスクリプトを呼び出しているためsystem、それぞれのスクリプトの変更は、そのスクリプトの実行中のみ持続します。

これを克服するには、すべての Perl スクリプトを異なるプロセスではなく同じプロセスで実行してみてください。

my @commands = ('Script-A.pl', 'Script-B.pl', 'echo "some other command"');

for my $cmd (@commands) {
    if ($cmd =~ /\.pl$/)
    {
        do $cmd;
    }
    else
    {
        system($cmd);
    }
}

do <FILE>別の Perl スクリプトのコードをインクルードして実行する簡単な方法です。すべてのスクリプトが同じプロセスにあることが保証されるため、への変更%ENVはメイン スクリプト全体で保持されます。

do <FILE>myは、ファイルごとに個別のレキシカル変数スペースを提供するため、ファイル間で衝突して宣言された変数について心配する必要はありません。ただし、それらは同じグローバル変数空間を共有するため、適切に動作しないスクリプト (たとえば、$/を使用せずに特別な変数を設定するなどlocal) がこの方法で実行されると、他のスクリプトの動作を台無しにする可能性があります。この方法を使用する場合は、すべてが正常に機能することを確認する必要があります。

もう 1 つの問題は、上記のコードは Perl スクリプトに引数がないことを前提としていることです。彼らに引数がある場合、それは機能しません。ただし、これを回避できます。

my @commands = ('Script-A.pl arg1 arg2');

for my $cmd (@commands) {
    if ($cmd =~ /\.pl\b\s*(.*)$/)
    {
        local @ARGV = split ' ', $1;
        do $cmd;
    }
    else
    {
        system($cmd);
    }
}

各スクリプトに のローカル コピーを与える@ARGVと、引数付きで呼び出されているように見えます。このコードは、単純な引数 (スペースなし、シェル マジックなし) に対してのみ機能します。

于 2013-04-13T07:32:28.237 に答える