七、重定向及管道

Linux I/O重定向与管道
本文详细介绍了Linux系统中的I/O重定向和管道技术,包括标准输入输出的定义、重定向的不同形式及其应用场景,并通过实例展示了如何使用这些技术来提高工作效率。

🎹 个人简介:大家好,我是 金鱼哥,CSDN运维领域新星创作者,华为云·云享专家,阿里云社区·专家博主
📚个人资质:CCNA、HCNP、CSNA(网络分析师),软考初级、中级网络工程师、RHCSA、RHCE、RHCA、RHCI、ITIL😜
💬格言:努力不一定成功,但要想成功就必须努力🔥

🎈支持我:可点赞👍、可收藏⭐️、可留言📝


本章节介绍重定向及管道的运用。这两个要好好理解,因为工作中用得非常之多,所以一定要掌握好。


📜7.1 标准输入和输出

程序:指令+数据
读入数据:Input
输出数据:Output
打开的文件都有一个fd: file descriptor (文件描述符)

📑文件描述符定义

文件描述符:是内核为了高效管理已被打开的文件所创建的索引,用于指向被打开的文件,所有执行I/O操作的系统调用都通过文件描述符;文件描述符是一个简单的非负整数,用以标明每一个被进程所打开的文件,程序刚刚启动的时候,第一个打开的文件是0,第二个是1,依此类推。也可以理解为是一个文件的身份ID。
用户通过操作系统处理信息的过程中,使用的交互设备文件(键盘,鼠标,显示器)

Linux给程序提供三种 I/O 设备

  • 标准输入(STDIN) -0 默认接受来自终端窗口的输入
  • 标准输出(STDOUT)-1 默认输出到终端窗口
  • 标准错误(STDERR) -2 默认输出到终端窗口

image-20220129154834347

范例:文件描述符

[root@servera ~]# ll /dev/std*
lrwxrwxrwx. 1 root root 15 Mar 25 19:21 /dev/stderr -> /proc/self/fd/2
lrwxrwxrwx. 1 root root 15 Mar 25 19:21 /dev/stdin -> /proc/self/fd/0
lrwxrwxrwx. 1 root root 15 Mar 25 19:21 /dev/stdout -> /proc/self/fd/1

📜7.2 I/O重定向 redirect

I/O重定向:将默认的输入,输出或错误对应的设备改变,指向新的目标

📑7.2.1 标准输出和错误重新定向

STDOUT和STDERR可以被重定向到指定文件,而非默认的当前终端

格式:

命令 操作符号 文件名

支持的操作符号包括:

1> 或 >  把STDOUT重定向到文件
2> 把STDERR重定向到文件
&> 把标准输出和错误都重定向
>& 把标准输出和错误都重定向,即和上面功能一样,建议使用上面方式

以上如果文件已存在,文件内容会被覆盖

set -C 禁止将内容覆盖已有文件,但可追加, 利用 >| 仍可强制覆盖
set +C 允许覆盖,默认

范例:

[root@servera ~]# ls ~ > /tmp/ls
[root@servera ~]# cat /tmp/ls
anaconda-ks.cfg
Desktop
Documents
Downloads
initial-setup-ks.cfg
Music
passwd
Pictures
Public
set
Templates
Videos

[root@servera ~]# ls xxx > /tmp/error
ls: cannot access 'xxx': No such file or directory
[root@servera ~]# cat /tmp/error

[root@servera ~]# ls xxx 2> /tmp/error 
[root@servera ~]# cat /tmp/error 
ls: cannot access 'xxx': No such file or directory

[root@servera ~]# ls ~ xxx &> all
[root@servera ~]# cat all
ls: cannot access 'xxx': No such file or directory
/root:
all
anaconda-ks.cfg
Desktop
Documents
Downloads
initial-setup-ks.cfg
Music
passwd
Pictures
Public
set
Templates
Videos

追加

>> 可以在原有内容基础上,追加内容
把输出和错误重新定向追加到文件

>> 追加标准输出重定向至文件
2>> 追加标准错误重定向至文件

