Как я могу разобрать командную строку с точкой с запятой? - PullRequest
0 голосов
/ 10 апреля 2020

Я пытаюсь прочитать аргументы командной строки, разделенные точкой с запятой с пробелом вперед и назад (например, ls; date; cal), но разделение было затруднено. Мои коды работают, когда я просто помещаю отдельную командную строку (например, ls или date), но всякий раз, когда я ставлю точку с запятой, она не работает (например, ls ; date)

Вот мой C код:

void parse(char *userInput, char **splitInput)
{
  //read until userInput is not end of line
  while (*userInput != '\0')
  {
    //replace any space in userInput as '\0'
    while (*userInput == ';')
    {
      *userInput++ = '\0';
    }
    //save the argument position
    *splitInput++ = userInput;
    //if userinput is not equal to space, read next userInput
    while (*userInput != ' ' && *userInput != ';' && *userInput != '\0')
    {
      userInput++;
    }
  }
}

void execute(char **splitInput)
{
  pid_t pid = fork();

  if (pid > 0) //parent process
  {
    pid_t parent_pid;
    parent_pid = wait(NULL);
  }
  else if (pid == 0) //child process
  {
    if (execvp(*splitInput, splitInput) < 0) 
    {
      printf("%s: command not found\n", *splitInput);
      exit(1);
    }      
  }  
  else //error
  {
    perror("fort error");
  }
}

void main(void)
{
  char userInput[100]; //execvp's first argument
  char *splitInput[100]; //execvp's second argument

  while(strcmp(userInput,"quit") != 0)
  {
    //ask for a user input
    printf("group 10> ");
    //read the entire line of input
    scanf("%[^\n]", userInput);
    //get characters from input; stop the loop problem
    getchar();
    //quit if user input is equal to quit
    if (strcmp(userInput, "quit") == 0)
    {
      exit(0);
    }
    //parse the input
    parse(userInput, splitInput);
    //execute fork
    execute(splitInput);
  }
}

1 Ответ

1 голос
/ 11 апреля 2020

Есть несколько способов сделать это. string.h предоставляет несколько функций, которые можно использовать: strtok(), strsep(), strchr() или комбинацию strcspn() и strspn() в зависимости от ваших потребностей. Вы также можете всегда ходить по строке, выбирая нужные токены из строки и игнорируя пробелы и несколько включенных разделителей. На самом деле есть хорошая обучающая ценность указателя в подходе к этому пути с точки зрения образования.

Каждый раз, когда вы перебираете что-то, выбирая различные фрагменты, вместо того, чтобы пытаться включить несколько вложенных циклов while, каждый из которых предназначен для Сканирование вперед, чтобы пропустить или найти определенный класс символов, часто более выгодно использовать state-l oop, где вы используете один или несколько флагов для отслеживания разных состояний. (строка для чтения символов в словах или между словами для чтения разделителей или пробелов и т. д. c ..). Таким образом, вложенные циклы не требуются, и вы просто используете по одному от l oop до l oop на каждый символ, отвечающий соответственно в зависимости от вашего текущего состояния.

Включение этого в работу для сканирования строки и выбора Выделите каждое из слов, оканчивающихся разделителем ';' или пробелом, и сохраняя один флаг состояния int in;, чтобы отслеживать, читаете ли вы символы в словах (in = 1;) или между словами, обрабатывающими пробелы и разделители (* 1019). *) и использовать char *sp в качестве указателя начала , указывающего на начало каждого слова, и userInput в качестве указателя конца , указывающего на текущий читаемый символ, вы можете do:

void parse(char *userInput, char **splitInput, char delim, size_t nptrs)
{
    int in = 0;             /* simple in-word flag 0-false/1-true */
    size_t n = 0;           /* counter to protect splitInput bounds */
    char *sp = userInput;   /* start-pointer initialized to userInput */

    while (n < nptrs - 1) { /* loop while pointers remain unfilled */
        /* if at end, is whitespace or a delimiter */
        if (!*userInput || isspace(*userInput) || *userInput == delim) {
            if (in) {                   /* if in word */
                splitInput[n++] = sp;   /* set pointer to start-pointer */
                splitInput[n] = NULL;   /* set next pointer NULL */
            }
            in = 0;                     /* reset in flag zero */
            if (*userInput)             /* if space or delim, nul-terminate */
                *userInput = 0;
            else    /* otherwise */
                return;                 /* at end-of-string */
        }
        else {  /* normal char */
            if (!in) {                  /* if not in-word */
                sp = userInput;         /* set start-pointer to 1st good char */
                in = 1;                 /* set in-word flag true */
            }
        }
        userInput++;    /* advance to next char */
    }
}

( примечание: над символом delim передается в качестве параметра вместе с nptrs для передачи количества доступных указателей, чтобы вы могли защитить свои границы массивов указателей при заполнении указателей. Также обратите внимание, что функция всегда устанавливает следующий указатель в вашем массиве на NULL в качестве часового, позволяя вам l oop над точкой inters в вашем массиве в main(), пока не будет достигнуто NULL, так как вы не возвращаете количество используемых указателей, либо как возвращаемую функцию, либо через параметр указателя)

Простой пример, который анализирует слова из " my; ; ; dog ;;; has;fleas ;" с использованием ';' или пробелами в качестве разделителей могут быть:

#include <stdio.h>
#include <ctype.h>

#define NPTR 32     /* if you need a constant, #define one (or more) */

void parse(char *userInput, char **splitInput, char delim, size_t nptrs)
{
    int in = 0;             /* simple in-word flag 0-false/1-true */
    size_t n = 0;           /* counter to protect splitInput bounds */
    char *sp = userInput;   /* start-pointer initialized to userInput */

    while (n < nptrs - 1) { /* loop while pointers remain unfilled */
        /* if at end, is whitespace or a delimiter */
        if (!*userInput || isspace(*userInput) || *userInput == delim) {
            if (in) {                   /* if in word */
                splitInput[n++] = sp;   /* set pointer to start-pointer */
                splitInput[n] = NULL;   /* set next pointer NULL */
            }
            in = 0;                     /* reset in flag zero */
            if (*userInput)             /* if space or delim, nul-terminate */
                *userInput = 0;
            else    /* otherwise */
                return;                 /* at end-of-string */
        }
        else {  /* normal char */
            if (!in) {                  /* if not in-word */
                sp = userInput;         /* set start-pointer to 1st good char */
                in = 1;                 /* set in-word flag true */
            }
        }
        userInput++;    /* advance to next char */
    }
}

int main (void) {

    char s[] = "  my; ; ;  dog  ;;; has;fleas  ;", *split[NPTR] = { NULL }, **p = split;

    parse (s, split, ';', NPTR);

    while (*p)
        printf ("'%s'\n", *p++);
}

( примечание: заголовок ctype.h включен для использования функции isspace() для проверять пробелы, а не связывать вместе операторы if(), проверяя space, '\t' или '\n' напрямую. Как правило, это хорошая практика.)

Пример использования / Вывод

$ ./bin/split_ptr_arr3
'my'
'dog'
'has'
'fleas'

Примечание: в выводе выше все включенные пробелы удалены.

Взгляд все закончилось и дайте мне знать, если у вас есть вопросы Существует буквально десятки способов подойти к разбиению строк, это всего лишь один общий и базовый c подход.

...