深入解析Linux文件重定向原理与dup2系统调用

        在Linux中,重定向(Redirection)是一种强大的功能,允许用户控制命令的输入来源(stdin)和输出目标(stdoutstderr)。通过重定向,你可以将命令的输出保存到文件、从文件读取输入,甚至将错误信息与正常输出分离处理。

目录

一、重定向的原理

1、输出重定向原理

2、追加重定向原理

3、输入重定向原理

4、标准输出流和标准错误流虽然都显示在屏幕上,但二者有什么区别呢?

1. 标准输出 (stdout) 和标准错误输出 (stderr)

2. perror("perror") 

函数原型

参数的作用

二、系统调用 dup2

功能说明

返回值

使用注意事项

应用示例


一、重定向的原理

        理解了文件描述符的概念及其分配规则后,我们就能掌握重定向的原理。通过以下三个示例,你会发现重定向的本质就是改变文件描述符所指向的struct file*对象。

1、输出重定向原理

所谓输出重定向,就是将程序原本要输出到某个文件的数据,转而输出到另一个指定文件中。

        例如,若需将原本输出到显示器(文件描述符1)的数据重定向至log.txt文件,可在打开log.txt前先关闭文件描述符1。这样后续打开log.txt时,系统会自动为其分配文件描述符1,实现输出重定向:

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int main()
{close(1);int fd = open("log.txt", O_WRONLY | O_CREAT, 0666);if (fd < 0){perror("open");return 1;}printf("hello world\n");printf("hello world\n");printf("hello world\n");printf("hello world\n");printf("hello world\n");fflush(stdout);close(fd);return 0;
}

运行结果后,我们发现显示器上并没有输出数据,对应数据输出到了log.txt文件当中:

补充说明:

    printf函数默认将数据输出到标准输出(stdout)。stdout本质上是一个指向struct FILE结构体的指针(对应下面红色方框部分),该结构体包含一个文件描述符成员变量。

        对于stdout而言,这个文件描述符的值固定为1。因此,printf实际上是将数据输出到文件描述符为1的设备。

        需要注意的是,C语言的数据并不会立即写入操作系统内存,而是先存储在C语言维护的缓冲区中。因此,在使用printf打印数据后,通常需要调用fflush函数来强制刷新缓冲区,确保数据被写入目标文件。

2、追加重定向原理

        追加重定向和输出重定向的唯一区别就是,输出重定向是覆盖式输出数据,而追加重定向是追加式输出数据。

        比如,我们希望将原本输出到"显示器文件"的数据追加写入log.txt文件,可以先关闭文件描述符1,再以追加写入模式打开log.txt。这样就能实现将数据追加到log.txt的重定向操作:

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int main()
{close(1);int fd = open("log.txt", O_WRONLY|O_APPEND|O_CREAT, 0666);if(fd < 0){perror("open");return 1;}printf("hello Linux\n");printf("hello Linux\n");printf("hello Linux\n");printf("hello Linux\n");printf("hello Linux\n");fflush(stdout);close(fd);return 0;
}

运行结果后,我们发现对应数据便追加式输出到了log.txt文件当中:

3、输入重定向原理

输入重定向就是,将我们本应该从一个文件读取数据,现在重定向为从另一个文件读取数据。

        例如,若要让原本从"键盘文件"读取数据的scanf函数改为从log.txt文件读取,可以在打开log.txt前先关闭文件描述符为0的文件(即"键盘文件")。这样后续打开log.txt时,系统会自动为其分配文件描述符0。

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int main()
{close(0);int fd = open("log.txt", O_RDONLY | O_CREAT, 0666);if (fd < 0){perror("open");return 1;}char str[40];while (scanf("%s", str) != EOF){printf("%s\n", str);}close(fd);return 0;
}

代码解析

  1. 关闭标准输入close(0) 关闭了文件描述符0(标准输入)。

  2. 打开文件open("log.txt", O_RDONLY | O_CREAT, 0666) 尝试以只读模式打开文件log.txt,如果文件不存在则创建。由于文件描述符0已被关闭,新打开的文件会占用最小的可用文件描述符,即0。

  3. 读取输入scanf("%s", str) 从文件描述符0(现在是log.txt)读取数据,直到遇到文件结束符(EOF)。

  4. 输出内容printf("%s\n", str) 将读取到的内容打印到标准输出。

