我有一个PHP脚本和一个bash脚本。他们在同一个目录中。我正在从命令行运行php脚本,它将数组传递给bash脚本。我正在尝试执行以下操作:
- 将PHP数组传递给BASH脚本
- 从STDIN获取用户输入
- 将用户输入传递回PHP脚本以进行进一步处理
这是我的PHP脚本:
<?php
$a=array("red","green","blue","yellow");
$string = '(' . implode(' ', $a) . ')'; // (red green blue yellow)
$user_response = shell_exec('./response.sh $string');
// do something with $user_response
?>
BASH脚本应该从STDIN读取数组并提示用户选择一个选项:
#!/bin/bash
options=$($1); # (red green blue yellow) but this isn't working
i=0;
echo "select an option";
for each in "${options[@]}"
do
echo "[$i] $each"
i=$((i+1))
done
echo;
read input;
echo "You picked option ${options[$input]}";
# here's where I want to pass or export the input back to the
# php script for further processing
当我运行php脚本时,它不显示数组选项。
您可以将shell脚本设置为:
#!/bin/bash
options=("$@")
i=0
echo "select an option"
for str in "${options[@]}"; do
echo "[$i] $str"
((i++))
done
echo
read -p 'Enter an option: ' input
echo "You picked option ${options[$input]}"
然后让你的PHP代码如下:
<?php
$a=array("red","green","blue","yellow");
$string = implode(' ', $a);
$user_response = shell_exec("./response.sh $string");
echo "$user_response\n";
?>
但是请记住,从PHP运行时输出将是这样的:
php -f test.php
Enter an option: 2
select an option
[0] red
[1] green
[2] blue
[3] yellow
You picked option blue
即用户输入将在显示脚本输出之前到来。
我说最简单的不是尝试模拟内部bash数组,而是使用'normal'逻辑/后处理。例如;如果你只是通过 implode(' ', $a)
到bash脚本(你也应该通过它 escapeshellarg()
):
$a=array("red","green","blue","yellow");
$args = implode(' ', array_map('escapeshellarg', $a));
$user_response = shell_exec('./response.sh '. $args);
然后你可以使用bash遍历参数
for each in $*; do
echo $each
done
您的解决方案的问题是Shell脚本的输出实际上是在PHP中 $response
变量:
SHELL脚本:
#!/bin/bash
echo "Before prompt"
read -p 'Enter a value: ' input
echo "You entered $input"
PHP脚本:
<?php
$shell = shell_exec("./t.sh");
echo "SHELL RESPONSE\n$shell\n";
的结果 php t.php
:
$ php t.php
Enter a value: foo
SHELL RESPONSE
Before prompt
You entered foo
你抓住了整个 STDOUT
Shell脚本。
如果您希望简单地将值传递给shell脚本,则选项为 $option_string = implode(' ', $array_of_values);
将为脚本单独设置选项。如果你想要一些更高级的东西(设置标志,分配东西等)试试这个(https://ideone.com/oetqaY):
function build_shell_args(Array $options = array(), $equals="=") {
static $ok_chars = '/^[-0-9a-z_:\/\.]+$/i';
$args = array();
foreach ($options as $key => $val) if (!is_null($val) && $val !== FALSE) {
$arg = '';
$key_len = 0;
if(is_string($key) && ($key_len = strlen($key)) > 0) {
if(!preg_match($ok_chars, $key))
$key = escapeshellarg($key);
$arg .= '-'.(($key_len > 1) ? '-' : '').$key;
}
if($val !== TRUE) {
if((string) $val !== (string) (int) $val) {
$val = print_r($val, TRUE);
if(!preg_match($ok_chars, $val))
$val = escapeshellarg($val);
}
if($key_len != 0)
$arg .= $equals;
$arg .= $val;
}
if(!empty($arg))
$args[] = $arg;
}
return implode(' ', $args);
}
这将是您传递给命令行的最全面的解决方案。
如果您正在寻找一种方法来提示用户(通常),我会考虑留在PHP中。最基本的方法是:
print_r("$question : ");
$fp = fopen('php://stdin', 'r');
$response = fgets($fp, 1024);
或者,为了支持验证问题,多行,并且仅在CLI上调用:
function prompt($message = NULL, $validator = NULL, $terminator = NULL, $include_terminating_line = FALSE) {
if(PHP_SAPI != 'cli') {
throw new \Exception('Can not Prompt. Not Interactive.');
}
$return = '';
// Defaults to 0 or more of any character.
$validator = !is_null($validator) ? $validator : '/^.*$/';
// Defaults to a lonely new-line character.
$terminator = !is_null($terminator) ? $terminator : "/^\\n$/";
if(@preg_match($validator, NULL) === FALSE) {
throw new Exception("Prompt Validator Regex INVALID. - '$validator'");
}
if(@preg_match($terminator, NULL) === FALSE) {
throw new Exception("Prompt Terminator Regex INVALID. - '$terminator'");
}
$fp = fopen('php://stdin', 'r');
$message = print_r($message,true);
while (TRUE) {
print_r("$message : ");
while (TRUE) {
$line = fgets($fp, 1024); // read the special file to get the user input from keyboard
$terminate = preg_match($terminator, $line);
$valid = preg_match($validator, $line);
if (!empty($valid) && (empty($terminate) || $include_terminating_line)) {
$return .= $line;
}
if (!empty($terminate)) {
break 2;
}
if(empty($valid)) {
print_r("\nInput Invalid!\n");
break;
}
}
}
return $return;
}
因为括号在子shell中运行它们中的内容,这不是我想要的......
我会改变这个......
$string = '(' . implode(' ', $a) . ')';
对此......
$string = '"' . implode (' ', $a) . '"';
另外,在这里使用双引号......
$user_response = shell_exec ("./response.sh $string");
或者爆发......
$user_response = shell_exec ('./response.sh ' . $string);
因此,我也会将BASH更改为简单地接受单个参数,字符串,并将该参数拆分为数组以获取我们的选项。
像这样......
#!/bin/bash
IFS=' ';
read -ra options <<< "$1";
i=0;
echo "select an option";
for each in "${options[@]}"; do
echo "[$i] $each";
i=$((i+1));
done;
unset i;
echo;
read input;
echo "You picked option " ${options[$input]};