Перенаправление при использовании PHP exec (или аналогичной функции)

В Python мы можем сделать что-то вроде этого:

pattern      = "foo"searchfile   = "/root/text"search       = "bar"replace      = "baz"
tempfile     = tempfile.mkstemp()[1]
grepcmd      = ["/bin/grep", "-E", pattern, searchfile]
sedcmd       = ["/bin/sed", "-E", "s/{0}/{1}/g".format(search, replace)]
with open(tempfile, "w") as temphandle:
grep = subprocess.Popen(grepcmd, stdout=subprocess.PIPE)
sed = subprocess.Popen(sedcmd, stdin=grep.stdout, stdout=temphandle)
grep.stdout.close()
sed.communicate()

Вы можете видеть, что stdout от grep команда передается как stdin к sed команда, которая в свою очередь указывает дескриптор файла в качестве его stdout, Это эквивалентно этой команде оболочки:

grep -E foo /root/text | sed -E 's/bar/baz/g' > /tmp/whatever

Я хотел бы повторить это поведение в PHP, но я не нахожу эквивалентную нативную функциональность. Я собирался создать эквивалентную команду оболочки в виде длинной строки и передать ее shell_exec() но это грязно, особенно при правильном использовании escapeshellarg() (Примечание: экранирование не требуется в приведенном выше коде Python.)

$pattern    = "foo";
$searchfile = "/root/text";
$search     = "bar";
$replace    = "baz";

$tempfile   = tempnam(sys_get_temp_dir(), 'asdf');
$grepcmd    = "/bin/grep -E " . escapeshellarg($pattern) . " " . escapeshellarg($searchfile);
$sedcmd     = "/bin/sed -E " . escapeshellarg("s/$search/$replace/g");
exec("$grepcmd | $sedcmd > $tempfile);

Я также могу запускать каждую команду отдельно, записывая вывод в переменную и передавая ее следующей команде, но это имеет очевидные недостатки.

Есть ли какой-нибудь родной способ сделать что-то подобное в PHP или мой текущий метод настолько хорош, насколько это возможно?

0

Решение

Ты можешь использовать proc_open и связанные функции для этого.

$descriptorSpec = [
0 => ['pipe', 'r'], // stdin
1 => ['pipe', 'w'], // stdout
2 => ['pipe', 'w'], // stderr
];

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

if (!is_resource($process)) {
throw new Exception('Unable to start shell process.');
}

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

$error = stream_get_contents($pipes[2]);
fclose($pipes[2]);

$status = proc_close($process);
if ($status !== 0) {
throw new Exception('Command ' . $cmd . ' returned code ' . $status . '. Output: ' . $error);
}

Если вы хотите использовать выходные данные первой команды, передайте один из результирующих каналов дескриптору stdin другой команды:

$descriptorSpec = [
0 => $pipes[1], // stdin
1 => ['pipe', 'w'], // stdout
2 => ['pipe', 'w'], // stderr
];

Если вы хотите перенаправить один из дескрипторов в файл, просто укажите ресурс, из которого вы получаете fopen():

$res = fopen('file.log', 'w+');
$descriptorSpec = [
0 => ['pipe', 'r'], // stdin
1 => $res, // stdout
2 => $res, // stderr
];
1

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]