scanf 按空格分隔读取:

  • 第一次读取 "hello",打印 hello

  • 第二次读取 "world",打印 world

  • 第三次读取 "hello",打印 hello

  • 第四次读取 "world",打印 world

  • ...

  • 直到遇到 "hello Linux" 时,scanf 会先读 "hello",再读 "Linux"。 

运行结果后,我们发现scanf函数将log.txt文件当中的数据都读取出来了: 

说明一下:
        scanf函数是默认从stdin读取数据的,而stdin指向的FILE结构体中存储的文件描述符是0,因此scanf实际上就是向文件描述符为0的文件读取数据。 

4、标准输出流和标准错误流虽然都显示在屏幕上,但二者有什么区别呢?

请看以下示例代码,它分别向标准输出流和标准错误流打印了两行字符串:

#include <stdio.h>
int main()
{printf("hello printf\n"); //stdoutperror("perror"); //stderrfprintf(stdout, "stdout:hello fprintf\n"); //stdoutfprintf(stderr, "stderr:hello fprintf\n"); //stderrreturn 0;
}

1. 标准输出 (stdout) 和标准错误输出 (stderr)

  • stdout(标准输出):默认输出到终端(屏幕),通常用于正常程序输出。

  • stderr(标准错误输出):默认也输出到终端(屏幕),但专用于错误或警告信息,不受重定向影响

2. perror("perror") 

函数原型
void perror(const char *s);
  • 参数 s:用户提供的字符串,会作为错误消息的前缀。

  • 功能:打印当前 errno 对应的系统错误描述,格式为 s: 错误描述

  • 作用:向 stderr 输出错误信息。

  • 特点

    • perror 用于打印最近的系统错误信息(通过 errno 获取)。

    • 如果之前没有发生错误,可能输出 "perror: Success"

    • 始终输出到 stderr

参数的作用
  • 如果 s 非空,perror 会先输出 s,后跟冒号和空格,再输出系统错误信息。

  • 如果 s 是空字符串 ("") 或 NULL,则只输出系统错误信息(无前缀)。

直接运行程序,结果很显然就是在显示器上输出四行字符串:

        从表面上看,标准输出流和标准错误流似乎没有区别,都会将数据显示在屏幕上。但当我们尝试将程序运行结果重定向到log.txt文件时,就会发现不同之处:只有标准输出的两行内容被写入文件,而标准错误的两行信息仍然显示在屏幕上:

重点:

        实际上,重定向操作针对的是文件描述符1(标准输出流),并不会影响文件描述符2(标准错误流)!!!!!!


二、系统调用 dup2

        实现重定向只需复制fd_array数组中的元素。比如,当我们将fd_array[3]的内容复制到fd_array[1]时,由于C语言中stdout对应文件描述符1,这样输出就被重定向到了log.txt文件。

        在Linux操作系统中提供了系统接口dup2,我们日常开发常常使用dup2系统调用来复制文件描述符,完成重定向。dup2的函数原型如下: 

int dup2(int oldfd, int newfd);

功能说明

        dup2函数将fd_array[oldfd]的内容复制到fd_array[newfd]中。若newfd文件描述符已打开,函数会先将其关闭。

返回值

        成功时返回newfd,失败时返回-1。

使用注意事项

  1. 当oldfd为无效文件描述符时,调用失败且不会关闭newfd对应的文件
  2. 若oldfd有效且newfd等于oldfd,函数直接返回newfd而不执行任何操作

应用示例

        将log.txt的文件描述符fd和标准输出描述符1传入dup2后,fd_array[fd]内容会复制到fd_array[1]。由于标准输出(stdout)对应文件描述符1,原本输出到显示器的内容将被重定向至log.txt文件:

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
int main()
{int fd = open("log.txt", O_WRONLY | O_CREAT, 0666);if (fd < 0){perror("open");return 1;}close(1);dup2(fd, 1);printf("hello printf\n");fprintf(stdout, "hello fprintf\n");return 0;
}

