在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
命令又将文件句柄指定为{{1} }}。这相当于这个shell命令:
grep -E foo /root/text | sed -E 's/bar/baz/g' > /tmp/whatever
我想在PHP中复制此行为,但我找不到相同的本机功能。我一直在做的是将等效的shell命令构建为一个长字符串并将其传递给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 :(得分:1)
您可以使用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
];