Unix 管道 - 从子描述符中的 stdin 读取数据

2024-04-21

我正在尝试在 c 中实现 unix 管道(即执行 ls | wc)。我找到了我的问题的相关解决方案(C Unix 管道示例 https://stackoverflow.com/questions/4841126/c-unix-pipes-example)但是,我不确定为什么已解决的代码片段的特定部分有效。

这是代码:

/* Run WC. */
int filedes[2];
pipe(filedes);

/* Run LS. */
pid_t pid = fork();
if (pid == 0) {
    /* Set stdout to the input side of the pipe, and run 'ls'. */
    dup2(filedes[1], 1);
    char *argv[] = {"ls", NULL};
    execv("/bin/ls", argv);
 } else {
    /* Close the input side of the pipe, to prevent it staying open. */
     close(filedes[1]);
 }

 /* Run WC. */
 pid = fork();
 if (pid == 0) {
      dup2(filedes[0], 0);
      char *argv[] = {"wc", NULL};
      execv("/usr/bin/wc", argv);
  }

在执行 wc 命令的子进程中,虽然它将 stdin 附加到文件描述符,但我们似乎没有显式读取第一个子进程中 ls 产生的输出。因此,对我来说, ls 似乎是独立运行的,而 wc 是独立运行的,因为我们在执行 wc 时没有明确使用 ls 的输出。那么这段代码是如何工作的(即它执行 ls | wc)?


显示的代码几乎可以工作(它减少了一些角落,但它可以工作),因为分叉的子进程确保执行的进程将写入的文件描述符(在这种情况下)ls)并从中读取(在情况下wc) 是管道的适当末端。您无需再做任何事情;标准输入是文件描述符0,所以wc不带(文件名)参数从标准输入读取。ls始终写入标准输出,文件描述符 1,除非正在写入错误消息。

代码片段中共有三个流程;父进程和两个子进程,每个子进程一个fork()。 父进程也应该关闭管道的两端;它只关闭一个。

一般来说,当你做了一个dup() or dup2()调用管道文件描述符时,您应该关闭管道的两端。你在这里可以逃脱惩罚,因为ls生成数据并终止;你不会在所有情况下都这样做。

评论:

/* Set stdout to the input side of the pipe, and run 'ls'. */

不准确;你正在设置stdout到管道的输出侧,而不是输入侧。

