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
相关推荐
lisanmengmeng2 小时前
添加ceph节点
linux·服务器·ceph
Tinyundg2 小时前
Linux系统分区
linux·运维·服务器
江畔何人初2 小时前
service发现
linux·运维·云原生
life码农2 小时前
Linux系统清空文件内容的几种方法
linux·运维·chrome
zbguolei2 小时前
虚拟机安装Ubuntu后无法登录
linux·运维·ubuntu
UP_Continue2 小时前
Linux--基础IO
linux·运维·服务器
驱动探索者2 小时前
linux hwspinlock 学习
linux·运维·学习
FJW0208142 小时前
使用HAProxy实现动静分离
linux·服务器
头发还没掉光光2 小时前
Linux 高级 IO 深度解析:从 IO 本质到 epoll全面讲解
linux·服务器·c语言·c++