许多堆栈帖子似乎暗示了类似的事情:
* * * * * root /usr/bin/pgrep -f 'socat -T10 TCP4-LISTEN:22222,fork UDP4:localhost:22223' || (/usr/bin/socat -T10 TCP4-LISTEN:22222,fork UDP4:localhost:22223 &)
可以作为cron
文件中的一行程序工作(例如/etc/cron.d/mycron
),但在使用标准的 Ubuntu 22.04 上根本不起作用。如果我直接执行它,或者将它放入脚本文件中,然后从 cron 运行脚本文件(使用或,同样的事情),cron
它显然可以正常工作。bash
sh
* * * * * root /bin/sh /root/myscript.sh
从尝试获取日志来看,它看起来像进程是被启动,但随后被杀死。我尝试了许多不同级别的包围,&
最后有和没有。都没有用。我做错了什么?
答案1
分析
您的 cron 运行sh -c …
,其中…
表示单个参数是您在 crontab 中放置在 之后的字符串* * * * * root
。此字符串显然包含您要传递给 的模式pgrep
。实际上pgrep
至少找到此sh
进程并报告成功,socat
未执行并sh
退出。
如果/bin/sh /root/myscript.sh
后面的参数sh -c
不包含模式。这就是此方法有效的原因。
请注意,的参数pgrep
也匹配模式,但从pgrep
不报告自己匹配。如果报告了,它实际上就毫无用处了。通过pgrep
在 crontab 中直接使用,您可以设置一种情况,即它总是找到其父级(sh
)并且不知道它不应该找到。
解决方案
使用此行:
* * * * * root /usr/bin/pgrep -f '^socat -T10 TCP4-LISTEN:22222,fork UDP4:localhost:22223$' || (/usr/bin/socat -T10 TCP4-LISTEN:22222,fork UDP4:localhost:22223 &)
^
位于模式开头的命令匹配开头,$
位于模式结尾的命令匹配结尾。现在只有完全匹配的命令socat -T10 TCP4-LISTEN:22222,fork UDP4:localhost:22223
才会匹配;sh -c …
否则不会匹配。
简化
我认为这个特定的命令您可以简单地每分钟异步运行它:
* * * * * root /usr/bin/socat -T10 TCP4-LISTEN:22222,fork UDP4:localhost:22223 &
socat
如果监听的端口已被占用,则要点是退出。但是 Cron 不会看到失败,因为whatever &
它始终返回退出状态 0。
请注意,一般来说,您不能盲目地使用这种简化。我们的socat
自动退出这一事实至关重要。除了每分钟启动的socat
(甚至socat
使用不同的参数)之外的工具可能会存活并积累。一般来说pgrep
很有用。