使用自己的“命令行参数”编写C命令提示符程序

时间:2015-09-11 17:57:53

标签: c command-line-arguments command-prompt

在此被困了好几个小时。如何在命令提示程序中读取命令行参数并使用execv()系统调用执行它?以下是YWIMC为提示的示例输出。

YWIMC > R /bin/ls
a.out ex2.c ...... //output from the “ls” command
YWIMC > R /bin/ls –l //same as executing “ls –l”
total 144
-rwx------ 1 sooyj compsc 8548 Aug 13 12:06 a.out
-rwx------ 1 sooyj compsc 6388 Aug 13 11:36 alarmClock
.................... //other files not shown

R命令的语法为R command_path [arg1到arg4],它们可以是0到4个参数。例如。 R / bin / ls OR R / bin / ls -l <​​/ p>

我应该使用execv(我假设它更好用于读取命令行参数,因为它使用char数组作为参数,而且我的作业分配也需要我)但是我在阅读参数时遇到了麻烦英寸

当有任何数量的参数(0到4)时,我该怎么做? 在阅读参数时,如何让程序认识到这是我给出的所有参数的结束? (我有一个问题,我会添加无数个参数,即使我将max设置为4.)以下是我现有的代码,只是我必须将execl更改为execv

else    {
            result = fork();
            if(result != 0) {   //Parent Code
                childID = wait(&status);
            }
            else    {   //Child Code
                if(strcmp(filePath, "/bin/ls") == 0)    { //specific /bin/ls command
                    execl("/bin/ls", "ls", NULL);
                }
                else    {   //run other programs
                    execl(filePath, NULL);
                }
                return 256;
            }

3 个答案:

答案 0 :(得分:0)

您可以使用malloc创建字符串数组。在读入参数时,使用realloc来增加数组的大小。然后,您可以将结果数组传递给execv

int arglen = 1;
char **args = malloc(arglen * sizeof(char *));
args[0] = strdup(/* program to run */);
while (/* more args to read */) {
    arglen++;
    args = realloc(args, arglen * sizeof(char *));
    args[arglen-1] = strdup(/* next arg */);
}
arglen++;
args = realloc(args, arglen * sizeof(char *));
args[arglen] = NULL;
...
execv(/* prog to call */, args);        

答案 1 :(得分:0)

  我想到的想法是读取文件/文件路径,接受所有   参数,使用execv(program,args)。

你走在正确的轨道上。练习不仅关注execv的使用,而且还巧妙地关注命令行参数索引,你必须注意命令行上给出的第一个参数的事实和索引为1 (例如argv[1]),而需要保存参数以传递给execv的数组将从索引0开始。

处理索引偏移量并不困难,您只需要注意如何填充要发送到execv的数组。 注意:变量初始化非常重要。您发送给args的{​​{1}}数组必须将最终指针设为execv,以充当NULL的标记,以了解停止处理参数的位置。确保您在数组末尾提供execv指针的一种方法是将所有指针初始化为NULL以开头:

NULL

然后你唯一的任务就是确保只填充数组中的前4个指针,留下最后一个char *args[5] = {NULL}; 。同样注意NULL中的第一个指针必须包含正在执行的程序的完整路径。除非您将正确的路径附加到args的开头(例如R ls),否则上面显示ls的原始示例将无效。你如何做到这一点取决于你。有一个简短的例子是:

/usr/bin/ls

<强>编译

#include <stdio.h>
#include <unistd.h>

int main (int argc, char **argv) {

    char *args[5] = {NULL};        /* all pointers initialized to NULL */
    int lim = argc < 5 ? argc : 5; /* limit the number of args to read */
    int nargs = lim - 1;           /* adjust the index to fill args    */
    int i;

    /* read the arguments from the command line */
    for (i = 1; i < lim; i++)
        args[i-1] = argv[i];

    /* output the arguments read */
    for (i = 0; i < nargs; i++)
        printf (" args[%d] = %s\n", i, args[i]);

    /* call execv (NOTE: you must provide a full-path
       to the program being executed, e.g. /usr/bin/ls) 
    */
    if (execv (args[0], args) == -1)
        fprintf (stderr, "error: execv failed - path correct?.\n");

    return 0;
}

使用/输出

$ gcc -Wall -Wextra -o bin/execvargs execvargs.c

再看一下execv

如果您想查看$ ./bin/execvargs /usr/bin/ls args[0] = /usr/bin/ls 3darrayaddr.c getline_minimal.c reallocptr.c BoggleData.txt getline_rdfile.c rec_char_in_str.c <snip> $ ./bin/execvargs /usr/bin/ls -l args[0] = /usr/bin/ls args[1] = -l total 7528 -rw-r--r-- 1 david david 376 Sep 23 2014 3darrayaddr.c -rw-r--r-- 1 david david 192 Jun 27 01:11 BoggleData.txt -rw-r--r-- 1 david david 3565 Jun 26 2014 DoubleLinkedList-old.c <snip> $ ./bin/execvargs my dog has fleas and so does the cat args[0] = my args[1] = dog args[2] = has args[3] = fleas error: execv failed - path correct?. 如何调用您作为execv传递的程序,您可以在shell中创建一个小测试脚本,它将回显{{1}调用时收到的参数}。简单的事情很好:

args[0]

将其称为execv并使其可执行。 (例如#!/bin/bash declare -i cnt=0 for i in "$@"; do printf " arg[%d] : %s\n" $cnt "$i" let cnt=cnt+1 done )然后提供test.sh以及您选择参与计划的参数:

chmod 0755 test.sh

答案 2 :(得分:0)

根据评论,主要问题不是实际执行,而是在您自己的代码中解析命令行。因此,我只是给出了我能想到的最基本的解决方案,并给予了很多评论。它不支持任何,如用户引用,转义或编辑命令行,但它应该有助于理解一般概念 - 尝试将其作为起点。

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

#define PROMPT "YWIMC > "

/* read in a command */
static char **getCommand(void)
{
    /* static buffers, no need to allocate dynamically for a simple example */
    static char cmdline[1024]; /* command-line */
    static char *command[7];   /* parsed command */

    /* initialize empty command */
    memset(command, 0, sizeof(command));

    do
    {
        /* show prompt: */
        fputs(PROMPT, stdout);

        /* read commandline: */
        if (fgets(cmdline, 1024, stdin))
        {
            int i = 0;

            /* get first token (the command name) */
            if ((command[i++] = strtok(cmdline, " \r\n\t")))
            {
                /* get up to 5 additional tokens (the parameters) */
                while (i < 6 && (command[i++] = strtok(0, " \r\n\t")));
            }
        }
    } while (!(command[0])); /* until something was entered */

    return command;
}

int main(void)
{
    /* endless loop */
    while (1)
    {
        /* get next command */
        char **command = getCommand();

        /* and try to execute it */
        if (!strncmp(command[0], "Q", 1))
        {
            /* quit command */

            puts("k tnx bye.");
            exit(0);
        }
        else if (!strncmp(command[0], "R", 1))
        {
            /* run command */

            /* check there was something to run given: */
            if (!command[1])
            {
                fputs("Command `R': Nothing to run.\n", stderr);
            }
            else
            {
                /* YOUR COMMAND EXECUTION GOES HERE */
                /* (try to create another "static" function for it) */
            }
        }
        else
        {
            int i = 0;

            /* some debugging on unrecognized commands */
            fprintf(stderr, "Unrecognized command: `%s' (args: ",
                    command[i++]);

            while (command[i])
            {
                fprintf(stderr, "`%s' ", command[i++]);
            }
            fputs(")\n", stderr);
        }
    }
}

要理解的一个关键问题是command有7个条目。第一个是为您的命令保留的。最后一个应始终为NULL(或0),以便您的代码可以检测到参数列表的结尾。留下5个可用参数。如果你的一个命令应该将其中的第一个参数作为外部命令运行并允许另外4个参数,那么你只需要那些参数。