我有一个PHP脚本和bash脚本。 他们在同一个目录中。 我正在从命令行运行PHP脚本,该脚本将数组传递给bash脚本。 我正在尝试执行以下操作:
这是我的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读取数组并提示用户select一个选项:
#!/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数组,但使用“正常”逻辑/后处理。 例如; 如果你只是传递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
变量中:
外壳脚本:
#!/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
您捕获了Shell脚本的整个STDOUT
。
如果你只是简单的将值传给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; }
因为圆括号里面有什么东西在一个子壳里面,这不是我想要的东西…
我会改变这个…
$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]};