ubuntuusers.de

Getopt bringt Optionen mit Whitespace durcheinander

Status: Gelöst | Ubuntu-Version: Ubuntu 18.04 (Bionic Beaver)
Antworten |

sugarcube

Avatar von sugarcube

Anmeldungsdatum:
12. Januar 2007

Beiträge: 236

Wohnort: Willich

Hallo alle,

ich sitze an einem Problem, bei dem ich anscheinend Tomaten auf den Augen habe.

Ich habe mir zwei Scripte geschrieben. Das eine ruft das andere auf und übergibt ermittelte Optionen und einen Dateinamen. Das andere wertet die Optionen mittels getopt aus und soll dann arbeiten.

Natürlich können die Optionen und der Dateiname Whitespace enthalten. Deshalb übergebe ich alles gequotet. Das zweite Script bekommt die Optionen auch sauber angereicht, aber nach der Verarbeitung durch getopt ist alles nur noch unbrauchbar, denn die Optionen werden miteinander verwürfelt. Zudem unterscheidet sich das von getopt geparste Ergebnis auch noch, je nachdem, ob ich den Aufruf von einem Script durchführe oder von der Komandozeile aus.

Damit die ganze Sache etwas plakativer wird, habe ich zwei Scripte gebastelt, das erste (autolnk_test) ruft das zweite (lnk_test) auf. Sie zeigen das Ergebnis bei verschiedenen Konstellationen. Einzig Optionen ohne Whitespace werden korrekt ausgewertet.

Hier ist autolnk_test

und hier lnk_test

Wenn die Scripte in einem Verzeichnis liegen, sieht mein Aufruf so aus:

1
sh ./autolnk_test

Wie muss der Aufruf sein, damit getopt Optionen mit Whitespace richtig abarbeitet? Irgendetwas übersehe ich, und freue mich über jede Hilfe.

seahawk1986

Anmeldungsdatum:
27. Oktober 2006

Beiträge: 11261

Wohnort: München

Das mit dem OptStrklappt so nicht, weil die einzelnen Argumente aus dem String ungequotet sind, sobald du die Variable ohne Quotes referenzierst.

Ich würde da keinen String für die Argumente nehmen, sondern einen Array:

$ OptArr=('-n' '--force="M§Test mit Whitespace (nur eine Option)"')
$ echo "autolnk_test:     "${OptArr[@]}" "$Filename"
$ /bin/bash ./lnk_test ${OptArr[@]}" "$Filename"
Vor Verarbeitung: -n --force="M§Test mit Whitespace (nur eine Option)"
Nach Getopt:      -n --force "M§Test mit Whitespace (nur eine Option)" --
Neu: true\nForce: true\nForceFolder: M§Test mit Whitespace (nur eine Option)\nReihe: false\nReihenName: \n$1: \n 

Wenn man in der letzten Zeile von lnk_test dem echo noch ein -ne mitgibt, macht echo auch die gewünschten Zeilenumbrüche.

rklm Team-Icon

Projektleitung

Anmeldungsdatum:
16. Oktober 2011

Beiträge: 13209

Ja, definitiv was seahawk1986 sagt: es ist ein Quoting-Problem. Du hast übrigens $Filename so definiert, dass es einfache Anführungsstriche enthält. Du willst aber eher eins von beiden:

1
2
Filename="Dateiname mit Whitespace"
Filename='Dateiname mit Whitespace'

Bei der Verwendung nachher natürlich mit Quotes

1
/bin/sh ./lnk_test ... "$Filename"

Übrigens kannst Du Dir das Leben leichter machen und musst nicht alle Zeilen doppelt tippen. Hier ist die einfachste Lösung zum Debuggen:

1
sh -x autolnk_test

Dann kannst Du die ganzen echo aus dem Skript werfen. Wenn Du die ausgeführten Befehle unbedingt nach Stdout schreiben willst, kann man es auch mit einer Shell-Funktion machen:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
#!/bin/bash

