2009-08-24 2 views
3

사용자에게 명령을 입력하라는 메시지를 표시하고 exec를 사용하여 해당 명령을 실행하려고합니다.유닉스에서 사용자 입력으로 C에서 execvp()를 사용하려고 시도했습니다.

예를 들어 "ls -la"라고 입력하면 해당 명령을 실행해야합니다. 나는 다음과 같은 코드를 시도했다 :

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

int main() 
{ 

    int ret, num_args; 

    printf("Enter number of arguments (Example: \"ls -la\" has 1 argument): "); 
    scanf("%d", &num_args); 

    char *cmd[num_args]; 

    printf("Enter command name: "); 
    scanf("%s", &cmd[0]); 

    int i; 
    for (i = 0; i < num_args; i++) 
    { 
      printf("Enter parameter: "); 
      scanf("%s", &cmd[i]); 
    } 

    execvp(cmd[0], cmd); 
} 

그러나, 나는 그것이 나에게 "분할 오류"

$ ./a.out 
Enter number of arguments (Example: "ls -la" has 1 argument): 2 
Enter command name: ls 
Enter parameter: -la 
Enter parameter: . 
Segmentation fault 
$ 

어떤 아이디어를 준 다음 실행을 시도 할 때?

답변

3

구현이 지원하는 경우 scanf() 또는 fgets() 대신 안전한 getline()을 사용해야합니다. getline()은 긴 줄과 NULL 문자를 안전하게 처리합니다. 전체 라인에 맞게 충분한 메모리를 할당합니다. getline()은 메모리를 할당 할 수 있으므로 나중에 직접 메모리를 비워야합니다.

여기는 glibc getline() documentation입니다. 여기

가의 getline을 사용하는 빠른 수정입니다 (아직 작업, 오류 검사를 필요로하고 나는 아직 완전히 정확성을 확인하지 않은) :

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

int main() 
{ 

    printf("Enter number of arguments (Example: \"ls -la\" has 1 argument): \n"); 

    char *num = NULL; 
    size_t sz = 0; 
    getline(&num, &sz, stdin); 

    int num_args; 
    sscanf(num, "%d", &num_args); 

    char *cmd[num_args+2]; 
    memset(cmd, 0, sizeof(char*) * (num_args+2)); 

    printf("Enter command name: \n"); 


    int len = getline(&cmd[0], &sz, stdin); 

    cmd[0][len-1] = '\0'; 

    int i; 
    for (i = 1; i < num_args+1; i++) 
    { 
     printf("Enter parameter: \n"); 
     sz = 0; 
     len = getline(&cmd[i], &sz, stdin); 
     cmd[i][len-1] = '\0'; 
    } 

    return execvp(cmd[0], cmd); 

} 
+0

컴파일러는 getline이 무엇인지 알지 못합니다. #include 줄이나 컴파일러 자체가 없기 때문입니까? –

+0

'getline'은 C의 GNU 함수입니다. http://www.gnu.org/s/libc/manual/html_node/Line-Input.html –

+0

컴파일러와 운영 체제는 무엇입니까? –

1

cmd 배열이 가리키는 문자열에 실제로 메모리를 할당하지 않았습니다.

+1

그럼 정확히 어떻게할까요? –

+1

malloc/free를 검색하여 "cmd"의 각 포인터에 충분한 공간이 할당되었는지 확인하십시오. –

2

argv에 항목이 하나 더 필요합니다. execvp으로 전달해야하며, 목록의 끝에 도달했음을 알려주기 위해 (char *)NULL이어야합니다.

+0

또 다른 하나는 명령의 이름 인 argv [0] (일반적으로)입니다. –

3

문자열에 메모리를 할당해야합니다. 당신이 (명령 자체가 cmd[0] 것을 잊지 마세요) num_args + 1 문자열을 받고있을거야, 모든

char *cmd[num_args]; 

첫째 : 다음 라인은 char에 대한 포인터의 num_args 가치를 할당합니다. 가장 쉬운 방법은 정적 문자 버퍼의 배열로 메모리를 할당하는 것입니다 : 지금 당신이 줄을 읽을 scanf을 사용할 수 없습니다, 그러나

const unsigned int MAX_LEN = 512; // Arbitrary number 
char cmd[num_args + 1][MAX_LEN]; 

때문에 사용자 수를 입력하여 문자 버퍼보다 ​​더 오래입니다 문자열 . fgets는 개행 문자를 읽고 있다는 사실을 숙지하십시오, 그렇게 할

fgets(cmd[i], MAX_LEN, stdin); 

확실히 표시 어떤 길 잃은 사람을 제거하는 대신, 사용자가 입력 할 수있는 문자의 수를 제한 할 수있는 fgets을 사용해야합니다 (그러나 그들이 거기에 있다고 가정하지는 마십시오).

+0

그렇게하면 컴파일러 오류가 발생합니다. 그것은 cmd [num_arghs + 1] [MAX_LEN]을 말하는 것입니다. 올바르지 않습니다 : "구문 오류 앞에 ';'" –

+0

@ 닉 코드를 다시 확인하십시오; 나는 작은 테스트 프로그램을 작성했고 그것은 나를 위해 잘 컴파일했다. –

+0

Woops, 나는'MAX_LEN = 512' 줄에 세미콜론을 깜빡입니다. 이제 해결되었습니다. –

-1

이 (scanf와의 man 페이지를 찾아 보라). 그것이 할 수있는 가장 사소한 일 중 하나는 자동으로 문자열 버퍼를 즉시 할당하는 것입니다. 문자열을 전달하는 대신 문자열에 포인터를 제공하고 %를 형식으로 제공해야합니다.

char *my_string; 
scanf("%as", &my_string); 

그럼 당신은 당신이 그것으로 완료 한 후 그냥) (무료로 기억 등, 버퍼 오버 플로우 귀찮게 할 필요가 없습니다, 미리 할당 귀찮게 할 필요가 없습니다.

+0

'% as'명세는 _not_ 표준 C 동작이다. –

관련 문제