/ / exec () dowolne polecenie w C - c, linux, shell, execvp

exec () dowolne polecenie w C - c, linux, shell, execvp

Powiedz w C, chcę zadzwonić execvp() na dowolnym poleceniu ciągu. Polecenie może być tylko:

char command[] = "ls -l";
char command[] = "rm *.txt";
char command[] = "cat makefile";

Chcę umieścić tę zmienną polecenia wewnątrz execvp(). Więc exec() funkcja smakowa może po prostu działać z dowolnym rodzajem dowolnego polecenia.

Jak mogę to zrobić? Dzięki.

UWAGA: system() nie jest dozwolone.

Odpowiedzi:

7 dla odpowiedzi № 1

Jeśli ty mieć zadzwonić execvp(), następnie musisz podzielić te ciągi na nazwę wykonywalną i tablicę argumentów (pierwszy to „nazwa” programu, a ostatni wskaźnik NULL).

Oznacza to coś w rodzaju:

char cmd1[] = "ls";  char *args1[] = {"ls", "-l", NULL};
char cmd1[] = "rm";  char *args1[] = {"rm", "*.txt", NULL}; // but see
// globbing below.
char cmd1[] = "cat"; char *args1[] = {"cat", "makefile", NULL};

Jest to nietrywialne ćwiczenie, zwłaszcza jeśli chcesz pozwolić na cytowanie, globowanie, uciekanie i tak dalej.

Cytowanie oznacza, że ​​będziesz musiał uważać na polecenia takie jak:

rm "file with spaces.txt"

w tym możesz „po prostu włamać się na przestrzenie -będziesz musiał interpretować elementy w komendzie w taki sam sposób jak powłoka. Uproszczone łamanie w przestrzeniach da ci polecenie z trzema argumentami dla tego ciągu powyżej, a nie poprawnym.

Przez globbing mam na myśli, że prawie na pewno będziesz miał problemy z czymś takim *.txt ponieważ zazwyczaj jest to muszla co rozszerza te argumenty. Przekazując to bezpośrednio do execvp() spowoduje wynik pojedynczy argument dosłownie *.txt zamiast wielu argumentów pasujących do wszystkich plików tekstowych w bieżącym katalogu.

Cytowanie oznacza, że ​​będziesz musiał obsługiwać takie rzeczy jak:

ls -l "file with spaces and " quote in it"

co dodatkowo skomplikuje twój parser.

Nie zrozum mnie źle, można to zrobić, ale prawdopodobnie jest to o wiele łatwiejszy widok system().

Jeśli nadal myślisz o tym execvp() trasa, musisz:

  • podziel ciąg na oddzielne żetony (raczej trudne, ponieważ musisz obsługiwać cytaty i ucieczki).
  • globuj wszystkie argumenty, co oznacza, że ​​te z symbolami wieloznacznymi (i tylko te, które nie zostały „uchylone lub chronione z powodu bycia w cudzysłowie”) są rozszerzane na wiele argumentów.
  • skonstruuj tablicę argumentów z poleceniem z przodu i NULL na końcu.
  • połączenie execvp() z parametrami będącymi pierwszymi elementami w tej tablicy i adresem tablicy.

2 dla odpowiedzi nr 2

Nie, exec rodzina funkcji nie przyjmuje pojedynczego wiersza poleceń typu łańcuch system robi. Zamiast tego używa argvjak tablica ciągów:

char *command = "/path/to/command";
char *arguments[] = { "command", "first argument", "second argument", NULL };
execvp(command, arguments);

Zauważ, że pierwszy wpis w arguments tablica jest samą komendą i tablica jest zakończona przez NULL.

Czy sprawdziłeś stronę podręcznika?


2 dla odpowiedzi nr 3

Aby użyć dowolnej z funkcji stylu execve, będzieszmusisz samodzielnie przeanalizować linię poleceń i zbudować wektor argv. Funkcje pobierają znak char **, gdzie ostatni element ma wartość null - musisz przeznaczyć wystarczającą ilość pamięci na to wszystko. Wtedy wywołanie w stylu execve powinno działać.

(p.s. Nie wspomniałeś o widelcu ...)


1 dla odpowiedzi nr 4

Aby rzeczy takie jak „*” „>”, „<”, „&” itp. Działały, musisz wykonać „/ bin / sh” i przekazać w linii poleceń jako argumenty. Więc sprowadza się to do tokenizowania twojego ciągu.


1 dla odpowiedzi nr 5

Musisz zrobić, aby powłoka przeanalizowała polecenie. Rozważ to:

/bin/sh -c "rm *.txt"

To powinno sprawić, że pójdziesz we właściwym kierunku. :)