Bash: Befehlszeile mit optionalen Argumenten

7

Ich verwende diese Art von Code:

#!/usr/bin/env bash
set -u
exclude1='--exclude=/path/*'
exclude2='--exclude=/path with spaces/*'
exclude3=''        # any 'exclude' can be empty
tar -czf backup.tgz "$exclude1" "$exclude2" "$exclude3" 2>&1 | grep -i 'my_reg_exp' > error.log
RESULT=("${PIPESTATUS[@]}")
... etc ...

Wenn ich diesen Code ausführe, wird folgende Fehlermeldung angezeigt:

tar: : Cannot stat: No such file or directory

Dies liegt daran, dass "$ exclude3" als leeres Argument übersetzt wird. Genau so, als hätte ich das getan:

tar -czf backup.tgz "$exclude1" "$exclude2" ''

Eine Möglichkeit, diesen Fehler zu vermeiden, besteht darin, die doppelten Anführungszeichen um $ excludeX zu entfernen. Dies ist jedoch ein Problem, wenn $ excludeX Leerzeichen oder andere seltsame Zeichen enthält.

Eine andere Möglichkeit wäre die Verwendung, evalaber da ich die doppelten Anführungszeichen beibehalten muss, sehe ich nicht, wie die Anführungszeichen UND die leeren Argumente bei Bedarf unterdrückt werden können.

Die einzige Lösung, die ich gefunden habe, besteht darin, die Befehlszeile mit Zeichenfolgenverkettung zu erstellen:

CMD='tar -czf backup.tgz'
if [[ -n "$exclude1" ]]; then CMD+=" \"$exclude1\" "; fi
if [[ -n "$exclude2" ]]; then CMD+=" \"$exclude2\" "; fi
if [[ -n "$exclude3" ]]; then CMD+=" \"$exclude3\" "; fi
eval $CMD 2>&1 | grep -i 'my_reg_exp' > error.log
RESULT=("${PIPESTATUS[@]}")
... etc ...

Hat jemand eine klügere Idee?

Gregory MOUSSAT
quelle

Antworten:

7
tar -czf backup.tgz "$exclude1" "$exclude2" ${exclude3+"$exclude3"} 2>&1

${exclude3+"$exclude3"}erweitert sich zu nichts, wenn $exclude3es nicht gesetzt ist, und zu "$exclude3", wenn es gesetzt ist.

(und ähnlich für die anderen Variablen, die möglicherweise nicht gesetzt sind.)

Beachten Sie, dass es einen Unterschied zwischen einer nicht gesetzten Variablen und einer Variablen gibt, die auf die leere Zeichenfolge festgelegt ist. Daher sollten Sie diese verwenden

unset exclude3

anstatt

exclude3=''
Uwe
quelle
1
Netter Trick, aber wenn $ exclude3 nicht gesetzt ist, gibt Bash einen Fehler aus, da 'set -u' als Sicherheitsmaßnahme verwendet wird.
Gregory MOUSSAT
Es funktioniert so lange, wie Sie nur testen, ob die Variable gesetzt ist oder nicht. Das Testen zählt nicht als Versuch, eine Parametererweiterung für die Variable durchzuführen .
Uwe
1
Übrigens gibt es eine verwandte Konstruktion, die nicht gesetzte und leere Variablen auf die gleiche Weise behandelt, nämlich ${exclude3:+"$exclude3"}(beachten Sie den Doppelpunkt).
Uwe
7

Verwenden Sie ein Array, da Sie in Bash arbeiten .

excludes=()
excludes+=('--exclude=/path/*')

tar -czf backup.tgz "${excludes[@]}"

Wenn Sie einen optionalen Eintrag in einer Variablen haben, fügen Sie ihn in einer Bedingung hinzu.

if [[ -n $exclude_or_empty ]]; then excludes+=("$exclude_or_empty"); fi
Gilles 'SO - hör auf böse zu sein'
quelle
1

Dies funktioniert für mich in Bash unter Ubuntu, aber ich habe keine Ahnung, ob es POSIX-kompatibel / kompatibel ist:

tar -czf backup.tgz \
$(if "$exclude1" != ""); then echo "$exclude1"; fi
$(if "$exclude2" != ""); then echo "$exclude3"; fi
$(if "$exclude3" != ""); then echo "$exclude3"; fi
tommy.carstensen
quelle