Как передать массив PHP в BASH script?

У меня есть php script и bash script. Они находятся в одном каталоге. Я запускаю PHP скрипт из командной строки, которая передаст массив в bash script. Я пытаюсь сделать следующее:

  • передать массив PHP в bash script
  • получить пользовательский ввод от STDIN
  • передать пользовательский ввод обратно в PHP script для дальнейшей обработки

Здесь мой php script:

<?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 script считывает массив из 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 where I want to pass or export the input back to the 
# PHP скрипт for further processing

Когда я запускаю php script, он не отображает параметры массива.

Ответ 1

У вас может быть ваша оболочка script следующим образом:

#!/bin/bash
options=("[email protected]")

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

то есть. пользовательский ввод появится до вывода из script.

Ответ 2

Я бы сказал, что проще всего не пытаться эмулировать внутренний массив bash, а использовать "нормальную" логику/пост-обработку. Например; если вы просто передаете implode(' ', $a) в bash script (вы также должны передать его через 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

Ответ 3

Проблема с вашим решением заключается в том, что вывод оболочки Script на самом деле находится в переменной PHP $response:

SHELL script:

#!/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 оболочки Script.

Если вы хотите просто передать значения в оболочку script, опция $option_string = implode(' ', $array_of_values); будет работать для размещения параметров отдельно для Script. Если вы хотите что-то более продвинутое (установить флаги, назначить вещи и т.д.), Попробуйте это (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;
}

Ответ 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]};