我设置了一个 bash 脚本来监视多个 UDP 流并将其转换为可操作的数据。我的问题是我需要将脚本设置为定期检查流捕获是否正在运行,如果没有运行则重新启动它。
挑战在于为每个流捕获创建新的进程名称或 ID,并检查它是否正在运行。
这是我所拥有的内容的淡化版本。我希望有人能告诉我我是否走在正确的道路上:
Subscriber () {
processName="$1$2$4";
echo "$processName";
pgrep $processName;
if [[ $? -ne 0 ]] ; then
echo "Subcription for $1 with IP $2 not found, restarting." ;
while read -re -t 43200 doc; do
<Code to analyze stream>
done < <(bash -c "exec -a $processName <Commands to capture stream as JSON doc>")
else
echo "Subcription for $1 wtih IP $2 found to be running, skipping." ;
fi
}
while read line; do
Subscriber $line;
done < $flatFile
理想情况下,我想获取 exec -a 之后列出的整个命令字符串的进程 ID 或名称,但它目前只接受第一个命令,这似乎有点工作,但我不相信它会做我想让它做的事。
flatFile 参考是一个动态更新的平面文件,列出了我正在监视的数百个流。
答案1
Linux 上的进程名称至少会在进程每次执行命令时更改,但会更改为所执行文件的基本名称,而不是argv[0]
bash 允许传递exec -a
.
pgrep
可以在 arg 列表(用空格连接)上与选项匹配-f
,但请注意,像 for 一样grep
,pgrep
进行r
常规e
表达式匹配,因此您需要构造一个正则表达式来匹配argv[0]
您想要的。
或者您可以确保传递的名称exec -a
不包含正则表达式字符(包括.
IPv4 地址中常见的字符)。
Subscriber () {
process_arg0="$1$2$4"
# change all regex operators and space to _
process_arg0="${process_arg0//[][ .\\+?\$^()*{\}]/_}"
printf>&2 '%s\n' "$process_arg0"
if ! LC_ALL=C pgrep -f "^$process_arg0( |\$)"; then
printf>&2 '%s\n' "Subscription for $1 with IP $2 not found, restarting."
while IFS= read -r -t 43200 doc; do
<Code to analyze stream>
done < <(
exec -a "$process_arg0" <Commands to capture stream as JSON doc>
)
else
printf>&2 '%s\n' "Subscription for $1 with IP $2 found to be running, skipping."
fi
}
(还删除了一些其他明显的错误,例如未加引号的引号、 的使用echo
、 的无意义-e
选项read
、 缺少IFS=
、read
解释器代码中嵌入的变量数据)。
无论如何,通过名称或参数列表匹配进程是非常脆弱和危险的,因为任何进程都可以为自己分配它们想要的任何名称或参数列表,并且这里使用的方法引入了竞争条件。使用适当的进程监督者/主管,例如您的 init 系统(systemd
、upstart
和 co)或专用工具,例如runit
、daemontools
、supervisor
、start-stop-daemon
可能更合适。