在旧版本Bash 3.2中运行并行进程的技术问询
求助:完善适配Bash 3.2的多进程并发脚本
我正在尝试写一个Bash脚本实现多进程同时运行,但写到一半卡住了,想请各位帮忙完善一下,而且这个脚本得能在Bash 3.2版本上正常运行。
目前我写的不完整脚本如下:
#!/usr/bin/env bash read -r -p "Enter number of sessions: " pro_count read -r -p "directory of files: " d nodeb_job() { printf 'Connecting to %s\n' "$i" cd || exit if [ ! -d "$d" ]; then mkdir "$d"/log fi foo "$i" "$d"/"$i" > "$d"/log/"$i" printf 'Done with %s\n' "$i" } j=0 for i in $(ls "$d"); do if (( j++ >= ...
适配Bash 3.2的完整脚本
#!/usr/bin/env bash # 读取用户输入的并发数和目标目录 read -r -p "Enter number of sessions: " pro_count read -r -p "Directory of files: " d # 定义要并发执行的任务函数 nodeb_job() { local target_name="$1" local base_dir="$2" printf 'Connecting to %s\n' "$target_name" # 确保日志目录存在,用-p递归创建避免父目录不存在的问题 if [ ! -d "${base_dir}/log" ]; then mkdir -p "${base_dir}/log" fi # 执行自定义任务foo,输出写入对应日志文件 foo "$target_name" "${base_dir}/${target_name}" > "${base_dir}/log/${target_name}" printf 'Done with %s\n' "$target_name" } # 初始化并发计数器 current_jobs=0 # 安全遍历目标目录下的所有条目(替代ls,避免特殊文件名解析错误) for item_path in "${d}"/*; do # 跳过不存在的条目(比如目录为空时的通配符本身) [ -e "${item_path}" ] || continue # 获取条目名称(去掉目录前缀) item_name=$(basename "${item_path}") # 后台启动任务 nodeb_job "${item_name}" "${d}" & # 更新并发计数器,达到上限时等待所有后台任务完成 (( current_jobs++ )) if (( current_jobs >= pro_count )); then wait current_jobs=0 # 重置计数器,继续下一批任务 fi done # 等待最后一批未完成的后台任务 wait printf 'All jobs finished successfully!\n'
关键修改说明(适配Bash 3.2+)
- 安全目录遍历:把
$(ls "$d")换成"$d"/*,避免文件名包含空格、换行或特殊字符时出现解析错误,这是Bash中更可靠的遍历方式。 - 函数解耦:给
nodeb_job添加了参数,不再依赖全局变量i和d,让代码更易维护,也避免了并发时的变量冲突。 - 日志目录处理:用
mkdir -p递归创建日志目录,同时调整检查逻辑,确保$d/log存在(毕竟用户输入的d应该是已存在的目录)。 - 并发控制兼容旧版本:Bash 3.2不支持
wait -n(等待任意一个后台进程结束),所以采用“达到指定并发数就等待所有后台进程完成”的策略,这是兼容旧版Bash的稳定方案。 - 收尾等待:循环结束后加了
wait,确保最后一批启动的任务全部执行完毕。
另外提醒:脚本里的foo是你自定义的任务命令,请确保它在运行环境中能正常执行,或者根据实际需求替换成你的真实任务。
内容的提问来源于stack exchange,提问作者user3437245
相关产品推荐
相关产品推荐

