Mein Projekt erfordert das Aufteilen eines Strings in argc
und argv
.
Habe einen ziemlich ausgezeichneten Code von Torek gefunden. Aber er verändert den Eingabepuffer, also habe ich einige Anpassungen vorgenommen, um meinen Bedürfnissen gerecht zu werden.
Ich habe einfach ein wenig mehr hinzugefügt, um das Mischen von Anführungszeichen bei der Eingabe in der Befehlszeile zu handhaben, damit sich das Verhalten mehr (aber nicht komplett) wie die Linux-Shell verhält.
Hinweis: Diese Funktion bearbeitet den Original-String nicht, sodass Sie den Eingabepuffer wiederverwenden können (Fehlerbericht, usw.).
void remove_quote(char* input){
//Implementieren Sie selbst das Entfernen von Anführungszeichen, damit es komplett wie die Linux-Shell ist
}
size_t cmd_param_split(char *buffer, char *argv[], size_t argv_max_size)
{
char *p, *start_of_word;
int c, i;
enum states { DULL=0, IN_WORD, IN_STRING, QUOTE_DOUBLE,QUOTE_SINGLE } state = DULL;
size_t argc = 0;
int quote = 0;
for (p = buffer; argc < argv_max_size && *p != '\0'; p++) {
c = (unsigned char) *p;
printf("Verarbeite %c, Zustand = %d\n", c,state);
switch (state) {
case DULL:
if (isspace(c)) {
continue;
}
if (c == '"' ||c == '\'') {
quote = c;
state = IN_STRING;
start_of_word = p + 1;
continue;
}
state = IN_WORD;
start_of_word = p;
continue;
case IN_STRING:
if (c == '"' || c == '\'') {
if (c!=quote)
continue;
else
quote = 0;
strncpy(argv[argc],start_of_word, p - start_of_word);
remove_quote(argv[argc]);
argc++;
state = DULL;
}
continue;
case IN_WORD:
if(quote==0 && (c == '\"' ||c == '\''))
quote = c;
else if (quote == c)
quote = 0;
if (isspace(c) && quote==0) {
strncpy(argv[argc],start_of_word, p - start_of_word);
remove_quote(argv[argc]);
argc++;
state = DULL;
}
continue;
}
}
if (state != DULL && argc < argv_max_size){
strncpy(argv[argc],start_of_word, p - start_of_word);
remove_quote(argv[argc]);
argc++;
}
if (quote){
printf("WARNUNG: Anführungszeichen sind nicht ausgeglichen. Das könnte zu unerwünschtem Verhalten führen\n");
for(i = 0;i
`
Getestet mit den folgenden Zeichenfolgen
1. "1 2 3 \'3 4\"567\' \"bol\'obala\" 2x2=\"foo\""
arg 0 = [1]
arg 1 = [2]
arg 2 = [3]
arg 3 = [3 4"567]
arg 4 = [bol'obala]
arg 5 = [2x2="foo"]
2. "./foo bar=\"Hanoi HoChiMinh\" exp='foo123 \"boo111' mixquote \"hanoi \'s\""
arg 0 = [./foo]
arg 1 = [bar="Hanoi HoChiMinh"]
arg 2 = [exp='foo123 "boo111']
arg 3 = [mixquote]
arg 4 = [hanoi 's]
Jedoch würde die Linux-Shell Anführungszeichen entfernen, selbst bei gemischtem Fall, wie unten gezeigt, wenn sie vom Befehlszeilenfenster aus ausgeführt wird, getestet auf einem RaspberryPi.
./foo bar="Hanoi HoChiMinh" exp='foo123 "boo111' mixquote "hanoi 's"
arg 0 = [./foo]
arg 1 = [bar=Hanoi HoChiMinh]
arg 2 = [exp=foo123 "boo111]
arg 3 = [mixquote]
arg 4 = [hanoi 's]
Also, wenn Sie wirklich das gesamte Verhalten der Linux-Shell nachahmen möchten, geben Sie einfach ein wenig mehr Mühe in die Entfernung der Anführungszeichen in der remove_quote() Funktion, wie ich oben leer gelassen habe.
`
0 Stimmen
Für welche Plattform? Wie Befehlszeilen in argc/argv umgewandelt werden, unterscheidet sich erheblich zwischen Windows und UNIX-basierten Systemen, zum Beispiel. Auf UNIX transformiert die Shell in der Regel die Befehlszeile erheblich, einschließlich des Durchlaufens (Dateimustererweiterung) und der Variablensubstitution. Auf Windows wird die Dateimustererweiterung nicht von der Shell durchgeführt (es sei denn, Sie verwenden etwas wie Cygwin oder das MKS Toolkit).
0 Stimmen
Wenn Sie nicht einmal mit zitierten Argumenten umgehen müssen, würde ich wirklich vorschlagen, Ihre eigene Funktion zu codieren, anstatt eine Bibliothek von Drittanbietern nur für diese Aufgabe einzuführen.
2 Stimmen
Hast du getopt() ausprobiert? (man 3 getopt). Du kannst die Quellen für die meisten Standard-UNIX/Linux-Tools für Beispiele einsehen, eine RIESIGE Anzahl davon. Selbst die Man-Page (zumindest die Linux-Version) enthält ein ordentliches Beispiel. Es gibt auch eine Reihe von Wrapper-Funktionen (du siehst hier Empfehlungen), aber getopt() scheint die einzige verfügbare für JEDE UNIX-Plattform zu sein (tatsächlich scheint sie Teil des POSIX-Standards zu sein).
0 Stimmen
Wenn Sie immer noch interessiert sind und industrielle Stärke von Grund auf wollen, in einem kleinen Codepaket. Suchen Sie auf dieser Seite nach
nargv
Mit Abstand die beste Lösung, die ich hier aus reinem c-Code gesehen habe. Bitte stimmen Sie für diese Antwort! Damit andere sie finden können.0 Stimmen
@user735796 Ich habe nach
nargv
gesucht und dein Kommentar ist der einzige Treffer. Also habe ich gegoogelt: github.com/hypersoft/nargv ... Ein paar Anmerkungen jedoch. Dies verwendet C99, daher wird es nicht mit dem Microsoft C-Compiler funktionieren. Auch eine Idee ist es, Unit-Tests mit einer Vielzahl von Testfällen zu haben, die jeden Typ von Szenario für den Parser überprüfen, um sicherzustellen, dass es wie erwartet funktioniert.0 Stimmen
Für Unix-Entwickler, die eine sehr einfache, aber leistungsstarke Implementierung wünschen, die das Bash-Style Escaping und Quoting behandelt: github.com/pasztorpisti/cmd2argv
0 Stimmen
Du möchtest wahrscheinlich auch das Globbing aktivieren, also siehe glob(7) und folge den dortigen Verweisen.
0 Stimmen
Nicht sicher, warum getopt hier Upvotes bekommt --- es löst ein anderes Problem (Analyse des Inhalts eines argv-Arrays, anstatt tatsächlich ein argv-Array aus einem String zu erstellen, wonach der OP gefragt hat).
0 Stimmen
Schau dir das an: stackoverflow.com/a/54617539/236062