您应该在执行后出现错误退出execv()来电;如果他们失败了,他们就会返回,并且这个过程可能会造成严重破坏(例如,如果ls失败,你最终会得到两个副本wc跑步。

An SSCCE http://sscce.org/

注意在每个过程中小心关闭管道的两端。一旦启动了两个子进程,父进程就不再使用管道。我留下了关闭的代码filedes[1]很早就到位(但将其从明确的else块,因为以下代码也仅在以下情况下执行:else被处决)。我很可能保留了一对closes()在需要关闭文件的三个代码路径中的每一个中。

#include <stdio.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <unistd.h>

int main(void)
{
    int filedes[2];
    int corpse;
    int status;
    pipe(filedes);

    /* Run LS. */
    pid_t pid = fork();
    if (pid == 0)
    {
        /* Set stdout to the output side of the pipe, and run 'ls'. */
        dup2(filedes[1], 1);
        close(filedes[1]);
        close(filedes[0]);
        char *argv[] = {"ls", NULL};
        execv("/bin/ls", argv);
        fprintf(stderr, "Failed to execute /bin/ls\n");
        exit(1);
    }
    /* Close the input side of the pipe, to prevent it staying open. */
    close(filedes[1]);

    /* Run WC. */
    pid = fork();
    if (pid == 0)
    {
        /* Set stdin to the input side of the pipe, and run 'wc'. */
        dup2(filedes[0], 0);
        close(filedes[0]);
        char *argv[] = {"wc", NULL};
        execv("/usr/bin/wc", argv);
        fprintf(stderr, "Failed to execute /usr/bin/wc\n");
        exit(1);
    }

    close(filedes[0]);

    while ((corpse = waitpid(-1, &status, 0)) > 0)
        printf("PID %d died 0x%.4X\n", corpse, status);
    return(0);

}

输出示例:

$ ./pipes-14312939
      32      32     389
PID 75954 died 0x0000
PID 75955 died 0x0000
$
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Unix 管道 - 从子描述符中的 stdin 读取数据 的相关文章

  • 如何检查图像对象与资源中的图像对象是否相同?

    所以我试图创建一个简单的程序 只需在单击图片框中更改图片即可 我目前只使用两张图片 所以我的图片框单击事件函数的代码 看起来像这样 private void pictureBox1 Click object sender EventArgs
  • 如何验证文件名称在 Windows 中是否有效?

    是否有一个 Windows API 函数可以将字符串值传递给该函数 该函数将返回一个指示文件名是否有效的值 我需要验证文件名是否有效 并且我正在寻找一种简单的方法来完成此操作 而无需重新发明轮子 我正在直接使用 C 但针对的是 Win32
  • 无法使用已与其底层 RCW 分离的 COM 对象。在 oledb 中

    我收到此错误 但我不知道我做错了什么 下面的代码在backrgroundworker中 将异常详细信息复制到剪贴板 System Runtime InteropServices InvalidComObjectException 未处理 通
  • 访问私人成员[关闭]

    Closed 这个问题是基于意见的 help closed questions 目前不接受答案 通过将类的私有成员转换为 void 指针 然后转换为结构来访问类的私有成员是否合适 我认为我无权修改包含我需要访问的数据成员的类 如果不道德 我
  • Qt-Qlist 检查包含自定义类

    有没有办法覆盖加载自定义类的 Qt QList 的比较机制 即在 java 中你只需要重写一个比较方法 我有一个带有我的自定义类模型的 QList QList
  • UML类图:抽象方法和属性是这样写的吗?

    当我第一次为一个小型 C 项目创建 uml 类图时 我在属性方面遇到了一些麻烦 最后我只是将属性添加为变量 lt
  • 从父类调用子类方法

    a doStuff 方法是否可以在不编辑 A 类的情况下打印 B did stuff 如果是这样 我该怎么做 class Program static void Main string args A a new A B b new B a
  • C++ 子字符串返回错误结果

    我有这个字符串 std string date 20121020 我正在做 std cout lt lt Date lt lt date lt lt n std cout lt lt Year lt lt date substr 0 4 l
  • C#:如何防止主窗体过早显示

    在我的 main 方法中 我像往常一样启动主窗体 Application EnableVisualStyles Application SetCompatibleTextRenderingDefault false Application
  • C 预处理器库

    我的任务是开发源分析工具C程序 并且我需要在分析本身之前预处理代码 我想知道什么是最好的图书馆 我需要一些重量轻 便于携带的东西 与其推出自己的 为什么不使用cpp这是的一部分gcc suite http gcc gnu org onlin
  • 指针减法混乱

    当我们从另一个指针中减去一个指针时 差值不等于它们相距多少字节 而是等于它们相距多少个整数 如果指向整数 为什么这样 这个想法是你指向内存块 06 07 08 09 10 11 mem 18 24 17 53 7 14 data 如果你有i
  • 如何返回 json 结果并将 unicode 字符转义为 \u1234

    我正在实现一个返回 json 结果的方法 例如 public JsonResult MethodName Guid key var result ApiHelper GetData key Data is stored in db as v
  • Qt表格小部件,删除行的按钮

    我有一个 QTableWidget 对于所有行 我将一列的 setCellWidget 设置为按钮 我想将此按钮连接到删除该行的函数 我尝试了这段代码 它不起作用 因为如果我只是单击按钮 我不会将当前行设置为按钮的行 ui gt table
  • clang 实例化后静态成员初始化

    这样的代码可以用 GCC 编译 但 clang 3 5 失败 include
  • 从库中捕获主线程 SynchronizationContext 或 Dispatcher

    我有一个 C 库 希望能够将工作发送 发布到 主 ui 线程 如果存在 该库可供以下人员使用 一个winforms应用程序 本机应用程序 带 UI 控制台应用程序 没有 UI 在库中 我想在初始化期间捕获一些东西 Synchronizati
  • 需要哪个版本的 Visual C++ 运行时库?

    microsoft 的最新 vcredist 2010 版 是否包含以前的版本 2008 SP1 和 2005 SP1 还是我需要安装全部 3 个版本 谢谢 你需要所有这些
  • 32 位到 64 位内联汇编移植

    我有一段 C 代码 在 GNU Linux 环境下用 g 编译 它加载一个函数指针 它如何执行并不重要 使用一些内联汇编将一些参数推送到堆栈上 然后调用该函数 代码如下 unsigned long stack 1 23 33 43 save
  • Validation.ErrorTemplate 的 Wpf 动态资源查找

    在我的 App xaml 中 我定义了一个资源Validation ErrorTemplate 这取决于动态BorderBrush资源 我打算定义独特的BorderBrush在我拥有的每个窗口以及窗口内的不同块内
  • x86 上未对齐的指针

    有人可以提供一个示例 将指针从一种类型转换为另一种类型由于未对齐而失败吗 在评论中这个答案 https stackoverflow com questions 544928 reading integer size bytes from a
  • 限制C#中的并行线程数

    我正在编写一个 C 程序来生成并通过 FTP 上传 50 万个文件 我想并行处理4个文件 因为机器有4个核心 文件生成需要更长的时间 是否可以将以下 Powershell 示例转换为 C 或者是否有更好的框架 例如 C 中的 Actor 框

随机推荐