范例:

[root@servera ~]# ls /opt xxx &>> all
[root@servera ~]# cat all
ls: cannot access 'xxx': No such file or directory
/root:
all
anaconda-ks.cfg
Desktop
Documents
Downloads
initial-setup-ks.cfg
Music
passwd
Pictures
Public
set
Templates
Videos
ls: cannot access 'xxx': No such file or directory
/opt:
test

📑7.2.2 标准输入重定向

从文件中导入STDIN,代替当前终端的输入设备,使用 < 来重定向标准输入
某些命令能够接受从文件中导入的STDIN

如bc命令

范例:

[root@servera ~]# echo 2^3 > bc.log
[root@servera ~]# cat bc.log 
2^3
[root@servera ~]# bc < bc.log 
8

📑7.2.3 把多行重定向

使用 “<<终止词” 命令从键盘把多行重导向给STDIN,直到终止词位置之前的所有文本都发送给
STDIN,有时被称为就地文本(here documents)
其中终止词可以是任何一个或多个符号,比如:!,@,$,EOF(End Of File)等,其中EOF
比较常用
范例:

[root@servera ~]# cat > test << EOF
> 1
> 2
> 3
> EOF
[root@servera ~]# cat test 
1
2
3

[root@servera ~]# cat >> test << EOF
> 4
> 5
> 6
> EOF
[root@servera ~]# cat test 
1
2
3
4
5
6


📜小结

把上面的描述做个总结,如下:

类型语法格式作用
标准输出重定向>以覆盖的方式,把命令的正确输出,输出到指定的文件或者设备中
标准输出重定向>>以追加的方式,把命令的正确输出,输出到指定的文件或者设备中
标准错误输出重定向2>以覆盖的方式,把命令的错误输出,输出到指定的文件或者设备中
标准错误输出重定向2>>以追加的方式,把命令的错误输出,输出到指定的文件或者设备中

在工作中,使用得最多的形式:

类型语法格式作用
同时保存正确输出和错误输出命令 > 文件 2>&1以覆盖的方式,把正确输出和错误输出都保存到同一个文件中。
命令 >> 文件 2>&1以追加的方式,把正确输出和错误输出都保存到同一个文件中。
命令 &> 文件以覆盖的方式,把正确输出和错误输出都保存到同一个文件中。
命令 &>> 文件以追加的方式,把正确输出和错误输出都保存到同一个文件中。
命令 >> 文件1 2>> 文件2把正确的输出追加到文件1中,把错误的输出追加到文件2中

📑两个特别的操作

1>&2 把标准输出重定向到标准错误

image-20220129160132408


2>&1 把标准错误重定向到标准输出

image-20220129160202244


📑工作中启动脚本的运用

截取工作中 JAVA 程序的启动脚本片段:

start() {
cd ${SOFTHOME}
nohup java -server -Xms512m -Xmx1g -XX:+UseG1GC -verbose:gc -Xloggc:${GCLOG} -XX:+PrintGCDateStamps -XX:+PrintGCDetails -XX:+UseGCLogFileRotation -XX:NumberOfGCLogFiles=10 -XX:GCLogFileSize=100M -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=${DUMPPATH} -jar ${SERVICE} --spring.config.location=${CONFIGFILE} >> ${NOHUP} 2>&1 &
}

将输出定义到指定的变量 ${NOHUP} 中。


📜7.3 管道

📑7.3.1 管道

管道(使用符号“|”表示)用来连接多个命令
格式:

命令1 | 命令2 | 命令3 | …

image-20220129173044945

功能说明:

  • 将命令1的STDOUT发送给命令2的STDIN,命令2的STDOUT发送到命令3的STDIN
  • 所有命令会在当前shell进程的子shell进程中执行
  • 组合多种工具的功能
[root@servera ~]# echo 2^3 | bc
8

ifconfig | grep ens160 -A 1 | tail -n 1 | tr -s " " | cut -d" " -f3

注意:

1、管道命令只处理前一个命令正确输出,不处理错误输出