代码运行后,我们即可发现数据被输出到了log.txt文件当中:

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/pingmian/89537.shtml
繁体地址,请注明出处:http://hk.pswp.cn/pingmian/89537.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

QGIS制作的仪表盘工程

在QGIS的官方资源库下载了一个QGIS制作的仪表盘工程&#xff0c;感觉非常炫酷&#xff01;分享给大家&#xff01;下面的仪表盘会将选中的道路数及长度&#xff0c;动态显示在相应的仪表项中&#xff01;下面的仪表盘会将选中的道路数及长度&#xff0c;动态显示在相应的仪表项…

Python高级数据类型:集合(Set)

集合是Python中一种非常有用的数据结构&#xff0c;它与列表类似但具有独特的特性。本文将全面介绍集合的所有知识点&#xff0c;从基础概念到高级用法&#xff0c;帮助初学者彻底掌握集合的使用。1. 集合简介1.1 什么是集合&#xff1f;集合&#xff08;Set&#xff09;是Pyth…

【Unity编辑器开发GUI.Window】

Unity GUI.Window 笔记 根据官方文档2021版本的&#xff0c;点击链接跳转记录 概述 GUI.Window 是 Unity IMGUI 系统中用于创建弹出窗口的核心方法&#xff0c;具有以下关键特性&#xff1a; 浮动窗口&#xff1a;浮于普通 GUI 控件之上焦点控制&#xff1a;可通过点击获得焦…

CAN通信驱动开发注意事项

以下是CAN通信驱动开发的关键注意事项相关的整理,涵盖硬件配置、协议实现、错误处理及性能优化等方面: 一、硬件层配置要点 引脚复用与时钟 确认MCU的CAN控制器引脚是否与GPIO复用,正确配置复用模式。 检查CAN控制器时钟源,确保波特率计算基准准确。 收发器(Transceiver)…

CCF编程能力等级认证GESP—C++8级—20250628

CCF编程能力等级认证GESP—C8级—20250628单选题&#xff08;每题 2 分&#xff0c;共 30 分&#xff09;判断题&#xff08;每题 2 分&#xff0c;共 20 分&#xff09;编程题 (每题 25 分&#xff0c;共 50 分)树上旅行遍历计数单选题&#xff08;每题 2 分&#xff0c;共 30…

135. Java 泛型 - 无界通配符

文章目录135. Java 泛型 - 无界通配符 (?)**1. 什么是无界通配符 (?)&#xff1f;****2. 为什么使用无界通配符&#xff1f;****3. 示例&#xff1a;使用 ? 处理任意列表****❌ 错误示例****✅ 正确示例****4. 为什么 List<Object> 和 List<?> 不一样&#xff…

NOIP提高组|2010T1机器翻译

NOIP2010年提高组第一题:机器翻译 题目描述 小晨的电脑上安装了一个机器翻译软件,他经常用这个软件来翻译英语文章。 这个翻译软件的原理很简单,它只是从头到尾,依次将每个英文单词用对应的中文含义来替换。对于每个英文单词,软件会先在内存中查找这个单词的中文含义,如果…

Change Data Capture (CDC) with Kafka Connect:实时数据同步的完整指南

Change Data Capture (CDC) 是一种高效的数据同步技术&#xff0c;能够捕获数据库的变更&#xff08;插入、更新、删除&#xff09;并实时传输到其他系统。结合 Kafka Connect&#xff0c;我们可以构建一个可靠、可扩展的 CDC 管道&#xff0c;实现数据库与数据湖、数据仓库或消…

云手机网络加速全攻略:解决游戏卡顿与APP连接失败困扰

用云手机玩游戏、挂脚本、跑自动任务&#xff0c;明明后台显示在线&#xff0c;但画面卡顿、操作延迟、甚至APP直接“转圈圈连不上”&#xff0c;是不是很抓狂&#xff1f;问题出在哪里&#xff1f;云手机不卡&#xff0c;网络卡&#xff1f;其实&#xff0c;大多数云手机的性能…

从“数字土著”到“数据公民”:K-12数据伦理课程的设计、实施与成效追踪研究

一、引言 1.1 研究背景与意义 在当今数字时代&#xff0c;信息技术以前所未有的速度渗透到社会的各个领域&#xff0c;深刻地改变了人们的生活、工作和学习方式。K-12 教育作为基础教育的关键阶段&#xff0c;也在数字化浪潮的推动下发生着巨大的变革。随着大数据、人工智能…

