2016-11-15 10 views
1

Я пытаюсь разбить строку на токены, чтобы создать массив параметров аргумента. Моя текущая реализация выглядит следующим образом (path путь к пользовательским исполняемым файлам, для которых необязательных аргументы считываются):Разбор строки в токенах на C - что не так?

// ARG_MAX as defined in limits.h 
int execute(char *exe) { 
    printf("args to %s: ", exe); 

    char *args = malloc(ARG_MAX); 
    scanf("%s", args); 

    char *argv[ARG_MAX]; 

    int i = 0; 
    argv[i++] = exe; 

    while ((argv[i] = strsep(&args, " \t")) != NULL) { 
     i++; 
    } 

    free(args); 
    execv(exe, argv); 
    return 0; 
} 

Что меня смущает то, что от моего понимания strsep это должно работать, как задумано, и в той степени, в которой при тестировании он точно выделяет tokens[0] как path, а tokens[1] должен быть любым tokens_s до первого символа пробела.

Если после пробела вы вводите другой аргумент, это не относится к tokens[2] и т. Д. Для последующих аргументов.

Я не могу понять, что я делал неправильно при использовании strsep, что не приводит к желаемой функциональности?

вход: exe = "/usr/bin/ps" args = "-e -l"

выход: exec ps -e

+0

'зсапЕ ("% S", арг);' не сохраняет ' '\ t'', ни пространства в' args'. Используйте 'fgets()'. Предложите опубликовать свой ввод. – chux

+0

добавлен ввод. попробовали использовать 'fgets()', но в тот момент, когда мне нужно было ввести аргументы в командной строке, оно просто продолжается без подсказки? – transiti0nary

+0

Поскольку этот пост не содержит полного компилируемого кода, он просто усложняет его работу. Добавление 'fgets()' вероятно, является проблемой, потому что другой код все еще использует 'scanf()'. Настоятельно рекомендуем опубликовать полный минимальный код, который показывает проблему. – chux

ответ

3

несколько ошибок:

  • Вы должны прочитать аргументы с fgets() прочитать несколько слов.

  • Вы должны использовать временную переменную для strsep(), так что вы можете передать исходный указатель из malloc() обратно free(), или просто использовать локальный массив.

Вот исправленный вариант:

#include <errno.h> 
#include <stdio.h> 
#include <string.h> 
#include <unistd.h> 
#include <limits.h> 

// ARG_MAX as defined in limits.h 
int execute(char *exe) { 
    char args[ARG_MAX + 1]; 

    printf("args to %s: ", exe); 
    fflush(stdout); 
    if (fgets(args, sizeof args, stdin)) { 
     char *argv[ARG_MAX/2]; 
     char *p; 

     int i = 0; 
     argv[i++] = exe; 

     p = args; 
     args[strcspn(args, "\n")] = '\0'; // strip the newline if present 
     while ((argv[i] = strsep(&p, " \t")) != NULL) { 
      i++; 
     } 

     printf("argv: "); 
     for (i = 0; argv[i]; i++) 
      printf(" '%s'", argv[i]); 
     printf("\n"); 

     execv(exe, argv); 
     printf("exec failed: %s\n", strerror(errno)); 
    } else { 
     printf("cannot read input\n"); 
    } 
    return 0; 
} 

int main(int argc, char *argv[]) { 
    char *exe = "printf"; 
    if (argc > 1) 
     exe = argv[1]; 
    return execute(exe); 
} 

Примечания:

  • execv не вернется в вашу программу, если это удастся.

  • strsep не разрушает последовательности разделителей, ваш метод будет создавать дополнительные аргументы, если у вас есть дополнительные пробелы.

EDIT: Если вход считывается из stdin, прежде чем вы получите запустить execute, и если такой ввод выполняется с вызовами scanf(), может быть в ожидании новой строки в stdin буфере, и fgets() прочтет это как пустая строка. Если это так, то первый промывать ожидающий ввода перед вызовом printf():

int c; 
while ((c = getchar()) != EOF && c != '\n') { 
    continue; 
} 
+0

Спасибо, что полезно, как его правильно реализовать, однако '' args to% s ', exe' никогда не печатается на консоль и вместо этого программа выполняет без аргументов с этим кодом? В этой проблеме я постоянно пытаюсь использовать 'fgets()' и 'getline()'. В моем исходном коде выше он все равно распечатает приглашение и выполнит, но только распознает первый аргумент – transiti0nary

+0

@ transiti0nary: если вы добавите 'fflush (stdout);', выводится ли приглашение? Вы уверены, что можете читать со стандартного ввода? Я обновил свой ответ, чтобы сделать ошибку более явной. – chqrlie

+0

Да, подсказка теперь распечатывается, но она все равно не останавливается на вводе и просто запускает exec без аргументов – transiti0nary