Linux shell 自动化运维脚本案例

2次阅读

脚本中date生成文件名结果相同,因未用命令替换语法;正确写法为LOGFILE=$(date +%Y%m%d).log;远程ssh执行需注意环境差异、显式路径和伪终端分配;find删除失败常因目录权限不足;ps|grep误判因匹配自身进程,应改用systemctl is-active或pgrep。

Linux shell 自动化运维脚本案例

脚本里用 date 生成文件名时,为什么每次运行结果都一样?

因为没加引号或命令替换写法错误,date 在脚本定义阶段就被执行了一次,后续调用只是复用最初结果。

  • 错误写法:LOGFILE=date +%Y%m%d.log → 这是把字符串 date +%Y%m%d.log 赋给变量,根本没执行命令
  • 正确写法:LOGFILE=$(date +%Y%m%d).logLOGFILE=`date +%Y%m%d`.log
  • 注意:如果格式里含空格或特殊字符(比如 %Y-%m-%d %H:%M),必须用双引号包住整个替换结果:"$(date '+%Y-%m-%d %H:%M')"
  • 常见坑:在 for 循环里反复用未加括号的 date 变量,实际只取了第一次值

ssh 批量执行远程命令,怎么避免卡住或权限失败?

本质是交互式 shell 和非交互式 shell 的环境差异导致的 PATH、key 加载、tty 分配问题。

  • -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/NULL 跳过首次连接确认(仅测试环境)
  • 强制分配伪终端用 -t,但多个命令时慎用 —— 容易因 stdin 关闭提前退出;更稳的是用 ssh user@host 'cmd1; cmd2' 单行拼接
  • 关键点:远程命令不继承本地 ~/.bashrc,PATH 常丢失,所以要显式写全路径,比如 /usr/bin/systemctl restart nginx,或开头加 source /etc/profile;
  • 调试技巧:先本地模拟非交互环境:bash -c 'echo $PATH; which systemctl',再对比远程输出

find + exec 删除旧日志时,为什么有些文件删不掉还报 Permission denied

不是权限不够,而是 find 在遍历目录时,对子目录没有读(r)或执行(x)权限,就无法继续向下查找,直接报错跳过 —— 删除动作根本没触发。

  • 安全做法:先用 find /var/log -name "*.log" -mtime +7 -print 看匹配哪些文件,确认无误再加 -delete
  • -exec rm {} ; 更高效的是 -delete(POSIX 不保证支持,但 gnu find 通用),且不 fork 新进程
  • 若必须用 -exec,结尾用 ; 而非 +:后者会把所有匹配文件一次性传给一个 rm,遇到路径含空格或特殊字符容易崩
  • 修复权限问题:不是给文件加 w,而是确保对父目录有 r-x(即能进、能列),例如 chmod a+rx /var/log/nginx

脚本里判断服务是否运行,用 ps | grep 为什么总误报?

因为 grep 自身进程也会被匹配进去,比如查 nginx,结果里混着 grep nginx 这条,导致判断恒为真。

  • 经典绕过法:ps aux | grep "[n]ginx" —— 方括号让 grep 匹配字符串但自身命令显示为 grep [n]ginx,不匹配自己
  • 更可靠的是用 systemctl is-active --quiet nginx(systemd 系统)或 pgrep nginx >/dev/null
  • 注意 pgrep 默认只匹配进程名,若需完整命令行得加 -f,但性能略差;且某些精简系统(如 Alpine)可能没装 procps
  • 别用 pidof 判断存活:它只看 pid 文件或 /proc,不验证进程是否真在跑(比如僵尸进程或已崩溃但 pid 未释放)

自动化脚本最麻烦的从来不是功能写不出来,而是时间、权限、环境变量、进程状态这些“看不见的上下文”在不同机器上悄悄变了。多加一句 set -eux 开头,比写十行逻辑更能早发现问题。

text=ZqhQzanResources