【问题标题】:Why the "wc" command called in the following program doesn't output any message in terminal?为什么以下程序中调用的“wc”命令没有在终端输出任何消息?
【发布时间】:2019-12-22 15:01:03
【问题描述】:

我正在尝试了解管道在 Linux 中的工作原理。我编写了以下程序,编译它然后在终端中运行它。程序正常退出,没有错误,但没有打印出任何消息。有什么不对的吗?

PS:这段代码sn-p来自MIT的xv6操作系统课程。

#include <stdio.h>
#include <unistd.h>

int main() {
    int p[2];
    char *argv[2];
    argv[0] = "wc";
    argv[1] = 0;
    pipe(p);
    if (fork() == 0) {
        close(0);
        dup(p[0]);
        close(p[0]);
        close(p[1]);
        execvp("/bin/wc", argv);
    } else {
        write(p[1], "hello world\n", 12);
        close(p[0]);
        close(p[1]);
    }
}

【问题讨论】:

  • 您可能应该检查返回值,例如来自execvp。在我的 Ubuntu 机器上 command -v wc 返回 /usr/bin/wc。另见How to check if a program exists from a Bash script?
  • @jww 谢谢!我的系统在usr/bin/wc 中也有“wc”。
  • @jww,exec*() 函数不会返回任何内容,除非函数失败。所以如果它返回应该总是调用perror() 然后exit( EXIT_FAILURE );
  • fork() 失败时,发布的代码无法检查。在这种情况下,应该先调用perror(),然后再调用exit( EXIT_FAILURE );
  • @user3629249- 请参阅execvp (3) man page。我在猜测(这只是一个猜测),execvp 失败,errnoENOENT

标签: c linux operating-system


【解决方案1】:

以下建议的代码:

  1. 干净编译
  2. 执行所需的功能
  3. 传递本地文件的名称,而不是一些随机字符串并且文件名以 NUL 字节终止
  4. 您需要将传递的文件名修改为当前目录中的文件
  5. 注意传递给write() 的长度包括尾随的 NUl 字节

现在建议的代码:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

#include <sys/types.h>
#include <sys/wait.h>

int main() {
    int p[2];
    char *argv[3];
    argv[0] = "wc";
    argv[1] = "--files0-from=-";
    argv[2] = (char *) NULL;
    if( pipe(p) != 0 )
    {
        perror( "pipe failed" );
        exit( EXIT_FAILURE );
    }
    pid_t pid = fork();
    switch( pid )
    { 
        case -1:
        perror( "fork failed" );
        exit( EXIT_FAILURE );
        break;

        case 0:
        close(0);
        if( dup2(p[0], 0) != 0 )
        {
            perror( "dup2 failed" );
            exit( EXIT_FAILURE );
        }
        close(p[0]);
        close(p[1]);
        execvp("/usr/bin/wc", argv);
        perror( "execvp failed" );
        exit( EXIT_FAILURE );
        break;

        default:
        write(p[1], "untitled2.c", 12);
        close(p[0]);
        wait( NULL );
        close(p[1]);
    }
}

注意:untitled2.c 就是这个源文件。

程序运行结果:

47 101 818 untitled2.c

【讨论】:

    【解决方案2】:

    仅当 wc 的参数是实际文件时,命令 wc 才会在行数、字符数和单词数之后打印文件名:

    $ wc hello_word.txt 1 2 12 hello_word.txt

    事实上,从终端进行重定向都不会打印出消息

    $ echo "hello word" | wc 1 2 11

    如果您愿意,您可以简单地在子进程的标准输出上打印出消息,然后再写入管道

    if (fork() == 0) {
      .. 
    } else {
        printf("Message: 'hello world'\n");
        write(p[1], "hello world\n", 12);
        close(p[0]);
        close(p[1]);
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-06-08
      • 2022-12-23
      • 1970-01-01
      • 1970-01-01
      • 2011-07-09
      • 1970-01-01
      相关资源
      最近更新 更多