Вполне нормально сделать execv
после исключения имени команды и некоторых первых параметров. Например, если у вас есть такой код (вам лучше опубликовать полный и проверяемый пример), давайте предположим, что вы делаете что-то вроде этого (если вам нужен пример, поищите справочную страницу xargs(1)
, у вас есть команда, и после обработки опций и их параметров вы хотите исключить все из них и выполнить остальные, как если бы это была командная строка, например, у меня есть команда для многократного выполнения команды с задержкой на некоторое указанное время, например:
cont -t 0.1 -- df -k .
Я использую <getopts.h>
для обработки параметров моей программы cont
, затем повторно выполняю команду df -k
. Опции позволяют показать версию программы, указать время ожидания, быть подробным или количество раз выполнения команды. Я написал это только сейчас, чтобы показать вам, как это сделать (пример включает в себя fork(2)
use, execvp(2)
и перенаправление для захвата выходных данных команды, чтобы иметь возможность вернуться к источнику, когда известно число строк мы получили, программа использует экранирование ANSI, чтобы переместить курсор назад в начало.)
#include <stdlib.h>
#include <stdio.h>
#include <getopt.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#define F(_fmt) "%s:%d: " _fmt, __FILE__, __LINE__
#define FLAG_VERBOSE (1<<0)
#define FLAG_VERSION (1<<1)
#define FLAG_DELAY (1<<2)
#define FLAG_NTIMES (1<<3)
int flags = 0;
useconds_t delay = 1000000;
size_t ntimes;
void doVersion(void)
{
fprintf(stderr,
"cont: v1.0\n"
"(C) Luis Colorado. All rights reserved.\n"
"License: BSD\n");
exit(EXIT_SUCCESS);
}
ssize_t loop(int argc_unused, char **argv)
{
int fd[2];
int res = pipe(fd);
res = fork();
if (res < 0) {
fprintf(stderr,
F("fork: ERROR %d: %s\n"),
errno,
strerror(errno));
return -1;
} else if (res == 0) { /* child */
close(fd[0]); /* not going to use it */
dup2(fd[1], 1); /* redirect output to pipe */
close(fd[1]);
execvp(argv[0], argv);
fprintf(stderr,
F("execv: ERROR %d: %s\n"),
errno, strerror(errno));
return -1;
} else { /* parent */
pid_t cld_pid = res;
close(fd[1]); /* no writing to the pipe */
FILE *f = fdopen(fd[0], "rt"); /* just reading */
int c;
size_t lines = 0;
while((c = fgetc(f)) != EOF) {
if (c == '\n') lines++;
putc(c, stdout);
}
wait(NULL);
return lines;
}
} /* loop */
int main(int argc, char **argv)
{
int opt;
float t;
while ((opt = getopt(argc, argv, "t:Vvn:")) >= 0) {
switch(opt) {
case 't': flags |= FLAG_DELAY;
t = atof(optarg);
break;
case 'V': flags |= FLAG_VERSION;
break;
case 'v': flags |= FLAG_VERBOSE;
break;
case 'n': flags |= FLAG_NTIMES;
ntimes = atoi(optarg);
break;
/* ... */
}
}
if (flags & FLAG_VERSION)
doVersion();
/* the next pair of sentences is like `shift optind' in the shell. */
/* trick, don't move the parameters, just move the pointer */
argc -= optind; /* adjust the number of parameters. */
argv += optind; /* advance the pointer to the proper place */
/* NOW, argc && argv are identical to the original ones, but lacking the
* first `optind' argument strings. As the original string array ended
* in a NULL, there's no need to construct it from allocating memory.
* Anyway, we're not going to use after it's consumed in main(). */
if (flags & FLAG_VERBOSE) {
char *sep = "About to execute: ";
int i;
for (i = 0; i < argc; i++) {
fprintf(stderr, "%s%s", sep, argv[i]);
sep = " ";
}
fprintf(stderr, "\n");
}
if (flags & FLAG_DELAY) {
delay = t * 1.0E6;
}
size_t total_lines = 0;
ssize_t n = 0;
while(!(flags & FLAG_NTIMES) || ntimes--) {
/* move up as many lines as input from subcommand */
if (n) printf("\r\033[%ldA@\b", n);
n = loop(argc, argv);
if (n < 0) {
/* we have already written the error */
exit(EXIT_FAILURE);
}
usleep(delay);
total_lines += n;
}
if (flags & FLAG_VERBOSE) {
fprintf(stderr,
F("Total lines: %lu\n"),
total_lines);
}
exit(EXIT_SUCCESS);
}
Вы можете скачать полную версию этой программы с Github