2、管道右边的命令,必须能够接收标准输入的数据流命令才行

3、管道符可以把两条命令连起来,它可以链接多个命令使用


📑7.3.2 tee

利用 tee 命令可以重定向到多个目标,经常配合管道符一起使用
格式

命令1 | tee [-a ] 文件名 | 命令2 ......

以上可以把命令1的STDOUT保存在文件中,做为命令2的输入
选项:

-a, --append		内容追加到给定的文件而非覆盖
	--help  在线帮助

tee指令会从标准输入设备读取数据,将其内容输出到标准输出设备,同时保存成文件

image-20220129173330187

功能:

  • 保存不同阶段的输出
  • 复杂管道的故障排除
  • 同时查看和记录输出
[root@servera ~]# echo 2+3 | tee -a bc.log | bc
5

[root@servera ~]# cat << EOF | tee test1
> 2
> 3
> 4
> 5
> EOF
2
3
4
5
[root@servera ~]# cat test1
2
3
4
5

💡总结

  • 介绍标准输入和输出的概念。
  • 介绍 I/O 重定向的运用。
  • 介绍管道的运用。

RHCSA认证作为基础认证,涉及的基础内容需要大家好好进行学习并巩固。有良好的基础才能更上一层楼。
好好加油,可以噶🤪。

以上就是【金鱼哥】对 第七章 重定向及管道 的简述和讲解。希望能对看到此文章的小伙伴有所帮助。

💾红帽认证专栏系列:
RHCSA专栏:戏说 RHCSA 认证
RHCE专栏:戏说 RHCE 认证
此文章收录在RHCA专栏:RHCA 回忆录

如果这篇【文章】有帮助到你,希望可以给【金鱼哥】点个赞👍,创作不易,相比官方的陈述,我更喜欢用【通俗易懂】的文笔去讲解每一个知识点。

如果有对【运维技术】感兴趣,也欢迎关注❤️❤️❤️ 【金鱼哥】❤️❤️❤️,我将会给你带来巨大的【收获与惊喜】💕💕!

