2013-03-12 4 views
-6

Я создал программу, которая действует как среда Linux. Вы вводите команду, и она делает это за вас.Создайте среду linux в C с помощью execl и fork()

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

int main() 
{ 

int pid; 
int status; 
printf("Enter command: "); 
char s[256]; 
fgets(s,256,stdin); 

const char *a[5]; 
int i = 0; 
char* token = strtok(s, " "); 
while(token) 
{ 
    a[i] = strtok(s," "); 
    i++; 
} 

while (a[0] != "exit") 
{ 
    if(a[0] = "cd") 
    { 
     chdir(a[1]); 
    } 

    else 
    { 
     pid = fork(); 
     if (pid == 0) 
     { 
     execvp(a[0],a); 
     } 
     if(pid > 0) 
     { 
      wait(&status); 
     } 
    } 

} 
return 0; 
} 

Он использует токены для разделения параметров команды. Я попытался запустить его, и он компилируется и запускается, но не выполняет команду, которую я хочу. Я думаю, что это может быть связано с тем, как он создает токены. Любая помощь будет большой. Благодарю.

+1

Научитесь использовать отладчик наподобие 'gdb'. Скомпилируйте свою программу с помощью 'gcc -Wall -g'. И очистите массив 'a [5]' (который должен быть намного больше или несколько выделенных кучей данных). Посмотрите также на исходный код небольших бесплатных программных оболочек (например, 'sash') –

+5

Также' a [0]! = "Exit" ', вероятно, не то, что вы хотите. Используйте 'strcmp'. – cnicutar

+1

Вам действительно нужно занять несколько часов, чтобы прочитать хорошую книгу программирования C. Затем прочитайте хорошую книгу программирования Linux, такую ​​как http://advancedlinuxprogramming.com/; провести день или два для чтения (возможно, в библиотеке). –

ответ

3

Линия:

a[i] = strtok(s," "); 

наборы a[i] к указателю в пределах строки, которые вы модифицирующие и которые могут в конечном итоге иметь временные NUL символов (от strtok) удалены.

Вы можете попробовать:

a[i] = strdup (strtok (s," ")); 

вместо этого.


Позвольте мне подробнее пояснить. Скажем, у нас есть команда (как она существует в памяти):

ls -al xyzzy\0 

Когда вы strtok это, он почти наверняка получает изменено на:

ls\0-al xyzzy\0 
^ 

, а затем он дает s (обозначенный ^) возвращается с strtok и помещается в a[0]. В следующий раз, через, он изменяет строку:

ls -al\0xyzzy\0 
^

и дает адрес, указанный ^ и места, в a[1]. К сожалению, a[0] теперь указывает на строку "ls -al"

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

Таким образом, вы будете в конечном итоге с:

a[0] = "ls -al xyzzy" 
a[1] = "-al xyzzy" 
a[2] = "xyzzy" 

Используя strdup, вы делаете копию каждой строки (в то время, когда строка, как вы ожидаете, одно слово), который затем не модифицируется последующими операциями в коде токенизации строки.

Помните, однако, чтобы освободить все те строки, которые вы выделили, когда закончите с ними.

Вы можете использовать этот код в качестве основы:

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

int main (void) { 
    char str[256], *word[20]; 
    int i, num, len; 

    printf ("Enter command: "); 
    fgets (str, sizeof (str), stdin); 

    num = 0; 
    word[num] = strtok (str, " "); 
    while (word[num] != NULL) { 
     word[num] = strdup (word[num]); 
     len = strlen (word[num]); 
     if (strlen (word[num]) > 0) 
      if (word[num][len-1] == '\n') 
       word[num][len-1] = '\0'; 
     word[++num] = strtok (NULL, " "); 
    } 

    for (i = 0; i < num; i++) { 
     printf ("%d: [%s]\n", i, (word[i] == NULL) ? "<<null>>" : word[i]); 
     free (word[i]); 
    } 

    return 0; 
} 

и следующего транскрипта показывает его в действии:

Enter command: ls -al xyzzy | grep -v plugh 
0: [ls] 
1: [-al] 
2: [xyzzy] 
3: [|] 
4: [grep] 
5: [-v] 
6: [plugh] 

Кроме того, правильный способ сравнения строк C не :

if (a[0] = "cd") 

, так как это сравнивает адреса ,, которые могут отличаться, даже если содержимое подложки идентично. Вместо этого вы должны использовать что-то вроде:

if (strcmp (a[0], "cd") == 0) 

И одна заключительная вещь, argv[] массив, который вы передаете execvp должны иметь конечный указатель завершающего NULL. Это часть контракта, поэтому вам нужно будет убедиться, что он встает перед вызовом execvp.

+0

Когда я делаю 'strdup (strtok (s," "));' все, что я вставляю, просто дает мне пустую строку. Я переписал все мои инструкции сравнения на 'strcmp'. Я не понимаю ваших последних замечаний о execvp. –

0

Цикл while while (a[0] != "exit") никогда не будет прерван. Вы сравниваете указатели (адреса памяти). Возможно, вы захотите прочитать о strcmp().

Операция if if(a[0] = "cd") похоже также не то, что я думаю, вы пытаетесь сделать. Вы назначаете указатель на "cd" на номер a[0]. Эта распространенная ошибка будет устранена, если вы использовали диагностику компилятора (вероятное намерение состояло в том, чтобы вместо этого использовать ==, что тоже не сработает - снова strcmp() - это то, что нужно использовать для сравнения строк).

+0

так 'strcmp (a [0], char * string1)', в котором строка1 установлена ​​для выхода? и один для cd? –

+0

Даже более простой 'strcmp (a [0],« exit »)' возвращает 0, если две строки равны (массивы char содержат ровно один и тот же символ до окончания «NUL'). – FooF

+0

Я все сравнивал с 'strcmp', но я получаю ошибку сегментации, когда когда-либо добавляю любую команду, включая выход. –

Смежные вопросы