shell编程 - 数据流指南

文章目录

  • [1. 核心概念](#1. 核心概念)
    • [1.1 文件描述符(File Descriptors)](#1.1 文件描述符(File Descriptors))
    • [1.2 重定向概念图](#1.2 重定向概念图)
  • [2. 输出重定向详解](#2. 输出重定向详解)
    • [2.1 基础输出重定向](#2.1 基础输出重定向)
    • [2.2 合并输出重定向](#2.2 合并输出重定向)
    • [2.3 特殊输出目标](#2.3 特殊输出目标)
  • [3. 输入重定向详解](#3. 输入重定向详解)
    • [3.1 基础输入重定向](#3.1 基础输入重定向)
    • [3.2 Here Document(文档内嵌)](#3.2 Here Document(文档内嵌))
    • [3.3 Here String(字符串输入)](#3.3 Here String(字符串输入))
  • [4. 文件描述符高级操作](#4. 文件描述符高级操作)
    • [4.1 自定义文件描述符](#4.1 自定义文件描述符)
    • [4.2 文件描述符复制与移动](#4.2 文件描述符复制与移动)
    • [4.3 输入文件描述符](#4.3 输入文件描述符)
  • [5. 管道符(|)的深入理解](#5. 管道符(|)的深入理解)
    • [5.1 基础管道](#5.1 基础管道)
    • [5.2 管道与文件描述符](#5.2 管道与文件描述符)
    • [5.3 管道的工作原理](#5.3 管道的工作原理)
  • [6. tee命令:分流输出](#6. tee命令:分流输出)
    • [6.1 tee基础用法](#6.1 tee基础用法)
    • [6.2 tee高级用法](#6.2 tee高级用法)
    • [6.3 tee与自定义文件描述符](#6.3 tee与自定义文件描述符)
  • [7. 进程替换](#7. 进程替换)
    • [7.1 基本概述](#7.1 基本概述)
    • [7.2 输入进程替换](#7.2 输入进程替换)
    • [7.2 输出进程替换](#7.2 输出进程替换)
  • [8. 最佳实践与陷阱](#8. 最佳实践与陷阱)
    • [8.1 常见陷阱](#8.1 常见陷阱)
    • [8.2 性能考虑](#8.2 性能考虑)
  • [9. 快速参考表](#9. 快速参考表)

1. 核心概念

1.1 文件描述符(File Descriptors)

文件描述符是操作系统用来跟踪打开文件的整数标识符,Shell中有三个标准文件描述符:

文件描述符 名称 默认设备 缩写
0 标准输入 键盘 stdin
1 标准输出 屏幕 stdout
2 标准输出 屏幕 stderr

1.2 重定向概念图

标准输出
标准错误
标准输入
连接命令
命令执行
输出类型
文件/设备
文件/设备
输入源
管道
下一个命令
文件
屏幕
dev/null
文件
屏幕
dev/null

2. 输出重定向详解

2.1 基础输出重定向

语法 说明 示例 应用场景
cmd > file 标准输出重定向到文件(覆盖) ls > list.txt 保存命令结果到文件
cmd >> file 标准输出重定向到文件(追加) date >> log.txt 日志记录
cmd 2> file 标准错误重定向到文件(覆盖) grep "x" nofile 2> error.log 错误日志分离
cmd 2>> file 标准错误重定向到文件(追加) cmd 2>> errors.txt 错误信息收集

2.2 合并输出重定向

语法 说明 示例 应用场景
cmd > file 2>&1 标准输出和错误都重定向到文件 script.sh > output.log 2>&1 完整日志记录
cmd &> file 同上(Bash简写) cmd &> all_output.txt Bash中简化写法
cmd > file1 2> file2 输出和错误分别到不同文件 make > build.log 2> error.log 分离正常和错误信息

示例详解:

bash 复制代码
# 错误示例:顺序很重要!
command 2>&1 > file    # 错误!stderr仍输出到屏幕
command > file 2>&1    # 正确!两者都到文件

# 解释:
# 2>&1 表示 "将stderr重定向到stdin当前指向的位置"
# 所以必须先重定向stdout,再重定向stderr

2.3 特殊输出目标

bash 复制代码
# 丢弃输出(黑洞设备)
command > /dev/null      # 丢弃标准输出
command 2> /dev/null     # 丢弃标准错误
command &> /dev/null     # 丢弃所有输出

# 实际应用:静默执行
if ping -c1 server &> /dev/null; then
    echo "Server is up"
fi

3. 输入重定向详解

3.1 基础输入重定向

语法 说明 示例 应用场景
cmd < file 从文件读取输入 wc -l < data.txt 统计文件行数
cmd << EOF Here Document 见下方示例 脚本内嵌数据
cmd <<< "str" Here String grep "x" <<< "text" 字符串作为输入

3.2 Here Document(文档内嵌)

bash 复制代码
# 基本用法
cat << EOF
这是多行文本
第二行内容
第三行内容
EOF

# 实际应用:自动化配置
ftp -n << END_FTP
open $SERVER
user $USER $PASS
binary
put $FILE
quit
END_FTP

# 抑制变量替换(单引号)
cat << 'EOF'
当前路径是:$PWD  # 这里$PWD不会展开
EOF

3.3 Here String(字符串输入)

bash 复制代码
# 传递字符串作为输入
tr 'a-z' 'A-Z' <<< "hello world"
# 输出:HELLO WORLD

# 实际应用:快速测试
md5sum <<< "test string"

4. 文件描述符高级操作

4.1 自定义文件描述符

bash 复制代码
# 创建自定义文件描述符
exec 3> custom.log      # 创建FD3用于输出
echo "Log message" >&3  # 写入FD3
exec 3>&-               # 关闭FD3

# 实际应用:多日志文件
exec 3> app.log
exec 4> error.log

echo "Info message" >&3
echo "Error occurred" >&4

exec 3>&-
exec 4>&-

4.2 文件描述符复制与移动

bash 复制代码
# 保存和恢复标准输出
exec 3>&1                     # 保存stdout到FD3
exec 1> output.log            # 重定向stdout到文件
echo "This goes to file"      # 输出到文件
exec 1>&3                     # 恢复stdout
echo "Back to terminal"       # 输出到终端

# 实际应用:临时重定向
log_to_file() {
    exec 3>&1  1>>"$LOG_FILE"  # 保存并重定向
    echo "[$(date)] $*"
    exec 1>&3 3>&-            # 恢复并关闭
}

4.3 输入文件描述符

bash 复制代码
# 从多个输入源读取
exec 3< input1.txt
exec 4< input2.txt

read -u 3 line1  # 从FD3读取
read -u 4 line2  # 从FD4读取

exec 3<&-
exec 4<&-

5. 管道符(|)的深入理解

5.1 基础管道

|command1的标准输出作为command2的标准输入

bash 复制代码
# 基本管道
command1 | command2          # command1的标准输出作为command2的标准输入
# 实际示例
ps aux | grep ssh            # 查找SSH进程
cat file.txt | sort | uniq   # 排序并去重

5.2 管道与文件描述符

bash 复制代码
# 管道只处理stdout,不处理stderr
ls nofile | wc -l            # stderr显示在屏幕,管道传递空输出

# 重定向stderr到管道
ls nofile 2>&1 | wc -l       # 错误信息也通过管道传递

5.3 管道的工作原理

关键特性
并行执行
匿名管道
单向通信
命令1
管道缓冲区
命令2

6. tee命令:分流输出

6.1 tee基础用法

tee命令从标准输入读取,并同时写入标准输出和文件。

bash 复制代码
# 基本语法
command | tee file           # 输出到屏幕和文件
command | tee -a file        # 追加到文件

# 实际应用
make 2>&1 | tee build.log   # 编译并保存日志

6.2 tee高级用法

bash 复制代码
# 多个输出目标
ls -l | tee file1 file2 file3

# 与管道结合
ls -l | tee file.log | grep "txt" | wc -l

# 实际应用:调试管道
cat data.txt | tee raw_data.log | grep "error" | tee errors.log | wc -l

6.3 tee与自定义文件描述符

bash 复制代码
# 保存中间结果
process_data() {
    input_data | tee >(process1) >(process2) > /dev/null
}

# 实际应用:并行处理
cat bigfile.txt | \
    tee >(grep "error" > errors.txt) \        
        >(grep "warning" > warnings.txt) \        
        >(wc -l > count.txt) \
        > /dev/null

7. 进程替换

7.1 基本概述

我们执行的命令是需要参数的。有些命令的参数是文件,而进程替换的意思就是使用进程去替换文件的位置
输入进程替换 :所有子进程的执行结果都会被保存到对应的临时文件中。所有子进程执行完毕后,主进程再执行。主进程以所有输入进程的临时文件作为输入参数
输出进程替换:主进程的输出文件参数被输出进程替换。主进程的所有输出都会被重定向到一个临时文件中,所有子进程以这个临时文件作为自己的输入文件参数

7.2 输入进程替换

diff命令用来比较两个文件的差异。现在这两个文件被两个输入进程替换掉了。bash会先起两个进程,执行进程中的命令,命令的输出结果会被分别保存到两个临时文件中。进程执行完毕后,diff命令比较两个临时文件的差异。

bash 复制代码
# 比较目录列表的差异
diff <(ls /path/to/dir1) <(ls /path/to/dir2)

# 比较文件排序后的差异
diff <(sort file1.txt) <(sort file2.txt)

paste命令用来合并多个文件。在这里,paste命令会等待三个输入进程执行完毕后,合并他们的临时文件

bash 复制代码
# 同时读取多个命令的输出
paste <(cat file1) <(wc -l file2) <(date)

# 输出示例(三列):# file1第一行内容   file2行数  当前日期时间

7.2 输出进程替换

tee命令的输出文件,被输出进程替换掉了,tee命令的所有输出,都会作为三个子进程的输入。

bash 复制代码
# 将输出同时发送到多个处理流程
echo "测试数据" | tee >(grep "测试" > test.txt) \                     
                     >(wc -l > count.txt) \                        
                     >(sha256sum > hash.txt)
                
# 查看结果
cat test.txt count.txt hash.txt

8. 最佳实践与陷阱

8.1 常见陷阱

bash 复制代码
# 陷阱1:顺序错误
cmd 2>&1 > file    # 错误!stderr不重定向到文件
cmd > file 2>&1    # 正确

# 陷阱2:管道中的stderr
cmd1 | cmd2        # stderr不通过管道
cmd1 2>&1 | cmd2   # stderr也通过管道

# 陷阱3:Here Document的空格
cat << EOF         # 正确
cat <<  EOF        # 错误(多空格)

8.2 性能考虑

bash 复制代码
# 避免不必要的tee
# 不佳:多次写磁盘
cat file | tee temp1 | process1 | tee temp2 | process2

# 改进:需要时才保存中间结果
if [ "$DEBUG" = "true" ]; then
    cat file | tee debug1.log | process1 | tee debug2.log | process2
else
    cat file | process1 | process2
fi

9. 快速参考表

操作 语法 说明
标准输出到文件 cmd > file 覆盖写入
追加输出 cmd >> file 追加写入
标准错误到文件 cmd 2> file 错误输出
两者都重定向 cmd &> file Bash简写
输入重定向 cmd < file 从文件读取
Here Document cmd << MARKER 内嵌文档
Here String cmd <<< "text" 字符串输入
管道 `cmd1 cmd2`
分流输出 `cmd tee file`
自定义FD输出 cmd >&3 写入FD3
自定义FD输入 cmd <&4 从FD4读取
关闭FD 3>&- 关闭FD3
相关推荐
HLC++10 小时前
Linux的进程间通信
android·linux·服务器
华清远见IT开放实验室11 小时前
实验室建设案例 | 石家庄科技信息职业学院嵌入式实验室——从底层硬件到系统应用,一所应用型高校的嵌入式人才培养这样落地
linux·arm开发·stm32·嵌入式硬件·高校·实验室建设
groundhappy14 小时前
idalib安装和codex ida-mcp配置
linux·开发语言·python
通信小小昕15 小时前
Ubuntu 26.04 中文输入法安装
linux·运维·ubuntu
张小姐的猫16 小时前
【Linux】网络编程 —— HTTP协议(上)
linux·运维·服务器·网络·http·单例模式·策略模式
栩栩云生16 小时前
AI 写代码犯的错,早被写进了错题集
linux·安全·ai编程
imc.1117 小时前
linux基础IO
linux·运维·服务器
BelongPanda19 小时前
Linux Nginx 纯手动 Let‘s Encrypt 泛域名证书配置教程
linux·nginx
酷可达拉斯19 小时前
Linux操作系统-shell编程(0)
linux·运维·服务器·python·云计算
2301_7779983420 小时前
Linux中断机制:操作系统如何高效运行
linux·运维·服务器