【操作系统】记录一次遇到shell退出码的问题处理


一、问题背景

在编写 Linux 安全检测脚本时,在处理一段代码逻辑的时候遇到一个有意思的问题,研究明白后整理出来。我在 shell 脚本中使用了如下结构:

suspicious_env=$(tr '\0' '\n' < "$proc_dir/environ" | grep -E "..." 2>/dev/null) || handle_error ...

以及:

suspicious_map=$(grep -E "..." "$proc_dir/maps" 2>/dev/null) || handle_error ...

目的是:

  • 检测进程的可疑环境变量或内存映射(grep 匹配到说明检测项异常,反之说明检测项没问题)。
  • 如果读取失败,调用 handle_error 报错并跳过当前进程。

但是发现:

即使没有错误,只是 grep 没有匹配内容(检测项正常),也会触发 handle_error


二、问题本质

1. Shell 中的退出码行为

退出码含义Shell 判断为成功?
0成功(有匹配)
1成功但无匹配
2+出现错误(如文件不存在)

2. || 的逻辑行为

command || fallback

如果 command 返回非 0(即失败),就会执行 fallback

所以:

  • grep 执行成功但没有匹配到内容时会返回 1,Shell 会当作失败处理,导致执行 handle_error
  • 但我只想在文件读取失败时才报错,而不是因为没有匹配内容就报错

三、解决方案

1. 分开处理“读取失败”和“没有匹配内容”

原理:
  • 先读取文件内容到变量(如 env_contentmap_content
  • 判断读取是否失败(退出码非 0),才调用 handle_error
  • 再用 grep 匹配内容,即使没有匹配,也不报错
示例:
env_content=$(tr '\0' '\n' < "$proc_dir/environ" 2>/dev/null)
if [ $? -ne 0 ]; then
    handle_error ...
    continue
fi

suspicious_env=$(echo "$env_content" | grep -E "...")

2. 使用变量代替多次读取文件

  • 一次性读取 /proc/<pid>/environ/proc/<pid>/maps 到变量中
  • 后续操作都基于变量,提高性能,减少系统调用

3. 处理正则表达式中的特殊字符

比如:

rwxp.*$$heap$$
  • 在 Shell 中,$$ 会被解释为当前进程 PID,导致匹配失败

  • 正确做法是:

    grep -E '(rwxp.*$$heap$$)'
    

    或:

    grep -E 'rwxp.*$$heap$$'
    

    用单引号包裹整个正则表达式,防止被 Shell 替换


四、优化后的写法(我最终采用)

环境变量检测(environ

env_content=$(tr '\0' '\n' < "$proc_dir/environ" 2>/dev/null)
if [ $? -ne 0 ]; then
    handle_error 0 "读取进程 ${pid} 环境变量失败" "processInfo"
    continue
fi

suspicious_env=$(echo "$env_content" | grep -E '(LD_PRELOAD|LD_LIBRARY_PATH.*\.so|ROOTKIT|HIDE)')
if [ -n "$suspicious_env" ]; then
    proc_name=$(cat "$proc_dir/comm" 2>/dev/null || echo "unknown")
    env_anomalies+=("PID:$pid Name:$proc_name 可疑环境变量")
fi

内存映射检测(maps

map_content=$(cat "$proc_dir/maps" 2>/dev/null)
if [ $? -ne 0 ]; then
    handle_error 0 "读取进程 ${pid} 内存映射失败" "processInfo"
    continue
fi

suspicious_map=$(echo "$map_content" | grep -E '(rwxp.*$$heap$$|rwxp.*$$stack$$|rwxp.*deleted)')
if [ -n "$suspicious_map" ]; then
    proc_name=$(cat "$proc_dir/comm" 2>/dev/null || echo "unknown")
    suspicious_maps+=("PID:$pid Name:$proc_name 可疑内存映射")
fi

五、总结一句话

不要直接对 grep 命令使用 ||,除非你真的需要区分“有无匹配内容”。

否则,应该先判断文件是否读取失败,再单独处理匹配内容。


by 久违

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

久违 °

我看到了月亮

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值