LVS详解

LVS(Linux virtual server)简介即linux虚拟服务器四层负载均衡基本上都会使用 LVS&#xff0c;据了解 BAT 等大厂都是 LVS 重度使用者&#xff0c;就是因为 LVS 非常出色的性能&#xff0c;能为公司节省巨大的成本。LVS&#xff0c;全称 Linux Virtual Server 是由国人章文嵩博…

Linux内核设计与实现 - 第5章 系统调用

目录一、系统调用概述二、系统调用实现机制四、性能优化技术五、常见问题排查六、安全注意事项一、系统调用概述 定义 用户空间访问内核功能的唯一合法入口提供硬件抽象接口&#xff0c;保证系统稳定和安全 与API区别 特性系统调用API执行层级内核态用户态实现方式软中断(int …

纸板制造糊机操作

糊机操作技巧:开机流程&#xff1a;首先&#xff0c;一切的一切&#xff0c;要看懂生管&#xff0c;我们要用哪个楞别&#xff0c;再看哪个门幅和材质。 也就是说&#xff0c;一切的一切&#xff0c;要生产了&#xff0c;原纸不能用错了吧&#xff01; 第一步&#xff1a; 压压…

WPF 多窗口分文件实现方案

WPF 多窗口分文件实现方案 项目文件结构 WindowSwitcher/ ├── App.xaml ├── App.xaml.cs ├── MainWindow.xaml ├── MainWindow.xaml.cs ├── Views/ │ ├── SettingsWindow.xaml │ ├── SettingsWindow.xaml.cs │ ├── DataWindow.xaml │ ├─…

在服务器(ECS)部署 MySQL 操作流程

在部署 MySQL 数据库之前需要准备好服务器环境。可以通过以下两种方式来准备部署服务器&#xff1a;云服务器&#xff08;ECS&#xff09;&#xff0c;如&#xff1a;阿里云、华为云、腾讯云等。IDC服务器。 现以阿里云服务器&#xff08;ECS&#xff09;Windows版本来进行部署…

Java File 类详解:从基础操作到实战应用,掌握文件与目录处理全貌

作为一名 Java 开发工程师&#xff0c;你一定在实际开发中遇到过需要操作文件或目录的场景&#xff0c;例如&#xff1a;读写配置文件、上传下载、日志处理、文件遍历、路径管理等。Java 提供了 java.io.File 类来帮助开发者完成这些任务。本文将带你全面掌握&#xff1a;File …

嵌入式学习-PyTorch(9)-day25

进入尾声&#xff0c;一个完整的模型训练 &#xff0c;点亮的第一个led#自己注释版 import torch import torchvision.datasets from torch import nn from torch.utils.tensorboard import SummaryWriter import time # from model import * from torch.utils.data import Dat…

用AI做带货视频评论分析进阶提分【Datawhale AI 夏令营】

文章目录回顾赛题优化1️⃣优化2️⃣回顾赛题 模块内容类型说明/示例赛题背景概述参赛者需构建端到端评论分析系统&#xff0c;实现商品识别、多维情感分析、评论聚类与主题提炼三大任务。商品识别输入video_desc&#xff08;视频描述&#xff09; video_tags&#xff08;标签…

Redis常见数据结构详细介绍

Redis 作为一款高性能的开源内存数据库&#xff0c;凭借其丰富多样的数据结构和出色的性能&#xff0c;在缓存、会话存储、实时分析等众多场景中得到了广泛应用。下面将详细介绍 Redis 主要的数据结构&#xff0c;包括它们的类型、具体用法和适用场景。1、字符串&#xff08;St…

HAMR硬盘高温写入的可靠性问题

热辅助磁记录(HAMR)作为突破传统磁记录密度极限的下一代存储技术,其在数据中心大规模应用的核心挑战在于可靠性保障。 扩展阅读: 下一个存储战场:HAMR技术HDD HAMR技术进入云存储市场! 漫谈HAMR硬盘的可靠性 随着存储密度向4Tbpsi迈进,传统磁记录技术遭遇"三难困境…