Jacky's blog
首页
  • Android
  • Web
  • Server
  • Python
  • iOS
  • Java
  • Vue
  • 计算机基础
  • AI
  • 全部工具
  • CLI 工具
  • 编辑器
  • 开发工具
  • 构建工具
  • 版本控制
  • 调试工具
  • 网络工具
  • 个人成长
  • 博客
  • 分类
  • 标签
  • 归档
收藏
GitHub (opens new window)

Jack Yang

编程; 随笔
首页
  • Android
  • Web
  • Server
  • Python
  • iOS
  • Java
  • Vue
  • 计算机基础
  • AI
  • 全部工具
  • CLI 工具
  • 编辑器
  • 开发工具
  • 构建工具
  • 版本控制
  • 调试工具
  • 网络工具
  • 个人成长
  • 博客
  • 分类
  • 标签
  • 归档
收藏
GitHub (opens new window)
  • 计算机基础
  • 计算机基础

  • 网络

  • 操作系统

  • Shell
    • Shell 学习与使用导航
    • shell 入门指南
    • Shell 执行模型与环境加载
      • 执行模型
        • 父子 Shell
        • 进程替换
        • Here Document
        • 重定向
        • IFS 与逐行读取
      • 执行、加载与继承
    • Shell 错误处理、调试与资源清理
    • Shell 常用命令速查手册
    • Shell 代码片段集合
  • 安全

  • 设计模式

  • cs
  • shell
Jacky
2026-10-26
目录

Shell 执行模型与环境加载

# 执行模型

# 父子 Shell

  • 内建命令(如 cd)、赋值和函数通常在当前 Shell 执行;外部程序运行于独立进程,不能反向修改父进程环境
  • (...) 创建子 shell:内部的 cd、变量定义只在子 shell 内生效,不影响父 shell。适合临时切换环境
  • Bash 默认将管道各段放在子 Shell 环境。关闭作业控制并开启 shopt -s lastpipe 时,末段可在当前环境运行;Zsh 默认可让末段在当前环境执行。不要把管道中的变量修改作为跨 Shell 保证
  • 进程替换 <(...) 同样是子 shell

经典陷阱:管道接 while 循环,循环内的计数在子 shell 里,循环外拿不到:

# ✗ count 在子 shell 中自增,循环结束后丢失
count=0
cat file.txt | while IFS= read -r line; do count=$((count + 1)); done
echo "$count"    # Bash 默认输出 0;Zsh 默认保留末段计数

# ✓ 用重定向代替管道,循环在当前 shell 执行
count=0
while IFS= read -r line || [ -n "$line" ]; do count=$((count + 1)); done < file.txt
echo "$count"
1
2
3
4
5
6
7
8
9

# 进程替换

<(...) 用文件描述符路径或 FIFO 暴露命令输出(不是普通磁盘临时文件),供只接受文件参数的命令使用(bash/zsh):

diff <(ls /path1) <(ls /path2)                       # 比较两个命令的输出
cat <(echo "Hello World")
paste <(cut -d: -f1 /etc/passwd) <(cut -d: -f3 /etc/passwd)
1
2
3

# Here Document

<<TAG 把多行文本作为命令输入,TAG 为自定义结束标记(文本中未出现即可):

cat << END
这是一段
多行文本
END
1
2
3
4

关键区别:tag 加不加引号决定是否做变量展开——

cat << EOF            # 展开 $var
$(date) $USER
EOF

cat << 'EOF'          # 不展开,原样输出
$(date) $USER
EOF
1
2
3
4
5
6
7

写文件与赋值多行字符串:

cat << END > config.pbtx    # 多行文本写入文件
这是一段配置
END

info=$(cat << 'EOF'         # 多行字符串赋值给变量(引号防展开)
line1
line2
EOF
)
echo "$info"
1
2
3
4
5
6
7
8
9
10

# 重定向

写法 含义
cmd > file / cmd >> file stdout 覆盖 / 追加到文件
cmd 2> file / cmd 2>> file stderr 重定向
cmd > file 2>&1 stdout 和 stderr 都进 file(bash 可简写 &>file)
cmd > /dev/null 2>&1 丢弃全部输出
cmd 2>&1 | less 合并后进管道

