Cron调度脚本时特定命令输出无法写入文件的问题排查
这个问题我之前帮朋友排查过类似的,核心原因大概率是cron的执行环境和你手动登录的shell环境差异,再加上sudo在无交互场景下的权限限制,导致那条进程fd统计的命令没正常跑起来。咱们一步步拆解解决:
1. 先搞定cron的PATH环境变量问题
手动登录shell时,你的PATH包含了很多系统命令的路径(比如/usr/bin),但cron默认的PATH非常精简(通常只有/usr/bin:/bin,不同系统略有区别)。如果命令里用了相对路径的工具,cron可能找不到对应的执行文件。
解决办法:把命令里的所有工具都换成绝对路径,你可以用which ps、which xargs这类命令查到它们的绝对路径。修改后的命令示例:
/usr/bin/ps -A -opid | /usr/bin/sudo /usr/bin/xargs -n1 -I{} /bin/bash -c '/usr/bin/echo {} $(/usr/bin/ls /proc/{}/fd | /usr/bin/wc -l);'
2. 解决sudo的无交互权限障碍
手动运行脚本时,你在交互式shell里,sudo会缓存密码或者你本身就是root;但cron是无后台静默运行的,sudo需要输入密码时会直接失败,导致整条命令终止。
这里有两个实用方案:
方案一:配置免密sudo权限
用visudo命令编辑sudoers文件(一定要用visudo,避免语法错误搞崩sudo),添加一行允许你的用户免密执行目标命令:your_username ALL=(ALL) NOPASSWD: /usr/bin/xargs -n1 -I{} /bin/bash -c 'echo {} $(ls /proc/{}/fd | wc -l);'把
your_username换成实际运行脚本的用户名,这样cron执行时sudo就不会卡密码了。方案二:直接用root用户的cron跑脚本
如果监控脚本本身就需要系统级权限,干脆切换到root(sudo su -),然后编辑root的cron(crontab -e)添加脚本。这样可以直接去掉命令里的sudo,彻底规避权限问题:/usr/bin/ps -A -opid | /usr/bin/xargs -n1 -I{} /bin/bash -c '/usr/bin/echo {} $(/usr/bin/ls /proc/{}/fd | /usr/bin/wc -l);'
3. 加个错误日志方便排查问题
可以在脚本里把错误输出重定向到日志文件,这样如果命令执行失败,你能看到具体的报错(比如命令找不到、权限不足)。比如在那条命令后面追加:
2>> /home/cron_memory_monitor_errors.log
按照这几步调整后,再测试cron调度,应该就能正常收集进程fd信息并写入文件了。
内容的提问来源于stack exchange,提问作者Goku

