c - 使用 execvp() 分离和执行命令行参数
问题描述
下面的代码可以正常工作。我输入任意 2 个命令,在本例中为 ls 和 pwd,终端输出这些命令的结果,以及运行它的子进程的 PID。
命令行目前看起来像这样:./practice.c ls pwd
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main(int argc, char ** argv){
long cpid1, cpid2;
switch(cpid1 = fork()){
case -1:
perror("fork failed");
return EXIT_FAILURE;
case 0:
printf("First child, pid=%d, executing command...\n", getpid());
execvp(argv[1], NULL);
return EXIT_FAILURE;
}
wait(NULL);
switch(cpid2 = fork()){
case -1:
perror("fork failed");
return EXIT_FAILURE;
case 0:
printf("Second child, pid=%d, executing command...\n", getpid());
execvp(argv[2], NULL);
return EXIT_FAILURE;
}
while(wait(NULL) != -1);
return EXIT_SUCCESS;
}
但是,我希望用户输入一个看起来更像这样的命令行: ./practice.c pwd , ls -l
所以,首先我的问题是分离出命令行。“PWD”将是 argv[1],然后“,”将是 argv[2],然后“ls”将是 argv[3],依此类推。我真正想要的是使用逗号作为分隔符。即便如此,在“ls -l”的情况下,我希望它是 1 个 arg,所以当我运行 exec 时,它看起来就像我所做的只是运行 execvp(“ls”,“-l”,NULL)。你有什么建议或技巧吗?
解决方案
将一些评论转移到答案中。
请注意,您会有类似的东西:
char *args[3] = { "ls", "-l", NULL };
(使用从 — 推导出的值argv
,您需要args[]
根据仅包含逗号 ( ) 的参数之前或之后的参数数量来调整大小,
),然后调用execvp(args[0], args);
. 您为调用显示的符号execvp()
将适用于execlp()
,但仅当您知道编译时的参数数量时。在您修改后的要求中,您不知道编译时参数的数量,这就是您需要使用execvp()
.
您现有的代码没有为调用的程序提供任何参数。不建议这样做。同样,您应该创建一个数组并使用它:
char args[2] = { argv[1], NULL };
…
execvp(args[0], args);
当然 forargv[2]
和第二个命令也是如此。根据修改后的要求,您需要将参数累积到逗号参数,然后运行它。您可以找到逗号参数的索引并将其替换为 NULL 并从那里开始工作。
此代码将执行提取到一个函数中execute()
,让main()
函数拆分参数列表等。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
static void execute(char **args);
int main(int argc, char **argv)
{
int arg1 = 1;
for (int i = 1; i < argc; i++)
{
if (strcmp(argv[i], ",") == 0)
{
argv[i] = NULL;
execute(&argv[arg1]);
arg1 = i + 1;
}
}
if (argv[arg1] != NULL)
execute(&argv[arg1]);
return EXIT_SUCCESS;
}
static void execute(char **args)
{
pid_t pid;
if ((pid = fork()) == -1)
{
perror("fork failed");
exit(EXIT_FAILURE);
}
else if (pid == 0)
{
char **argv = args;
while (*argv)
printf("[%s]", *argv++);
putchar('\n');
printf("Child pid=%d executing command %s...\n", getpid(), args[0]);
execvp(args[0], args);
fprintf(stderr, "%d: failed to execute command %s\n", getpid(), args[0]);
exit(EXIT_FAILURE);
}
else
{
int corpse;
int status;
while ((corpse = wait(&status)) != -1)
printf("Child %d exited with status 0x%.4X\n", corpse, status);
}
}
程序源在vp13.c
;程序是vp13
。当像这样运行时,它会产生:
$ vp13 ls -l , pwd , ls -C -F , date '+%Y-%m-%dT%H:%M:%S'
[ls][-l]
Child pid=54602 executing command ls...
total 32
-rwxr-xr-x 1 jonathanleffler staff 9076 Dec 3 21:18 vp13
-rw-r--r-- 1 jonathanleffler staff 1148 Dec 3 21:18 vp13.c
drwxr-xr-x 3 jonathanleffler staff 96 Dec 3 21:15 vp13.dSYM
Child 54602 exited with status 0x0000
[pwd]
Child pid=54603 executing command pwd...
/Users/jonathanleffler/soq/so-6513-7710
Child 54603 exited with status 0x0000
[ls][-C][-F]
Child pid=54604 executing command ls...
vp13* vp13.c vp13.dSYM/
Child 54604 exited with status 0x0000
[date][+%Y-%m-%dT%H:%M:%S]
Child pid=54605 executing command date...
2020-12-03T21:23:55
Child 54605 exited with status 0x0000
$
我相信这对你来说不太灵活。
推荐阅读
- install4j - createbundle 命令行拒绝在 Windows 上生成 Mac 包
- javascript - Javascript:使用 fetch 将数据发布到 PHP
- mysql - MySQL Workbench:检查2行数据后插入行,循环整个表
- marklogic - CloudWatch 与 MarkLogic DHS 的集成
- html - 需要帮助打包脚本以放置在头部(Wordpress)
- python - 我想使用 matplotlib 在饼图聊天中绘制泰坦尼克数据集的性别(男性/女性)比例,显示男性和女性的百分比表示
- flutter - ListView 在显示键盘后调整大小
- c# - Xamarin 表单从 Firebase 获取所有值
- javascript - nodejs puppeteer无法下载URL中带有特殊字符的图像文件
- html - CSS样式实现曲线圆