测试将 50000 个参数从 php 传递到 bash 脚本需要多长时间,结果是我无法一次将 1000 个参数从 php 传递到 bash 脚本,除非我可以?
PHP:
$array = fetch_results_from_working_pool_temp_table ();
$outputfile = "/var/www/html/outputFile";
$pidfile = "/var/www/html/pidFile";
$id = "";
$array_check=array();
foreach ( $array as $row => $column ) {
$id .= $column ['id'];
$id .= " ";
}
$cmd = "sudo /bin/bash /var/www/html/statistics/pass_all.sh {$id}";
exec( sprintf ( "%s >> %s 2>&1 & echo $! >> %s", $cmd, $outputfile, $pidfile ) );
bash:
#!/bin/bash
for ip in "$@"
do
echo "${ip}"
done
所以我的php将参数传递给巴什, bash 打印到输出文件以及任何错误。pid文件将保存使用此 exec 启动的进程的 pid。 该命令甚至没有被执行,因为我没有看到任何进程启动。exec 中传递的参数有限制吗?或者从 PHP 或 Linux shell 中? 我正在运行 php 5.4 和 Linux Redhat 7 我想使用 GNU 并行运行进程,但因为 PHP 是单线程的(有库可以传递这个,但我宁愿避免这种情况)。也许我可以以某种方式将它传递给一个文本文件并执行从该文本文件中提取的脚本?帮助!
**更新:我的机器限制:** #getconf ARG_MAX 2097152 #ulimit -a 核心文件大小(块,-c)0 数据段大小(kbytes,-d)无限制 调度优先级 (-e) 0 文件大小(块,-f)无限制 待处理信号 (-i) 256634 最大锁定内存(千字节,-l)64 最大内存大小(kbytes,-m)无限制 打开文件 (-n) 1024 管道大小(512 字节,-p)8 POSIX 消息队列(字节,-q)819200 实时优先级 (-r) 0 堆栈大小(千字节,-s)8192 CPU时间(秒,-t)无限制 最大用户进程数 (-u) 4096 虚拟内存(千字节,-v)无限制 文件锁 (-x) 无限制
答案1
在大多数系统上,内核限制execve()
系统调用参数的大小(命令行参数+环境变量)。在 Linux 上,该限制与最大堆栈大小有关,但通常默认堆栈大小限制为 8 MB,您至少会获得至少 2 MB 的总大小。它还限制了一个单身的参数为 128 kB,参见例如bash 文件名扩展(通配符)是否有最大限制?如果有,它是什么?和Linux 中环境变量的限制提高 128KiB
如果 PHPsh -c 'command line'
在您调用时运行exec("command line")
,则参数-c
很可能会超过 128 kB 限制。事实上,命令行随后被 shell 分割成不同的单词,这一事实也无济于事。
答案2
当您有这么多参数时,您希望通过标准输入 (stdin) 或文件将它们传递给 GNU Parallel。
我会做类似的事情(未经测试):
$f = popen("parallel","w");
fwrite($f,$commands);
close ($f);
这样您就可以避免临时文件。
答案3
因此,在您的帮助下,这是我的解决方案:PHP:
function scan_targets() {
$targetsFile= "[absolute path to the file]/targets";
$array_with_targets = fetch_from_db (); //function that gets me all the targets
$outputfile = "[absolute path to the file]/outputFile"; //output from parallel script
$pidfile = "[absolute path to the file]/pidFile"; //PID of the process
$target = "";
foreach ( $array_with_targets as $row => $column ) {
$id .= $column ['id'];
$id .= " ";
}
file_put_contents($targetsFile, $ip) ;
$cmd = "/bin/bash [absolute path to the file]/pass_targets.sh";
exec( sprintf ( "%s >> %s 2>&1 & echo $! >> %s", $cmd, $outputfile, $pidfile ) );
重击:
#!/bin/bash
#appending arguments to the command
targets_array=()
IFS=" "
while read -r field || [ -n "$field" ]; do
targets_array+=("$field")
done <[absolute path to the file]/targets
parallel bash [absolute path to the file]/check.sh ::: $targets_array
您还可以使用 -Dall 选项运行并行,以了解正在发生的情况,我设法在 7 小时内扫描了近 40.000 个主机。 Web 服务器在几秒钟内将所有目标添加到文件中,并且当我的 exec 启动使用的后台进程时,无需等待结果(我们将其输出到文件中)。
check.sh 脚本还会更新特定目标的 Mariadb 数据库记录。