如何将PHP数组传递给BASH脚本?

我有一个PHP脚本和bash脚本。 他们在同一个目录中。 我正在从命令行运行PHP脚本,该脚本将数组传递给bash脚本。 我正在尝试执行以下操作:

  1. 将一个PHP数组传递给BASH脚本
  2. 从STDIN获得用户input
  3. 将用户input传回给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读取数组并提示用户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]};