Ubuntu下Bash脚本有时失效:禁用USB端口后无法恢复
看起来你的脚本核心逻辑没问题,但偶尔失效的情况大概率是crontab执行环境的特殊性或者脚本鲁棒性不足导致的,咱们一步步排查解决:
1. 先搞清楚到底哪一步出问题:加日志记录
crontab默认不会输出脚本的执行信息,你根本不知道是sleep没执行还是恢复命令失败了。先修改crontab的执行行,把日志打出来:
# 假设你的脚本路径是/root/usb_fix.sh,改成这样: */5 * * * * /root/usb_fix.sh >> /var/log/usb_script.log 2>&1
之后再出现失效情况时,直接看/var/log/usb_script.log里的报错,就能定位具体环节。
2. 给所有命令加上绝对路径
crontab的环境变量PATH比你平时用的shell窄很多,比如sleep、ping这些命令可能因为路径问题没找到,导致脚本中途退出。把脚本里的所有命令都换成绝对路径:
/bin/sleep代替sleep/bin/ping代替ping/bin/echo代替echo
比如原来的sleep 5改成/bin/sleep 5,这样就不会因为PATH缺失导致命令执行失败。
3. 优化网络检测逻辑,避免误判
如果你的网络检测只是简单的ping -c 1 google.com,很容易因为临时丢包、DNS解析失败误判成无网络。换成更可靠的检测方式,比如检测DNS端口:
# 用nc检测8.8.8.8的53端口(Google公共DNS),超时2秒 if ! /bin/nc -z -w 2 8.8.8.8 53; then # 这里执行USB禁用逻辑 fi
或者多ping几次提高准确率:
if ! /bin/ping -c 3 -W 2 8.8.8.8 > /dev/null 2>&1; then # 无网络,执行操作 fi
4. 动态获取USB设备路径,别硬编码
你说只有一个USB端口,但有时候系统重启或者设备重新识别后,设备路径可能会变(比如从1-1变成1-2)。如果脚本里硬编码了路径,就会导致恢复时找不到设备。改成动态获取:
# 获取USB驱动下的设备节点(排除usb本身的目录) USB_DEVICE=$(/bin/ls /sys/bus/usb/drivers/usb/ | /bin/grep -E "^[0-9]+-[0-9]+$") if [ -n "$USB_DEVICE" ]; then # 禁用USB端口 /bin/echo "$USB_DEVICE" > /sys/bus/usb/drivers/usb/unbind # 把恢复操作放到后台执行,避免当前脚本中断导致失败 /bin/sleep 5 && /bin/echo "$USB_DEVICE" > /sys/bus/usb/drivers/usb/bind & fi
把恢复命令放到后台(加&),就算当前脚本因为某种原因被中断,后台的sleep和启用命令依然会执行。
5. 给脚本加锁,避免并行冲突
如果crontab的执行间隔太短(比如1分钟一次),而上一次的脚本还在sleep状态,就会导致多个脚本实例并行运行,互相干扰。用flock给脚本加锁:
修改crontab行:
*/5 * * * * /usr/bin/flock -n /tmp/usb_script.lock /root/usb_fix.sh >> /var/log/usb_script.log 2>&1
这样同一时间只会有一个脚本实例在运行,避免冲突。
最后验证
按照上面的修改调整后,观察几天日志,如果还是有问题,把日志里的报错信息贴出来,就能进一步定位了。
内容的提问来源于stack exchange,提问作者Andermutu

