少于 1 分钟阅读 次阅读

问题背景

发现以下现象:

  1. 普通用户直接输出PATH
    user@user:~$ echo "$PATH"
    /opt/Qt5.15.2/bin:/usr/local/sbin:/usr/local/bin:...(其他系统路径)
    
  2. 普通用户通过sudo输出PATH
    user@user:~$ sudo echo "$PATH"
    /opt/Qt5.15.2/bin:/usr/local/sbin:/usr/local/bin:...(与操作1相同)
    
  3. 通过sudo sh -c输出PATH
    user@user:~$ sudo sh -c 'echo $PATH'
    /usr/local/sbin:/usr/local/bin:...(缺少/opt/Qt5.15.2/bin等路径)
    
  4. root用户直接输出PATH
    root@user:~# echo "$PATH"
    /opt/Qt5.15.2/bin:/usr/local/sbin:/usr/local/bin:...(与操作1相同)
    

核心疑问:为什么操作3的PATH缺失部分路径?而其他操作结果一致?


关键概念解析

1. Shell的类型与配置文件加载机制

Linux的Shell分为两种维度:

  • 登录Shell (Login Shell) vs 非登录Shell (Non-Login Shell)
    • 登录Shell:用户登录时启动(如SSH登录、su - username)。
      加载的配置文件
      • /etc/profile(系统级)
      • ~/.bash_profile~/.bashrc(用户级,仅bash)
    • 非登录Shell:在已登录会话中启动新Shell(如直接运行bash)。
      加载的配置文件
      • ~/.bashrc(用户级)
  • 交互式Shell (Interactive Shell) vs 非交互式Shell (Non-Interactive Shell)
    • 交互式Shell:允许用户输入命令(如终端窗口)。
    • 非交互式Shell:执行脚本或命令(如bash -c "command")。

2. sudo的执行机制

  • 默认行为
    • 以目标用户(默认root)身份执行命令。
    • 不加载目标用户的Shell配置文件(如/root/.bashrc)。
    • 环境变量继承策略:默认仅保留部分安全变量(如TERM),重置PATH为安全值(定义在/etc/sudoers中)。
  • 执行流程
    sudo command → 启动root的非交互式、非登录Shell → 执行command
    

现象原因分析

操作1:普通用户直接输出PATH

  • Shell类型:交互式登录Shell(如通过SSH登录)。
  • 配置文件加载
    • 加载/etc/profile~/.bashrc
    • 用户自定义路径(如/opt/Qt5.15.2/bin)通过~/.bashrc添加到PATH

操作2:sudo echo "$PATH"

  • 变量展开时机$PATHsudo执行前已被当前用户的Shell展开。
  • 实际输出:普通用户的PATH,而非root用户的PATH
  • 关键误解:看似输出root的路径,实则是普通用户的路径。

操作3:sudo sh -c 'echo $PATH'

  • Shell类型:root的非交互式、非登录Shell。
  • 配置文件未加载
    • 不读取/root/.bashrc(仅交互式Shell加载)。
    • PATH/etc/environment或默认安全路径定义。
  • 结果:仅包含系统默认路径,缺失自定义路径。

操作4:root用户直接输出PATH

  • Shell类型:交互式登录Shell(如su -sudo -i)。
  • 配置文件加载
    • 加载/root/.bashrc,其中包含与普通用户相同的自定义路径。

留下评论