27

別の Perl スクリプトを実行する必要がある Perl スクリプトがあります。この 2 番目のスクリプトはコマンド ラインで直接実行できますが、最初のプログラム内から実行する必要があります。スタンドアロンで実行するときに通常渡されるいくつかのパラメーターを渡す必要があります (最初のスクリプトは定期的に実行され、2 番目のスクリプトは特定のシステム条件下で実行されます)。

予備の Google 検索では、バックティックまたは system() 呼び出しを使用することをお勧めします。それを実行する他の方法はありますか?(私たちが話しているのはPerlなので、私はそうだと思います:P)呼び出されたプログラムから出力をキャプチャする必要がある場合、どの方法が優先されますか(そして、可能であれば、2番目のプログラムが直接呼び出された)?

(編集:ああ、SOはいくつかの関連する質問を提案しています。これ近いですが、私が求めているものとまったく同じではありません。2番目のプログラムは、実行に1時間以上かかる可能性があります(多くのI / O)ので、 1 回限りの呼び出しがこれに適しているかどうかはわかりません。)

4

9 に答える 9

35

あなたはそれを行うことができます。

{
    local @ARGV = qw<param1 param2 param3>;
    do '/home/buddy/myscript.pl';
}

perl の別のコピーをロードするオーバーヘッドを防ぎます。

于 2008-12-15T01:59:10.417 に答える
34

現在の perl インタープリターの場所は、特殊変数 で見つけることができます$^X。これは、perl がパスにない場合、または複数のバージョンの perl が利用可能であるが、全体的に同じバージョンを使用していることを確認する場合に重要です。

他の Perl プログラムを含む外部コマンドを実行する場合、それらが実際に実行されたかどうかを判断するのは非常に困難です。検査$?は永続的な精神的な傷を残す可能性があるため、私はIPC::System::Simple (CPAN から入手可能)を使用することを好みます。

use strict;
use warnings;
use IPC::System::Simple qw(system capture);

# Run a command, wait until it finishes, and make sure it works.
# Output from this program goes directly to STDOUT, and it can take input
# from your STDIN if required.
system($^X, "yourscript.pl", @ARGS);

# Run a command, wait until it finishes, and make sure it works.
# The output of this command is captured into $results.
my $results = capture($^X, "yourscript.pl", @ARGS);

上記の両方の例で、外部プログラムに渡したい引数はすべて に入り@ARGSます。上記の両方の例では、シェルも回避されています。これにより、速度がわずかに向上し、シェルのメタ文字が関与する不要な相互作用が回避されます。上記のコードでは、2 番目のプログラムが成功を示すためにゼロの終了値を返すことも想定しています。そうでない場合は、許容される終了値の追加の最初の引数を指定できます。

 # Both of these commands allow an exit value of 0, 1 or 2 to be considered
 # a successful execution of the command.

 system( [0,1,2], $^X, "yourscript.pl", @ARGS );
 # OR
 capture( [0,1,2, $^X, "yourscript.pl", @ARGS );

長時間実行されるプロセスがあり、生成にそのデータを処理したい場合は、おそらくパイプで開くか、CPAN のより重い IPC モジュールの 1 つが必要になるでしょう。

そうは言っても、Perl から別の Perl プログラムを呼び出す必要があるときはいつでも、モジュールを使用する方が良い選択かどうかを検討したいと思うかもしれません。別のプログラムを起動すると、起動コストと、プロセス間でデータを移動するための I/O コストの両方の点で、かなりのオーバーヘッドが発生します。また、エラー処理の難しさも大幅に増加します。外部プログラムをモジュールに変換できれば、全体の設計が簡素化されることがあります。

ではごきげんよう、

ポール

于 2008-12-13T13:21:28.873 に答える
13

これを行う方法はいくつか考えられます。最初の 2 つは既に述べたので、詳細には触れません。

  1. バッククォート: $retVal = `perl somePerlScript.pl`;
  2. system()電話
  3. eval

これevalは、他のファイルを文字列 (または文字列のリスト) に丸呑みし、文字列を「評価」することで実現できます。サンプルを次に示します。

#!/usr/bin/perl
open PERLFILE, "<somePerlScript.pl";
undef $/;   # this allows me to slurp the file, ignoring newlines
my $program = <PERLFILE>;
eval $program;

4 . 行う:

「somePerlScript.pl」を実行します

于 2008-12-13T05:40:17.353 に答える
12

質問に対する適切な回答は既に得られていますが、別の見方をする可能性は常にあります。実行するスクリプトを最初のスクリプトからリファクタリングすることを検討する必要があるかもしれません。機能をモジュールに変換します。最初のスクリプトと 2 番目のスクリプトのモジュールを使用します。

于 2008-12-13T12:41:40.060 に答える
6

コマンドの出力を取得する必要がある場合は、バッククォートを使用してください。

systemコマンドの出力をキャプチャする必要がない場合に使用します。

TMTOWTDI: 他の方法もありますが、最も簡単で可能性が高いのはこの 2 つです。

于 2008-12-13T04:56:29.127 に答える
6

外部スクリプトを非同期的に呼び出す必要がある場合 (終了するのを待たずに起動するだけの場合)、次のようにします。

# On Unix systems, either of these will execute and just carry-on
# You can't collect output that way
`myscript.pl &`;
system ('myscript.pl &');    

# On Windows systems the equivalent would be
`start myscript.pl`;
system ('start myscript.pl');

# If you just want to execute another script and terminate the current one
exec ('myscript.pl');
于 2008-12-13T05:23:07.247 に答える
5

プロセス間通信のいくつかのオプションについては、 perlipcのドキュメントを参照してください。

最初のスクリプトが 2 番目のスクリプトの環境をセットアップするだけの場合は、exec.

于 2008-12-13T08:06:47.963 に答える
1
#!/usr/bin/perl
use strict;

open(OUTPUT, "date|") or die "Failed to create process: $!\n";

while (<OUTPUT>)
{
  print;
}

close(OUTPUT);

print "Process exited with value " . ($? >> 8) . "\n";

これにより、プロセスが開始dateされ、コマンドの出力が一度に 1 行ずつ処理できる OUTPUT ファイルハンドルにパイプされます。コマンドが終了したら、出力ファイルハンドルを閉じて、プロセスの戻り値を取得できます。必要なものに置き換えdateてください。

于 2008-12-13T04:57:50.230 に答える
0

非サブルーチンを外部ファイルにオフロードして編集を容易にするために、このようなことをしたかったのです。実際にこれをサブルーチンにしました。この方法の利点は、外部ファイル内の「my」変数がメインの名前空間で宣言されることです。「do」を使用すると、メインの名前空間に移行しないようです。以下のプレゼンテーションにはエラー処理が含まれていないことに注意してください

sub getcode($) {
  my @list;
  my $filename = shift;
  open (INFILE, "< $filename");
  @list = <INFILE>;
  close (INFILE);
  return \@list;
}

# and to use it:

my $codelist = [];
$codelist = getcode('sourcefile.pl');
eval join ("", @$codelist);
于 2013-02-05T18:42:46.123 に答える