【问题标题】:execvp isn't reading the entire argv[]?execvp 没有读取整个 argv[]?
【发布时间】:2016-05-16 22:06:18
【问题描述】:

我有类似基本外壳的东西。 我的问题是,当我执行类似 ./test ls -l 的操作时,它不使用 -l 参数。 这和我做 ./test ls 完全一样。 根据 man 的说法,int execvp(const char *file, char *const argv[]),所以 execvp 不应该读取整个 **argv 吗?

int mySystem(char* str[]){
    wordexp_t p;
    char **w;
    wordexp(str[1],&p,0);
    w = p.we_wordv;
    int q= fork();
    if(q==0){
        execvp(w[0],w);
        perror("erro");
        _exit(-1);
    }

    int sp;
    wordfree(&p); 
    wait(&sp);
    if(WIFEXITED(sp)){
        return WEXITSTATUS(sp);
    }
    return 0;
}

int main(int argc,char **argv){
    mySystem(argv);
    return 0;
}

谢谢。

【问题讨论】:

  • 您是否确认 argv 参数具有预期的内容?还是您只是假设您设置正确?
  • 如果我循环 p.we_wordv 参数并打印它,它只会传递 ls,就像(我认为)你指出的那样......我假设问题是 wordexp 的第一个参数(str[1])?
  • 你到底为什么叫 wordexp?
  • 这是一个小项目。我希望能够在我的终端上做一些事情,比如 ./program backup *.txt ,它将压缩该目录上的所有 .txt 文件。我已经完成了压缩部分,我尝试使用 wordexp 因为(据我所知)它会自动解释像 * 这样的命令。不知道我解释的对不对。
  • @rici 经过一些研究后,我认为应该像本页这样的 bc:gnu.org/software/libc/manual/html_node/…

标签: c fork execvp


【解决方案1】:

你的论点应该是这样的(注意后面的 0 并且没有引号)

static char *cmd[] = { "ls", "-l", 0 };

因此,您可以尝试对 exec 的调用进行硬编码,并查看它是否有效。

我无法调试您的代码,因为它不完整。如果您使用调试器,您可以检查这些值。请记住,args 必须在一个数组中才能执行。这里有一些基本的代码来完成它并解释它,并且还允许你制作一个管道。

/* One way to create a pipeline of N processes */

/* stderr.h */
#ifndef STDERR_H_INCLUDED
#define STDERR_H_INCLUDED

static void err_setarg0(const char *argv0);
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 "stderr.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);

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

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

/* Collect dead children until there are none left */
static void corpse_collector(void)
{
    pid_t parent = getpid();
    pid_t corpse;
    int   status;
    while ((corpse = waitpid(0, &status, 0)) != -1)
    {
        fprintf(stderr, "%d: child %d status 0x%.4X\n",
                (int)parent, (int)corpse, status);
    }
}

/*  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]);

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);
}
#include <stdio.h>
#include <stdarg.h>
#include <errno.h>
#include <string.h>
#include <stdlib.h>
int main(int argc, char **argv)
{

    printf("%s", argv[1]);

    err_setarg0(argv[0]);
    if (argc == 1)
    {
        /* Run the built in pipe-line */
        exec_pipeline(ncmds, cmds);
    }
    else
    {

        /* Run command line specified by user */
        char *original = "ls";
        char **pointer_to_original = &original;
        for (int i = 0; i < argc; ++i) {   printf("blarg blarg %i\n", argc);
            printf("%s", argv[i]);// = "ls";
        }
        exec_arguments(argc, argv);
    }
    corpse_collector();
    return(0);
}

/* stderr.c */
/*#include "stderr.h"*/
#include <stdio.h>
#include <stdarg.h>
#include <errno.h>
#include <string.h>
#include <stdlib.h>

static const char *arg0 = "<undefined>";

static void err_setarg0(const char *argv0)
{
    arg0 = argv0;
}

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);
}

【讨论】:

    【解决方案2】:

    您不需要wordexp 来解释命令行参数。 Shell 已经为您完成了这项工作。只需将argv + 1 传递给execvp

    您需要wordexp 的唯一原因是我将整个命令行解释为单个参数(例如`myutil“ls -l *.txt”)或从文件或类似文件中读取。但是你为什么要这么复杂呢?

    【讨论】:

      猜你喜欢
      • 2016-03-06
      • 2021-12-18
      • 2023-03-15
      • 2019-08-20
      • 1970-01-01
      • 1970-01-01
      • 2013-10-30
      • 1970-01-01
      • 2020-03-02
      相关资源
      最近更新 更多