Filename='Dateiname mit Whitespace'

x() { echo ">> autolnk_test: $*"; "$@"; }


OptStr='-n --force="M§Test mit Whitespace (nur eine Option)"'
x /bin/sh ./lnk_test $OptStr "$Filename"

OptStr='-n --force="M§Test mit Whitespace" --reihe="Name mit Whitespace"'
x /bin/sh ./lnk_test $OptStr "$Filename"

OptStr='-n --force="M§Test_ohne_Whitespace" --reihe="Name mit Whitespace"'
x /bin/sh ./lnk_test $OptStr "$Filename"

OptStr='-n --force="M§Test_ohne_Whitespace" --reihe="Name_ohne_Whitespace"'
x /bin/sh ./lnk_test $OptStr "$Filename"

rklm Team-Icon

Projektleitung

Anmeldungsdatum:
16. Oktober 2011

Beiträge: 13209

Noch ein paar Anmerkungen zu lnk_test:

  • Innerhalb von Skripten besser Variablennamen nur in Kleinschrift um sie leichter von Umgebungsvariablen zu unterscheiden.

  • Ich benutze lieber das Shell-Builtin getopts anstatt /usr/bin/getopt, weil es halt eingebaut ist und damit direkt Variablen der aktuellen Shell setzen kann. M.E. macht getopt nur Sinn, wenn man lange Optionsnamen nutzen will. (obwohl...) Zu dem Thema "getopt vs. getopts" gibt es allerdings reichlich Material...

seahawk1986

Anmeldungsdatum:
27. Oktober 2006

Beiträge: 11261

Wohnort: München

In meiner Antwort fehlt ein doppeltes Anführungszeichen - das sollte so aussehen:

$ /bin/bash ./lnk_test "${OptArr[@]}" "$Filename" 

sugarcube

(Themenstarter)
Avatar von sugarcube

Anmeldungsdatum:
12. Januar 2007

Beiträge: 236

Wohnort: Willich

Danke für die schnelle Antwort.

@seahawk1986

OptArr=('-n' '--force="M§Test mit Whitespace (nur eine Option)"')

Funktioniert bei mir nur auf der Kommandozeile. Im Script erhalte ich

Syntax error: "(" unexpected

Meine Güte - es bleibt bei mir bei Tomaten auf den Augen. Ich seh's nicht!

@rklm: Ja, Variablenbenamungen sind ein prima Thema um am Stammtisch zu diskutieren. Bei mir sind sie immer so, und ich glaube, dass ich mich wohl nicht mehr ohne Androhung von Peitschenhieben umstellen werde... 😉 getopts hatte ich auch verwendet, aber im Ursprungsscript sind so viele Optionen möglich, dass ich auf getopt ausweichen musste. Auch hier sind die Diskussionen viele und mir wohl bekannt.

Und an beide: Eure Tipps zum Debuggen und zur einfacheren Ausgabe schätze ich sehr.

sugarcube

(Themenstarter)
Avatar von sugarcube

Anmeldungsdatum:
12. Januar 2007

Beiträge: 236

Wohnort: Willich

Arrgh! sh benutzt. Dann kanns ja nicht gehen.

sugarcube

(Themenstarter)
Avatar von sugarcube

Anmeldungsdatum:
12. Januar 2007

Beiträge: 236

Wohnort: Willich

Danke rklm und seahawk1986, ihr habt mich auf den richtigen Weg geschubst.

Hier die Lösung, für das aufrufende Script, falls es jemanden später mal interessiert:

1
2
3
4
5
6
#!/bin/bash

Filename=(\'Dateiname mit Whitespace\')

OptArr=('-n' '--force="M§Test mit Whitespace (nur eine Option)"' '--reihe="Name mit Whitespace"')
/bin/bash ./lnk_test "${OptArr[@]}" "${Filename[@]}"

Und im aufgerufenen Script muss für getopt die Option -u gesetzt werden, sonst gibt es Probleme mit dem Quoting.

Antworten |