使用strtok运行多个命令

时间:2018-03-17 00:31:28

标签: c shell strtok

我正在尝试使用C创建一个shell,它可以使用分号(;)分隔多个命令。目前我正在尝试使用strtok来分离命令,但我认为我没有正确使用它。我会在不发布完整代码的情况下发布所有信息。是否正确使用了strtok?

ListView

编辑:根据指示,我删除了最初发布的大部分代码,专注于使用strtok。编译时,临时shell将一次接受一个命令。我正在尝试使用“;”同时分离和运行两个命令。我正确使用strtok吗?如果没有,还有其他选择吗?

2 个答案:

答案 0 :(得分:1)

< p>如果< code> strtok()< / code>,则应始终检查返回< code> NULL< / code>。我会改变结构如下:< / p> < pre>< code> char * semi =“;”; //你的semikolon char * token = NULL; //你的令牌字符串 // ... //拆分第一个分号 token = strtok(str,semi); if(token == NULL){     perror(“没有给出命令......”);     返回NULL; } 做{     //在这里执行你的代码     // fork()等     //你应该得到每一行(每个semikolon分隔的字符串)     //它应该存储到令牌中 } while((token = strtok(NULL,semi)!= NULL); < /代码>< /预> < p>我希望,我确实理解你的问题...< / p> < p>但正如我所看到的,您需要拆分< code>标记< / code>再次按空格将它们转换为< code> char< / code> -Array for< code> argv []< / code> (第二个参数)< code> execvp()< / code>。这里的问题是,< code> strtok()< / code>内部使用< code> static< / code> (?)变量存储最后一个位置。所以使用另一个< code> strtok()< / code>在循环内部会“破坏”你的文字。< / p> < p>你可以这样做:< / p> < pre>< code> char * str; //你的字符串...... char semi [1] =“;”; //你的semikolon和空间; strtok()将分裂 char * token = NULL; //你的令牌字符串 int len = 0; char * token2; int argvpos = 0; // ... //拆分第一个分号 token = strtok(str,semi); if(token == NULL){     perror(“没有给出命令......”);     返回EXIT_FAILURE; } 做{     //保存令牌的长度     len = strlen(token);     //拆分空白以获取参数     token2 = strtok(token,“”);     //构建参数数组     while(token2!= NULL){         args [argvpos ++] = token2;         token2 = strtok(NULL,“”);     }     //使用token(作为命令)执行某些操作     //和args(作为参数)     // ... } while((token = strtok(token + len + 1,semi)!= NULL); //在while条件中,您将长度添加到令牌;所以你得到了“旧的”最后一个位置 < /代码>< /预> < p>我认为这不是一个好的解决方案,但它应该有效。我希望,我确实理解你的问题; - )< / p> < p>亲切的问候。< / p>

答案 1 :(得分:1)

为了正常工作,strtok应与while循环一起使用。此外,您无需再运行execvp次。

我使用您的代码创建了一个小示例程序,以演示如何正确使用您的代码:

#include <string.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/wait.h>

int main()
{
  char str[] = "ls -1; echo 'hello world'"; // Input commands separated by ';'

  // Break the commands string into an array
  char *commands[10]; // Array to hold a max of 10 commands
  char *semi = ";";
  char *token = strtok(str, semi);
  int i = 0;
  while (token != NULL) 
  {
    commands[i] = token;
    ++i;
    token = strtok(NULL, semi);
  }
  int numCommands = i; // numCommands is the max number of input commands

  // Run each input command in a child process
  i = 0;
  while (i < numCommands)
  {
    printf("Command: %s\n", commands[i]);

    // Tokenize the command so that it can be run using execvp
    char *args[10] = {}; // Array to hold command args
    args[0] = strtok(commands[i], " ");
    int tokenCounter = 0;
    while (args[tokenCounter] != NULL)
    {
      tokenCounter++;
      args[tokenCounter] = strtok(NULL, " ");
    }

    // Create a child process
    int childpid = fork();

    // If this is child process, run the command
    if (childpid == 0)
    {
      if ((execvp(args[0], args)) < 0)
      {
        printf("Error! Command not recognized.\n");
      }
      exit(0);
    }
    // If this is the parent, wait for the child to finish
    else if (childpid > 0)
    {
      wait(&childpid);
    }
    // If the child process could not be created, print an error and exit
    else
    {
      printf("Error: Could not create a child process.\n");
      exit(1);
    }

    ++i;
  }

  return 0;
}