<think>首先,我需要理解用户的问题。用户要求解释如何在C语言或Linux系统编程中将printf输出重定向管道。参考提供的引用内容,特别是引用[1]中提到的open-close-open方法,但用户的问题是关于printf输出重定向管道,而不是输入重定向。 引用[1]中有一个示例程序(demo1.c),它展示了如何使用open-close-open方法将标准输入重定向到文件。但用户的问题是关于printf输出重定向管道。因此,我需要专注于输出重定向。 用户意图是了解如何将printf的输出重定向管道,而不是输入重定向。引用[1]中的demo1.c展示了输入重定向,但用户需要输出重定向。 在Linux系统编程中,重定向标准输出到管道通常涉及创建管道,然后使用dup2函数将标准输出(文件描述符1)重定向管道的写端。以下是步骤: 1. **创建管道**:使用`pipe`系统调用创建一个管道管道用于进程间通信,有两个文件描述符:`fd[0]`用于读,`fd[1]`用于写。 2. **重定向标准输出**: - 在父进程中,关闭管道的读端`fd[0]`,保留写端`fd[1]`。 - 在子进程中,关闭管道的写端`fd[1]`,保留读端`fd[0]`。 - 然后,子进程可以使用`printf`写入管道,而父进程可以从管道读取。 引用[1]中的demo1.c展示了如何重定向标准输入到文件,但用户需要输出重定向,因此我们需要调整代码,将标准输出重定向管道。 以下是修改后的代码示例,将printf的输出重定向管道: ```c #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <fcntl.h> int main() { int pipefd[2]; char buf[100]; pid_t pid; if (pipe(pipefd) == -1) { perror("pipe"); exit(EXIT_FAILURE); } pid = fork(); if (pid < 0) { perror("fork"); exit(EXIT_FAILURE); } if (pid == 0) { // 子进程 close(pipefd[0]); // 关闭读端 // 子进程写入管道 printf("Hello from child!\n"); // 关闭写端 close(pipefd[1]); exit(0); } else { // 父进程 close(pipefd[1]); // 关闭父进程的写端 // 父进程从管道读取 read(pipefd[0], buf, sizeof(buf)); printf("Parent read: %s\n", buf); close(pipefd[0]); // 关闭读端 } return 0; } ``` 在这个示例中: - 父进程创建了一个管道,然后fork出一个子进程。 - 子进程关闭了管道的读端(`pipefd[0]`),只保留写端(`pipefd[1]`),然后使用`printf`写入。 - 父进程关闭了写端,只保留读端,然后使用`read`读取子进程写入的数据。 但是,用户要求的是将printf的输出重定向管道,而不是fork。因此,另一种方法是使用`popen`函数,它允许运行一个命令并捕获其输出作为文件流。 引用[2]中提到了`popen`函数,它用于创建一个管道,执行一个命令,并返回一个文件流。`popen`函数可以用于读取命令的输出(使用"r"模式)或写入命令的输入(使用"w"模式)。 以下是一个使用`popen`将printf输出重定向管道的例子: ```c #include <stdio.h> #include <stdlib.h> int main() { FILE *fp; char buffer[128]; // 使用popen运行命令"ls",并读取其输出 fp = popen("ls", "r"); if (fp == NULL) { perror("popen"); exit(EXIT_FAILURE); } // 读取命令输出并打印 while (fgets(buffer, sizeof(buffer), fp) != NULL) { printf("%s", buffer); } // 关闭管道 pclose(fp); return 0; } ``` 在这个示例中: - `popen("ls", "r")`打开一个管道,执行`ls`命令,并返回一个文件流,用于读取命令的输出。 - 然后使用`fgets`读取命令的输出并打印。 - 最后使用`pclose`关闭管道。 因此,用户可以通过使用`popen`函数将printf的输出重定向管道,而不是使用fork。这更符合用户的需求。 总结: 1. 使用`popen`函数打开一个管道,执行命令,并返回一个文件流。 2. 使用`fprintf`或`fwrite`向该文件流写入数据,这些数据将通过管道发送到命令。 3. 使用`pclose`关闭管道。 这样,printf的输出将被重定向管道,而不是标准输出。</think>在C语言Linux系统编程中,将`printf`的输出重定向管道涉及标准输出的重定向操作。这通常通过以下两种方式实现: ### 一、使用文件描述符重定向(低级I/O) 1. **创建管道**:使用`pipe`系统调用创建管道 ```c #include <unistd.h> #include <fcntl.h> int pipefd[2]; if (pipe(pipefd) == -1) { perror("pipe error"); exit(EXIT_FAILURE); } ``` 2. **重定向标准输出**:使用`dup2`系统调用将标准输出文件描述符(STDOUT_FILENO)重定向管道的写端(pipefd[1]) ```c close(STDOUT_FILENO); // 关闭标准输出 dup2(pipefd[1], STDOUT_FILENO); // 复制管道写端到标准输出 close(pipefd[1]); // 关闭管道写端(保留标准输出) ``` 3. **输出到管道**:此时`printf`会直接写入管道 ```c printf("This message is sent to pipe\n"); // 输出到管道 ``` ### 二、使用标准I/O库函数重定向(高级I/O) 1. **使用`popen`函数**:直接创建命令管道并返回文件流 ```c #include <stdio.h> #include <stdlib.h> FILE *fp = popen("ls", "r"); // 创建读取管道 if (fp != NULL) { char buffer[128]; while (fgets(buffer, sizeof(buffer), fp) != NULL) { printf("%s", buffer); // 输出到管道 } pclose(fp); // 关闭管道 } ``` ### 关键原理说明 1. **管道本质**:管道是内核维护的环形队列,文件描述符`fd[0]`用于读,`fd[1]`用于写[^3] 2. **重定向操作**:通过`dup2`实现文件描述符的复制重定向 3. **数据流方向**:`printf`重定向后数据流向管道写端(写缓冲区)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

IT民工金鱼哥

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值