You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

带全局exec重定向的Bash脚本在root与普通用户下行为不一致求助

问题原因与解决方案

原因分析

  • 普通用户执行时输出在提示符后:
    你用的exec &> >(tee -a main.log)通过进程替换创建tee进程,接管脚本的stdout和stderr。但进程替换的输出和父shell的提示符输出是异步的——脚本执行完后父shell立刻打印提示符,tee的输出却稍晚才到终端,所以就出现了输出在提示符后面的情况。

  • root用户执行时终端无输出、日志有重复内容:
    日志里的两次inactive是两次执行(普通用户+sudo)的结果,不是单次执行写入两次。sudo执行时终端没输出,是因为sudo会修改终端权限或环境,导致进程替换里的tee无法正确关联当前终端;加上exec &> >(tee...)完全接管了bash的stdout/stderr,在sudo环境下终端文件描述符可能被重置,最终tee的输出只能写入日志,没法显示到屏幕。

  • bash -x执行时的异常:
    bash -x的调试信息默认发往stderr,而你用exec &> >(tee...)把stderr也重定向到了tee,所以调试信息会被写入日志而非终端;看起来脚本“停止”只是因为调试输出没在屏幕显示,实际脚本仍在运行,和你补充的说明一致。

修复后的脚本

改用管道+代码块的写法,避免进程替换带来的环境差异,在普通用户和root下行为完全一致:

#!/bin/bash

{
    case $1 in
        "start")
            echo "Starting some services..."
            ;;
        "status")
            echo "inactive"
            ;;
        *)
            echo "Usage: $0 start | status" >&2
            exit 1
            ;;
    esac
} 2>&1 | tee -a main.log

写法说明

  • 用{ ... }把核心逻辑包裹成代码块,统一处理所有输出
  • 2>&1将代码块的stderr重定向到stdout,让所有输出进入管道
  • tee -a main.log同时把管道内容输出到终端,并且追加写入日志文件

如果需要把bash -x的调试信息也写入日志,可以手动把调试输出也接入管道:

bash -x ./main.sh status 2>&1 | tee -a debug.log

内容的提问来源于stack exchange,提问作者Unda

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.22 11:03:17