【问题标题】:How to pass a PHP array to a BASH script?如何将 PHP 数组传递给 BASH 脚本?
【发布时间】:2015-12-19 16:30:09
【问题描述】:

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

  1. 将 PHP 数组传递给 BASH 脚本
  2. 从 STDIN 获取用户输入
  3. 将用户输入传回 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 脚本时,它不显示数组选项。

【问题讨论】:

  • 您不想将$string 作为其实际值传递吗?它目前作为字符串 $string 值传递。在 shell_exec("./response.sh $string"); 中使用双引号,以便 PHP 可以解析它。至于 Bash 我不知道,所以我不会把它作为答案。
  • 使用双引号时出现以下错误:sh: 1: Syntax error: word unexpected (expecting ")")
  • 我知道您已经选择了一个答案,但我想知道您正在寻找的是否只是选择选项的能力,如果您可能对 PHP 脚本提示输入更感兴趣.
  • 这正是我正在寻找的。我最初想在 BASH b/c 中进行提示,我知道我想如何格式化它并使它看起来不错,但后来我意识到在 PHP 脚本中完成这一切可能会更容易。我会试试你的解决方案。

标签: php arrays linux bash shell


【解决方案1】:

我想说最简单的方法是不要尝试模拟内部 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

【讨论】:

  • bash 脚本的外观如何?当response.sh被调用时,假设在终端上显示选项并提示用户输入,然后将输入传回php脚本。
  • 我不会做你的作业;如果我的回答对您的具体问题有所帮助;请接受这个答案并自己完成脚本。
【解决方案2】:

您的解决方案的问题是 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

您捕获了 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;
}

【讨论】:

    【解决方案3】:

    你的 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 脚本的输出显示之前,如果我必须在 php 脚本中完成这一切可能会更容易。再次感谢。
    • 发生这种情况是因为 PHP 变量 $user_response 包含 STDOUT 的内容,而不是用户响应的实际值。
    【解决方案4】:

    由于括号在子外壳中运行它们中的内容,这不是我认为你想要的......

    我会改变这个...

    $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]};
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-06-18
      • 1970-01-01
      • 2016-08-16
      • 2012-07-06
      • 2018-02-23
      • 2012-01-23
      • 1970-01-01
      • 2020-11-02
      相关资源
      最近更新 更多