Вопрос или проблема
Я пытаюсь создать простой скрипт, который отправляет ping на сетевое соединение:
#!/usr/bin/env bash
# Обнаружение IP для Xdebug в Docker
# Авторские права (C) 2023 Димитриос Десиллас
#
# Эта программа является свободным программным обеспечением: вы можете распространять её и/или изменять
# в соответствии с условиями Стандартной общественной лицензии GNU, опубликованной
# Фондом свободного программного обеспечения, либо версии 3 лицензии, либо
# (по вашему выбору) любой последующей версии.
#
# Эта программа распространяется в надежде, что она будет полезна,
# но БЕЗ КАКИХ-ЛИБО ГАРАНТИЙ; даже без подразумеваемых гарантий
# ПРИГОДНОСТИ ДЛЯ КОНКРЕТНОЙ ЦЕЛИ или ТОВАРНОЙ ПРИГОДНОСТИ. Подробности смотрите в
# Стандартной общественной лицензии GNU.
#
# Вы должны были получить копию Стандартной общественной лицензии GNU
# вместе с этой программой. Если нет, см. <https://www.gnu.org/licenses/>.
SCRIPT=$(cat << 'EOM'
<?php
define('ERROR',"\033[0;31m");
define('OK',"\033[0;32m");
define('HIGILIGHT',"\033[0;96m");
define('HIGILIGHT2',"\033[1;33;4;44m");
define('HIGILIGHT_ERROR',"\033[0;95m");
define('NC',"\033[0m");
if(count($argv) < 2){
echo HIGILIGHT_ERROR." No IP and port provided".NC.PHP_EOL;
exit(-1);
}
$host = $argv[1];
$host_parts = explode(":",$host);
$host = $host_parts[0];
if(isset($host_parts[1])){
$port=$host_parts[1];
} elseif(isset($argv[2])){
$port = $argv[2];
} else {
echo HIGILIGHT_ERROR." No port provided".NC.PHP_EOL;
exit(-1);
}
$port = intval($port);
$timeout = 30;
echo PHP_EOL."##############".PHP_EOL.PHP_EOL."TESTING ".HIGILIGHT2.$host.':'.$port.NC.PHP_EOL;
//проверяем, установлено ли соединение через is_resource
$sk = @fsockopen($host, $port, $errnum, $errstr, $timeout);
if (!is_resource($sk)) {
echo ERROR."connection fail: ".HIGILIGHT_ERROR. $errnum . " " . $errstr.NC.PHP_EOL;
exit(1);
} else {
echo OK."Connected".NC.PHP_EOL;
exit(0);
}
EOM
)
echo "$SCRIPT" | php -d xdebug.mode=off $@
exit $?
Но как только я его выполняю:
bash check_connect 172.162.5.3:3306
Я получаю:
Could not open input file: 172.162.5.3:3306
Как я могу также использовать конвейер и аргументы командной строки в моем скрипте?
Вы можете запустить php -- arguments
например:
#!/bin/sh
S='<?php
printf("You entered %s\n",$argv[1]);
?>'
echo $S | php -- hello
вернет вывод
You entered hello
Ответ или решение
Запуск PHP-скриптов непосредственно внутри оболочки Bash с поддержкой передачи аргументов командной строки является полезным навыком для IT-специалистов, особенно когда необходимо быстро запускать сетевые проверки или выполнять другие автоматизированные задачи из скриптов. Для этого важно чётко понять, каким образом данные передаются между Bash и PHP, поскольку некоторые ошибки могут возникнуть из-за неправильной интерпретации или передачи входных данных.
Теоретическая основа
PHP достаточно гибок и может исполняться без необходимости создания отдельных файлов, что делает его удобным для инлайновых скриптов. При работе с командной строкой, PHP предоставляет глобальный массив $argv
, который содержит список всех аргументов, переданных скрипту. Первый элемент массива $argv[0]
всегда является именем файла скрипта, а последующие элементы — это переданные параметры. В Bash, командная строка поддерживает передачу аргументов скрипту при помощи переменных $@
, которые автоматически собирают все аргументы, переданные скрипту.
Пример применения
Рассмотрим пример скрипта, в котором Bash используется для запуска инлайнового PHP-скрипта, предназначенного для тестирования сетевого соединения. В этом случае важно правильно передать аргументы так, чтобы PHP смог их корректно обработать. Основной проблемой вашего текущего кода является попытка передать параметры из Bash в PHP, когда последний ожидает входные данные через стандартный ввод (STDIN), что приводит к ошибке «Could not open input file».
Корректное применение
Вот как можно исправить скрипт, чтобы он правильно передавал аргументы:
#!/usr/bin/env bash
# Определение PHP-скрипта как строки
SCRIPT=$(cat << 'EOM'
<?php
define('ERROR',"\033[0;31m");
define('OK',"\033[0;32m");
define('HIGHLIGHT',"\033[0;96m");
define('HIGHLIGHT2',"\033[1;33;4;44m");
define('HIGHLIGHT_ERROR',"\033[0;95m");
define('NC',"\033[0m");
if(count($argv) < 2){
echo HIGHLIGHT_ERROR." No IP and port provided".NC.PHP_EOL;
exit(-1);
}
$host = $argv[1];
$host_parts = explode(":",$host);
$host = $host_parts[0];
if(isset($host_parts[1])){
$port=$host_parts[1];
} elseif(isset($argv[2])){
$port = $argv[2];
} else {
echo HIGHLIGHT_ERROR." No port provided".NC.PHP_EOL;
exit(-1);
}
$port = intval($port);
$timeout = 30;
echo PHP_EOL."##############".PHP_EOL.PHP_EOL."TESTING ".HIGHLIGHT2.$host.':'.$port.NC.PHP_EOL;
$sk = @fsockopen($host, $port, $errnum, $errstr, $timeout);
if (!is_resource($sk)) {
echo ERROR."Connection fail: ".HIGHLIGHT_ERROR. $errnum . " " . $errstr.NC.PHP_EOL;
exit(1);
} else {
echo OK."Connected".NC.PHP_EOL;
exit(0);
}
EOM
)
# Передача аргументов
echo "$SCRIPT" | php -- $@
exit $?
Применение решений
При запуске данного скрипта через терминал, например, командой:
bash check_connect.sh 172.162.5.3:3306
аргументы будут корректно переданы в PHP-скрипт, который, в свою очередь, выполнит проверку соединения по заданному IP и порту.
Дополнительные советы
-
Отладка: Если возникает ошибка в работе скрипта, попробуйте добавить вывод отладочных сообщений, чтобы видеть, какие именно данные передаются в PHP. Это можно сделать, добавив команды
echo
в Bash иvar_dump()
илиprint_r()
в PHP. -
Безопасность: Всегда проверяйте вводимые данные на безопасность, особенно если скрипты планируется использовать в производственной среде. Это важно для защиты от атак, таких как инъекции.
-
Документирование: Документируйте каждый шаг скрипта, указывая, какие именно переменные и функции используются и почему. Это облегчит понимание вашего кода другими разработчиками или самим вами через некоторое время.
С данном подходом вы можете существенно расширить возможности своих Bash-скриптов, делая их более гибкими и функциональными.