求助:Bash while循环中ffmpeg无法随动态URL变量更新启停
动态更新URL并控制ffmpeg启停的Bash脚本修复
需求说明
- 通过
journalctl监听"application"的日志,提取其中的目标URL(var0) - 根据
var0的状态执行对应逻辑:- URL未变化:不执行任何操作
- URL已变更:终止运行中的ffmpeg,使用新URL重启推流
- URL为空:终止运行中的ffmpeg,等待新的URL出现
- 最终通过ffmpeg将分离的音视频HLSv5流合并为MPEG-TS格式,推送到
udp://227.0.0.1:1234
当前问题
脚本首次启动时逻辑正常,但当var0变更或为空时,仍会沿用首次启动的URL执行ffmpeg,无法按预期完成启停控制。
原脚本
#!/bin/sh journalctl -fu application -o cat > /tmp/jctl & while true do cat /tmp/jctl | grep "playing" | tail -n1 | tee /tmp/all grep -Eo "(prox/http|prox/https)%3a//\[a-zA-Z0-9./?=\_%:-\]\*(:)" /tmp/all | tail -n1 | sed 's,:,,g' | sed 's,prox/https%3a,https:,g' | tee /tmp/var0 var0=$(sed -n "1p" /tmp/var0) if [ ! -z "$var0" ] # URL not empty then curl -L $var0 | tee /tmp/tmp var1=$(sed -n '/RESOLUTION=1/{n;p}' /tmp/tmp | sed -n "1p") var2=$(sed '/DEFAULT=YES[^[]*URI="/!d;s//&\n/;s/.*\n//;:a;/"/bb;$!{n;ba};:b;s//\n&/;P;D' /tmp/tmp | sed -n "1p") `ffmpeg -re -rtbufsize 8M -i $var1 -i $var2 -c copy -f mpegts udp://227.0.0.1:1234?pkt_size=1316 &` fi done
修复后的脚本
#!/bin/bash # 初始化状态变量 old_var0="" ffmpeg_pid="" # 定义临时文件列表,方便统一清理 temp_files="/tmp/jctl /tmp/all /tmp/var0 /tmp/tmp" # 脚本退出时的清理逻辑 cleanup() { # 终止ffmpeg进程(如果存在) [ -n "$ffmpeg_pid" ] && kill "$ffmpeg_pid" 2>/dev/null # 删除临时文件 rm -f $temp_files exit 0 } # 捕获退出、中断、终止信号,触发清理 trap cleanup EXIT INT TERM # 启动journalctl实时监听日志,后台运行 journalctl -fu application -o cat > /tmp/jctl & while true do # 只读取新增的日志行,避免重复处理历史内容 tail -n0 -F /tmp/jctl | grep -m1 "playing" | tee /tmp/all # 修正正则,正确提取并格式化URL grep -Eo "(prox/http|prox/https)%3a//[a-zA-Z0-9./?=\_%:-]*" /tmp/all | tail -n1 | sed 's,prox/http%3a,http:,g' | sed 's,prox/https%3a,https:,g' | tee /tmp/var0 var0=$(cat /tmp/var0 | tr -d '\n') # 情况3:URL为空,终止ffmpeg并重置状态 if [ -z "$var0" ]; then [ -n "$ffmpeg_pid" ] && kill "$ffmpeg_pid" 2>/dev/null ffmpeg_pid="" old_var0="" continue fi # 情况1:URL未变化,直接跳过循环 if [ "$var0" = "$old_var0" ]; then continue fi # 情况2:URL已变更,先终止旧的ffmpeg进程 [ -n "$ffmpeg_pid" ] && kill "$ffmpeg_pid" 2>/dev/null # 获取音视频流地址,简化sed逻辑 curl -L "$var0" | tee /tmp/tmp var1=$(sed -n '/RESOLUTION=1/{n;p}' /tmp/tmp | head -n1) var2=$(sed -n '/DEFAULT=YES/{s/.*URI="\([^"]*\)".*/\1/p}' /tmp/tmp | head -n1) # 启动新的ffmpeg进程并记录PID ffmpeg -re -rtbufsize 8M -i "$var1" -i "$var2" -c copy -f mpegts udp://227.0.0.1:1234?pkt_size=1316 & ffmpeg_pid=$! # 更新旧URL记录 old_var0="$var0" done
关键修改说明
- 进程管控:新增
ffmpeg_pid变量记录进程ID,确保能精准终止旧的ffmpeg实例 - URL对比:用
old_var0保存上一次的有效URL,避免重复启动相同推流任务 - 空URL处理:明确判断URL为空时的逻辑,终止ffmpeg并重置状态
- 日志读取优化:改用
tail -n0 -F仅读取新增日志行,避免每次循环重复处理历史内容 - 正则修正:修复原URL提取正则的语法错误,确保能正确匹配目标URL
- 安全加固:给变量添加双引号,避免含特殊字符的URL导致命令执行异常
- 清理机制:新增退出清理逻辑,脚本终止时自动删除临时文件、终止子进程
- 逻辑简化:简化
var2的提取sed命令,提升可读性和稳定性
内容的提问来源于stack exchange,提问作者NewbiDam
相关产品推荐
相关产品推荐

