5.1.1 Shell环境与执行方式

Shell环境概述#

Shell 是用户与内核交互的命令解释器,常见实现包括 Bash、Zsh、Dash。不同 Shell 在语法与内建命令上存在差异,运维脚本通常以 Bash 为主。

文章图片

常见 Shell 类型与识别#

  • 查看当前登录 Shell(用户默认):echo $SHELL
  • 查看当前运行中的 Shell:ps -p $$
  • 常见路径:/bin/bash/bin/sh/bin/zsh
  • /bin/sh 可能指向 dashbash,需注意兼容性

命令示例与说明:

echo $SHELL          # 输出用户默认登录Shell
ps -p $$ -o comm=    # 输出当前进程对应的Shell名称
ls -l /bin/sh        # 查看 /bin/sh 实际指向

预期效果:
- echo $SHELL 输出如 /bin/bash
- ls -l /bin/sh 输出如 -> dash-> bash

Shell 启动方式#

  • 登录 Shell:读取 /etc/profile~/.bash_profile~/.bash_login~/.profile
  • 非登录交互 Shell:读取 ~/.bashrc
  • 非交互 Shell(脚本):默认不读取上述文件,可用 source. 显式加载

示例:验证不同启动方式加载配置

# 1) 在 ~/.bashrc 中加入标记
echo 'echo "Loaded .bashrc"' >> ~/.bashrc

# 2) 开一个新的非登录交互shell
bash
# 预期输出:Loaded .bashrc

# 3) 退出后执行非交互脚本
cat > /tmp/test.sh <<'EOF'
#!/bin/bash
echo "RUN SCRIPT"
EOF
bash /tmp/test.sh
# 预期输出:RUN SCRIPT(不会显示 Loaded .bashrc)

脚本执行方式#

  • 显式调用解释器bash script.sh,不依赖执行权限
  • 直接执行./script.sh,需可执行权限与正确的 shebang
  • source 执行source script.sh. script.sh,在当前 Shell 中执行并保留变量

示例:三种方式对变量影响

cat > /tmp/envdemo.sh <<'EOF'
#!/bin/bash
export FOO="from_script"
BAR="local_only"
echo "FOO=$FOO BAR=$BAR"
EOF

# 1) 显式调用
bash /tmp/envdemo.sh
echo "FOO=$FOO BAR=$BAR"   # 预期:FOO= BAR=

# 2) 直接执行
chmod +x /tmp/envdemo.sh
/tmp/envdemo.sh
echo "FOO=$FOO BAR=$BAR"   # 预期:FOO= BAR=

# 3) source 执行
source /tmp/envdemo.sh
echo "FOO=$FOO BAR=$BAR"   # 预期:FOO=from_script BAR=local_only

Shebang 与执行环境#

  • Shebang 位于脚本首行:#!/bin/bash
  • 指定解释器路径,决定脚本语法与内建命令
  • 推荐使用:#!/usr/bin/env bash 以适配多路径环境

示例:不同 shebang 的可移植性

cat > /tmp/hello.sh <<'EOF'
#!/usr/bin/env bash
echo "Hello from $(command -v bash)"
EOF
chmod +x /tmp/hello.sh
/tmp/hello.sh

命令解释:
- command -v bash:输出 bash 的实际路径
- #!/usr/bin/env bash:通过环境变量查找 bash,适配不同系统路径

执行环境与变量作用域#

  • 子进程执行脚本时,变量需 export 才能传递
  • source 执行不会开启子进程,可直接影响当前环境
  • 脚本中设置的 PATH 只在当前进程有效

示例:export 的作用

cat > /tmp/varscope.sh <<'EOF'
#!/bin/bash
echo "IN SCRIPT: FOO=$FOO"
EOF

FOO="local"
bash /tmp/varscope.sh        # 预期:IN SCRIPT: FOO=
export FOO="exported"
bash /tmp/varscope.sh        # 预期:IN SCRIPT: FOO=exported

执行权限与安全注意#

  • 赋予权限:chmod +x script.sh
  • 控制可写权限,避免脚本被篡改
  • 避免在脚本中硬编码敏感信息,必要时使用环境变量或外部配置

权限与安全示例:

# 仅所有者可读写执行
chmod 700 /usr/local/bin/backup.sh
ls -l /usr/local/bin/backup.sh

预期效果:
- 权限显示为 -rwx------,减少被非授权用户修改的风险

安装与依赖检查(Bash)#

多数发行版默认安装 Bash,可通过包管理器确认:

# Debian/Ubuntu
dpkg -l | grep -E '^ii  bash'
# CentOS/RHEL
rpm -qa | grep '^bash-'

排错与常见问题#

1) 报错:/bin/bash^M: bad interpreter
- 原因:脚本为 Windows 换行
- 解决:

sed -i 's/\r$//' /path/script.sh

2) 报错:permission denied
- 原因:未赋执行权限
- 解决:

chmod +x /path/script.sh

3) 报错:command not found
- 原因:PATH 不包含命令路径或使用了 sh 运行 bash 特性
- 解决:

which yourcmd
export PATH=$PATH:/usr/local/bin
bash /path/script.sh

实战建议#

  • 统一使用 Bash 并在脚本首行声明
  • 明确脚本执行方式,避免环境差异导致的兼容问题
  • 脚本顶部视需要启用严格模式:set -euo pipefail

示例:严格模式模板

cat > /tmp/template.sh <<'EOF'
#!/usr/bin/env bash
set -euo pipefail

echo "脚本启动..."
EOF
chmod +x /tmp/template.sh

练习#

1) 编写脚本 envcheck.sh 输出当前 Shell、/bin/sh 指向,并展示 $PATH 的前 3 项。
2) 使用 source 运行脚本,观察变量在当前 Shell 中是否保留。
3) 故意将脚本改为 CRLF 行尾并修复。