C:如何解析 "|"

标签 c shell unix

嘿,所以我利用暑假学习unix和c。我想通过实现管道来扩展我当前的程序。如何修改我的代码以便它解析“|”。我将使用 execvp 来运行命令。在 shell 中,如果我输入 cat file | tr a A 我想拆分 cattr 以便它执行两者 这是我当前的代码

numBytes = read(0, buffer, INPUT_BUFFER_SIZE);
char *token;
inputBuffer[numBytes] = '\0';

token = strtok(buffer, " \n");

int i = 0;
while(token != NULL){
  userInput[i] = token;
  token = strtok(NULL, " \n");
  ++i;
}
userInput[i] = 0;

最佳答案

您可以使用我们的程序pipeline.c这向您展示了如何实现管道。您分割了一个管道 who | awk '{print $1}' |排序| uniq-c| sort -n 并使用数组来执行管道:

static char *cmd0[] = {"who", 0};
static char *cmd1[] = {"awk", "{print $1}", 0};
static char *cmd2[] = {"sort", 0};
static char *cmd3[] = {"uniq", "-c", 0};
static char *cmd4[] = {"sort", "-n", 0};

当您将命令拆分为如上所述的数组时,您可以使用如下代码。

#define _XOPEN_SOURCE 500

/*
 * pipeline.c
 * One way to create a pipeline of N processes using execvp
 * written 2015 by: Jonathan Leffler
 * test, packaging and maintenance by Niklas Rosencrantz nik@kth.se
 * /

#ifndef STDERR_H_INCLUDED
#define STDERR_H_INCLU, DED
#endif /* STDERR_H_INCLUDED */

/* pipeline.c */
#include <assert.h>
#include <stdio.h>
#include <sys/wait.h>
#include <unistd.h>
#include <stdlib.h>
#include <memory.h>
#include <errno.h>

typedef int Pipe[2];
/* exec_nth_command() and exec_pipe_command() are mutually recursive */
static void exec_pipe_command(int ncmds, char ***cmds, Pipe output);
static void err_vsyswarn(char const *fmt, va_list args)
{
    int errnum = errno;
    //fprintf(stderr, "%s:%d: ", arg0, (int)getpid());
    vfprintf(stderr, fmt, args);
    if (errnum != 0)
        fprintf(stderr, " (%d: %s)", errnum, strerror(errnum));
    putc('\n', stderr);
}

static void err_syswarn(char const *fmt, ...)  {
    va_list args;
//    va_start(args, fmt);
    err_vsyswarn(fmt, args);
  //  va_end(args);
}

static void err_sysexit(char const *fmt, ...)
{
    va_list args;
    //va_start(args, fmt);
    err_vsyswarn(fmt, args);
    //va_end(args);
    exit(1);
}

/* With the standard output plumbing sorted, execute Nth command */
static void exec_nth_command(int ncmds, char ***cmds) {
    assert(ncmds >= 1);
    if (ncmds > 1) {
        pid_t pid;
        Pipe input;
        if (pipe(input) != 0)
            err_sysexit("Failed to create pipe");
        if ((pid = fork()) < 0)
            err_sysexit("Failed to fork");
        if (pid == 0) {
            /* Child */
            exec_pipe_command(ncmds - 1, cmds, input);
        }
        /* Fix standard input to read end of pipe */
        dup2(input[0], 0);
        close(input[0]);
        close(input[1]);
    }
    execvp(cmds[ncmds - 1][0], cmds[ncmds - 1]);
    err_sysexit("Failed to exec %s", cmds[ncmds - 1][0]);
    /*NOTREACHED*/
}
/* exec_nth_command() and exec_pipe_command() are mutually recursive */
/* Given pipe, plumb it to standard output, then execute Nth command */
static void exec_pipe_command(int ncmds, char ***cmds, Pipe output) {
    assert(ncmds >= 1);
    /* Fix stdout to write end of pipe */
    dup2(output[1], 1);
    close(output[0]);
    close(output[1]);
    exec_nth_command(ncmds, cmds);
}

/* Execute the N commands in the pipeline */
static void exec_pipeline(int ncmds, char ***cmds) {
    assert(ncmds >= 1);
    pid_t pid;
    if ((pid = fork()) < 0)
        err_syswarn("Failed to fork");
    if (pid != 0)
        return;
    exec_nth_command(ncmds, cmds);
}

static void exec_arguments(int argc, char **argv)
{
    /* Split the command line into sequences of arguments */
    /* Break at pipe symbols as arguments on their own */
    char **cmdv[argc/2];            // Way too many
    char  *args[argc+1];
    int cmdn = 0;
    int argn = 0;

    cmdv[cmdn++] = &args[argn];
    for (int i = 1; i < argc; i++)
    {
        char *arg = argv[i];
        if (strcmp(arg, "|") == 0)
        {
            if (i == 1)
                err_sysexit("Syntax error: pipe before any command");
            if (args[argn-1] == 0)
                err_sysexit("Syntax error: two pipes with no command between");
            arg = 0;
        }
        args[argn++] = arg;
        if (arg == 0)
            cmdv[cmdn++] = &args[argn];
    }
    if (args[argn-1] == 0)
        err_sysexit("Syntax error: pipe with no command following");
    args[argn] = 0;
    exec_pipeline(cmdn, cmdv);
}
/*  who | awk '{print $1}' | sort | uniq -c | sort -n */
static char *cmd0[] = {"who", 0};
static char *cmd1[] = {"awk", "{print $1}", 0};
static char *cmd2[] = {"sort", 0};
static char *cmd3[] = {"uniq", "-c", 0};
static char *cmd4[] = {"sort", "-n", 0};

static char **cmds[] = {cmd0, cmd1, cmd2, cmd3, cmd4};
static int ncmds = sizeof(cmds) / sizeof(cmds[0]);

int main(int argc, char **argv) {
    /* The most basic example */
    char *execArgs[] = { "ls", "-al", 0 };
    execvp("ls", execArgs);

    if (argc == 1) {
        /* Run the built in pipe-line */
        exec_pipeline(ncmds, cmds);
    } else {
        /* Run command line specified by user */
        exec_arguments(argc, argv);
    }
    return(0);
}

关于C:如何解析 "|",我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38020666/

相关文章:

c - 有没有办法通过epoll机制等待alsa事件?

有人能告诉我哪里出了问题吗?我该如何替换 C 中的字符串?

linux - 从两个文本文件(平行语料库)中一致地随机采样 N 行

linux - 如何通过shell脚本调用COBOL程序

linux - unix中sh和sh -c的区别

c - 在C中的多个源文件中包含头文件

c - 行列式程序无法正常工作

linux - Shell 的交错脚本

linux - 为什么这个 bash 代码不起作用?

linux - 理解 if 中大括号和圆括号的使用