17

Unix システム コマンドexec()を使用してタスクを追加するときに、出力をキャプチャしようとして、 と格闘してきました。at私の問題は、スクリプトから実行したときに出力が得られないことですが、ターミナルPHP から対話モードで実行すると、数行が出力されます。

実行したいコマンドは次のとおりです。

echo exec("echo 'php -f /path/to/file.php foo=1' | at now + 1 minutes", $result);

var_dump()を与えstring(0) ""print_r()吐き出すArray ()。を使用してみましたがshell_exec()、これは を出力しますが、Web ページのコンテキストで実行するとNULL次のように出力されます。hi

echo exec("echo 'hi'");

これも出力します:

echo exec("atq");

しかし、使用するとすぐatに何も出力されません。次の出力を取得するにはどうすればよいですか。

exec("echo 'php -f /path/to/file.php foo=1' | at now + 1 minutes", $result);

現在、Apache を介して PHP で「通常」として実行すると何も出力されないため、ターミナルと PHP の対話型コンソールでコマンドを実行すると、次のような期待される結果が得られます。

php > echo exec("echo 'php -f /path/to/file.php foo=1' | at now + 1 minutes", $result);
warning: commands will be executed using /bin/sh
job 1219 at Sun Jun 10 12:43:00 2012

safe_modeatがオフになっていて、実行時にパイプで挿入された echo ステートメントで出力が得られない理由がatqわかりexec()ません。この質問を検索して読みましたが、すべて役に立ちませんでした。

で2番目の引数を使用する場合、出力を文字列または配列exec()に返すにはどうすればよいですか?atexec()

4

3 に答える 3

29

機能する、1 行のソリューション

こんなに簡単だとは思いませんでした。2>&1必要なのは、実行するコマンドの最後に置くことによって stderr を stdout に再ルーティングすることだけです。からの出力atは標準出力に出力されるため、次のようにキャプチャされexec()ます。

echo exec("echo 'php -f /path/to/file.php foo=1' | at now + 1 minutes 2>&1", $result);

私の古い解決策:

私は1行または2行の解決策を維持しようとしていましたが、最終的に機能したのは、標準エラー出力にログを記録するproc_open() ため、読み取りません! atexec()これを指摘してくれた@Tourniquetに感謝しますが、彼は回答を削除しました。引用するには:

私が見る限り、stderrへの出力で、execによってキャプチャされません。あまり自信がありませんが、 http://php.net/manual/en/function.proc-open.phpの使用を検討してください。これにより、stderr を独自のパイプに向けることができます。

これは実際には正しい方法です。私の解決策(stderrのみが必要なため)は、これを行うことでした:

// Open process to run `at` command
$process = proc_open("echo 'php -f /path/to/file.php foo=1' | at now + 1 minutes", array(2 => array("pipe", "w")), $pipes);

// Get stuff from stderr, because `at` prints out there for some odd reason
if(is_resource($process)) {
    $output = stream_get_contents($pipes[2], 100);
    fclose($pipes[2]);

    $return_value = proc_close($process);
}

$outputatstderr に出力されたもの(これはエラーではないため、実際には stdout に送られるはずです)$return_valueが含ま0れ、成功した場合は含まれます。

于 2012-06-10T13:43:11.080 に答える
8

ここでは、 proc_openを使用したより複雑なソリューションを示します。私の場合、「2>&1」の回避策が機能しないため、この回答を書いています。

function runCommand($bin, $command = '', $force = true)
{
    $stream = null;
    $bin .= $force ? ' 2>&1' : '';

    $descriptorSpec = array
    (
        0 => array('pipe', 'r'),
        1 => array('pipe', 'w')
    );

    $process = proc_open($bin, $descriptorSpec, $pipes);

    if (is_resource($process))
    {
        fwrite($pipes[0], $command);
        fclose($pipes[0]);

        $stream = stream_get_contents($pipes[1]);
        fclose($pipes[1]);

        proc_close($process);
    }

    return $stream;
}

使用例:

// getting the mime type of a supplied file
echo runCommand('file -bi ' . escapeshellarg($file));

コマンドパラメータを使用した別の例:

// executing php code on the fly
echo runCommand('/usr/bin/php', '<?php echo "hello world!"; ?>');

forceパラメーターを使用した別の例(これは、実行プロセス中に出力を変更するコマンドに役立ちます)。

// converting an mp3 to a wav file
echo runCommand('lame --decode ' . escapeshellarg($source) . ' ' . escapeshellarg($dest), '', true);

これが役立つことを願っています:-)

于 2013-06-07T13:43:27.553 に答える
1

最小限の (非) 動作例を作成してみてください。すべてを分解し、一度に 1 つのことだけをテストします。

あなたのbashの1つのエラーは次のとおりです。

hpek@melda:~/temp$ echo 'php -f /path/to/file.php foo=1' | at now + 1 minutes
at: pluralization is wrong
job 22 at Sun Jun 10 14:48:00 2012
hpek@melda:~/temp$ 

minute代わりに og と書いてくださいminutes

私の出力atはメールで送られてきます!!

于 2012-06-10T12:50:06.927 に答える