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 № 1Jeś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 argv
jak 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. :)