Вызов внешних команд Unix с аргументами

Я нашел способ вызывать внешние команды 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».


person i_ll_be_back    schedule 07.05.2016    source источник
comment
Удаление всей среды и замена ее только текущим именем каталога может сделать некоторые программы недовольными. Это не то, как вы это делаете — что бы вы ни пытались сделать.   -  person Jonathan Leffler    schedule 08.05.2016
comment
Типичная команда в памяти выглядит следующим образом: static char *cmd1[] = {"awk", "{print $1}", 0}; Обратите внимание, что кавычки удалены, а завершающий 0.   -  person Niklas R.    schedule 08.05.2016


Ответы (2)


Предполагая, что вы знаете количество аргументов в args и что это argcs:

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

Если нет, вы можете легко определить argcs, перебирая массив в поисках конечного NULL.

person Christophe    schedule 07.05.2016

Вы также можете сделать конвейер; посмотрите, как создаются команды, и посмотрите на структуру, это массивы, которые заканчиваются на 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};*/

Вот некоторые вспомогательные функции при создании конвейера с аргументами. Они хорошо протестированы и не содержат ошибок.

конвейер.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);
}

Код исходит из предыдущего проекта оболочки из более раннего вопроса, где за указанный выше код была назначена награда. Уже есть развернутый ответ с подробностями — Как исправить эти ошибки в моем код. Также есть более ранний ответ на C minishell: добавление конвейеров, который содержит большую часть цитируемого кода.

Вы также можете прочитать pipe(2), pipe(7) и Продвинутое программирование для Linux

person Niklas R.    schedule 07.05.2016
comment
Это хороший код — откуда вы его взяли и собираетесь ли вы отдать ему должное? Есть ли причина, по которой вы не должны быть забыты за плагиат - person Jonathan Leffler; 08.05.2016
comment
Какие веб-сайты? Вы должны отдать им должное — точно так же, как эти веб-сайты должны отдать должное SO, поскольку именно там код был опубликован первым. - person Jonathan Leffler; 08.05.2016
comment
@JonathanLeffler Я уверен, что ранее дал вам награду за этот код, вы помогли мне в чате и научили меня. - person Niklas R.; 08.05.2016
comment
ХОРОШО; Благодарю. Но одно из требований SO заключается в том, что кредит предоставляется за код, который не принадлежит вам. Вы можете просто включить ссылку на вопрос (я даже сделал для вас домашнюю работу — она находится в ссылке «плагиат» в моем первом комментарии) с кратким примечанием о том, откуда он взялся. Этого будет достаточно. Простое цитирование, как вы это делали изначально, не соответствует (как я понимаю) руководящим принципам SO по атрибуции. - person Jonathan Leffler; 08.05.2016
comment
С внесенными поправками, теперь я согласен с этим ответом (редакция от 02 августа 2016 г., 00:02 UTC). - person Jonathan Leffler; 14.05.2016