【问题标题】:Call Unix external commands with arguments使用参数调用 Unix 外部命令
【发布时间】:2016-09-02 19:55:08
【问题描述】:

我找到了一种不带参数调用 unix 外部命令的方法(例如“ls”、“pwd”)。是这样的:

//Child process
char cwd[1024];
getcwd(cwd, sizeof(cwd));
char *argv[] = {*args, NULL}//(ex.) {"ls", NULL}
char *env[] = {cwd, NULL};
//concat():method that connects 2 strings
char *command_source = concat("/bin/", *args);
execve(command_source, argv, env);
return 0;

我正在尝试转换此代码以接受带有“ls -l”等参数的外部命令

【问题讨论】:

  • Zapping 整个环境并用当前目录名替换它会使一些程序不愉快。这不是你做的方式——不管你想做什么。
  • 一个典型的命令在内存中是这样的:static char *cmd1[] = {"awk", "{print $1}", 0}; 注意引号被去掉了,结尾是 0。

标签: c shell unix exec execve


【解决方案1】:

假设您知道args 中的参数数量并且它是argcs

...
char **argv = calloc(sizeof(char*), argcs+1); 
for (int i=0; i<argcs; i++) 
    argv[i]=args[i]; 
argv[argcs]=NULL; 
...

如果不是,您可以通过遍历数组搜索结尾 NULL 轻松确定 argcs

【讨论】:

    【解决方案2】:

    你也可以做一个管道;看看命令是如何构建的,看看结构,它们是以 0 结尾的数组,引号被去掉了:

    /*  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};*/
    

    当您创建带参数的管道时,这里有一些实用函数。它们经过了良好的测试并且没有错误。

    pipeline.c

    #define _XOPEN_SOURCE 500
    /* One way to create a pipeline of N processes */
    
    #ifndef STDERR_H_INCLUDED
    #define STDERR_H_INCLUDED
    
    static void err_sysexit(char const *fmt, ...);
    
    static void err_syswarn(char const *fmt, ...);
    
    #endif /* STDERR_H_INCLUDED */
    
    /* pipeline.c */
    #include <assert.h>
    #include <stdio.h>
    #include <string.h>
    #include <sys/wait.h>
    #include <unistd.h>
    #include <stdlib.h>
    #include "openshell.h"
    #include <errno.h>
    
    /* exec_nth_command() and exec_pipe_command() are mutually recursive */
    static void exec_pipe_command(int ncmds, char ***cmds, Pipe output);
    
    /* 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*/
    }
    
    /* 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);
    }
    
    
    /*  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]);*/
    
    /* Execute the N commands in the pipeline */
    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);
    }
    
    #include <stdarg.h>
    
    static const char *arg0 = "<undefined>";
    
    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);
    }
    

    代码来自先前问题中的先前 shell 项目,在该问题中,上述代码获得了赏金。已经有一个详细的答案 - How to fix these errors in my code。还有 C minishell: adding pipelines 的较早答案,其中包含大部分引用的代码。

    您也可以阅读pipe(2)pipe(7)Advanced Linux Programming

    【讨论】:

    • 那是很好的代码——你从哪里得到它,你会在应得的地方给予信任吗?有什么理由不应该让plagiarism被遗忘吗?
    • 哪些网站?你应该赞扬那些——就像那些网站应该赞扬 SO,因为那是代码首先发布的地方。
    • @JonathanLeffler 我敢肯定,我早先为您提供了此代码的赏金,您在聊天站点中帮助了我并教了我。
    • 好的;谢谢。但是 SO 的要求之一是对不属于您的代码给予信用。你可以简单地包含一个问题的链接(我什至已经为你完成了作业——它在我第一条评论的“抄袭”链接中),并简要说明它的来源。那就足够了。像您最初那样简单地引用它不符合(我理解的)关于归因的 SO 指南。
    • 经过修正,我现在可以接受这个答案(截至 2016-08-02 00:02 UTC 的修订版)。
    猜你喜欢
    • 1970-01-01
    • 2014-12-09
    • 1970-01-01
    • 1970-01-01
    • 2015-08-29
    • 1970-01-01
    • 1970-01-01
    • 2019-03-23
    • 1970-01-01
    相关资源
    最近更新 更多