2>&1 拆解:2 是 stderr 的文件描述符,> 重定向,&1 表示"引用 fd 1(stdout)",即把 stderr 合并到 stdout 当前指向的位置。

顺序很重要:cmd 2>&1 > file 先把 stderr 指向当时的 stdout(终端),再把 stdout 指向 file——stderr 仍打到终端。要合并进文件必须 > file 2>&1。

# IFS 与逐行读取

IFS(Internal Field Separator)决定 shell 分词的边界。逐行读取的标准写法:

while IFS= read -r path; do
    [ -z "$path" ] && continue
    ...
done < "$input_file"
1
2
3
4
  • IFS=(置空):不裁剪行首尾空白,整行作为单个变量值
  • -r:反斜杠不做转义,路径等特殊字符原样保留

按分隔符给多个变量分配字段;最后一个变量接收剩余部分:

IFS=' ' read -r first rest <<< "abc ddd eee fff"
printf '<%s><%s>\n' "$first" "$rest"  # <abc><ddd eee fff>
# 只写 read -r word 时,一个变量接收整行,不会逐词循环
1
2
3

# 执行、加载与继承

调用 执行环境 对当前终端的影响
./script.sh 新进程,按 shebang 选择解释器(需执行权限) 子进程的 cd、赋值不传回
bash script.sh 新 Bash 进程,忽略脚本 shebang 的解释器选择 不能修改父 Shell
source file / . file 当前 Shell 读取执行;. 是 POSIX 写法 变量、函数、cd、选项、exit 均影响当前 Shell
export NAME=value 标记变量传给之后启动的子进程 子进程不能反向更新父环境;不传递普通别名
exec command 外部命令替换当前 Shell 进程映像 正常不会返回;不应在日常终端随意执行
exec >log 2>&1 无命令时修改当前 Shell 文件描述符 后续输出持续重定向
PROJECT_HOME="$HOME/projects/demo"       # 当前 Shell 变量
export PROJECT_HOME                     # 后续子进程可继承
bash -c 'printf "%s\n" "$PROJECT_HOME"'  # 可以读到;子进程赋值不能改回父进程
1
2
3

配置加载与最短重载路径:交互 Zsh 在 ~/.zshrc 中放项目提供的单一加载入口,改配置后仍执行 source ~/.zshrc。加载链应由项目入口维护,不要求使用者记住内部环境文件。外部安装/初始化程序可以写入配置、安装到已有 PATH 目录,但不能直接改变已经运行的父 Shell;若新命令放进原有 PATH,往往立即可用。见 Zsh 配置。

Shell 常见启动文件(各模式不同)
Bash 登录 /etc/profile,随后首个可读的 ~/.bash_profile、~/.bash_login、~/.profile
Bash 交互非登录 ~/.bashrc;登录配置可显式加载它
Zsh .zshenv 总会参与常规启动;登录加 .zprofile,交互加 .zshrc,登录末尾加 .zlogin;路径受 ZDOTDIR 影响

$SHELL 通常表示账户登录 Shell,不代表当前脚本解释器。使用 type name / command -v name 检查别名、函数、命令与 PATH 命中情况;Bash 查找缓存必要时 hash -r,Zsh 可 rehash。

进程替换的失败:diff <(producer1) <(producer2) 只能直接得到 diff 的状态,生产者失败不会自动合并进它。关键数据先保存到受检的临时文件,再比较;不要认为 pipefail 会检查所有 <(...)。

依据:Bash 执行环境 (opens new window)、Bash 启动文件 (opens new window)、Zsh 执行规则 (opens new window)。

#Shell#guide
上次更新: 2026/10/26, 22:32:55
shell 入门指南
Shell 错误处理、调试与资源清理

← shell 入门指南 Shell 错误处理、调试与资源清理→

最近更新
01
Shell 错误处理、调试与资源清理
10-26
02
diff 与 patch:比较文件、目录和处理补丁
10-26
03
网络工具与诊断:macOS 和 Linux 对照
10-26
更多文章>
Theme by Vdoing | Copyright © 2019-2026 Jacky | MIT License
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式