Ich möchte params an ein Bash-Skript im dd-Stil übergeben. Grundsätzlich möchte ich
./script a=1 b=43
die gleiche Wirkung haben wie
a=1 b=43 ./script
Ich dachte, ich könnte dies erreichen mit:
for arg in "$@"; do
eval "$arg";
done
Was ist ein guter Weg, um sicherzustellen, dass der eval
sicher ist, dh dass "$arg"
eine statische (keine Code-Ausführung), variable Zuweisung entspricht?
Oder gibt es einen besseren Weg, dies zu tun? (Ich möchte das einfach halten).
=
Trennzeichen analysieren und die Zuweisung mit einem sorgfältiger konstruierten Eval durchführen. Nur zur Sicherheit, für den privaten Gebrauch, würde ich es tun, wie Sie es getan haben.Antworten:
Sie können dies in bash ohne eval (und ohne künstliche Flucht) tun:
Bearbeiten: Auf der Grundlage eines Kommentars von Stéphane Chazelas habe ich der Deklaration Flags hinzugefügt, um zu vermeiden, dass die zugewiesene Variable bereits als Array- oder Ganzzahlvariable deklariert ist. In diesem Fall wird eine Reihe von Fällen vermieden, in denen
declare
der Wertteil deskey=val
Arguments ausgewertet wird . (+a
Dies führt zu einem Fehler, wenn die zu setzende Variable beispielsweise bereits als Array-Variable deklariert ist.) Alle diese Sicherheitsanfälligkeiten beziehen sich auf die Verwendung dieser Syntax zum Neuzuweisen vorhandener (Array- oder Ganzzahl-) Variablen, die normalerweise allgemein bekannt sind Shell-Variablen.Tatsächlich ist dies nur eine Instanz einer Klasse von Injektionsangriffen, die sich gleichermaßen auf
eval
Lösungen auswirkt : Es wäre wirklich viel besser, nur bekannte Argumentnamen zuzulassen, als blind festzulegen, welche Variable zufällig in der Befehlszeile vorhanden war. (Überlegen Sie, was passiert, wenn die BefehlszeilePATH
z. B. festgelegt wird. Oder setzen Sie sie zurückPS1
, um einige Auswertungen einzuschließen, die bei der nächsten Eingabeaufforderung angezeigt werden.)Anstatt bash-Variablen zu verwenden, würde ich lieber ein assoziatives Array benannter Argumente verwenden, das sowohl einfacher festzulegen als auch viel sicherer ist. Alternativ können tatsächliche Bash-Variablen festgelegt werden, jedoch nur, wenn sich ihre Namen in einem assoziativen Array legitimer Argumente befinden.
Als Beispiel für den letzteren Ansatz:
quelle
^[[:alpha:]_][[:alnum:]_]*=
:?foo=
ist die einzige Möglichkeit, foo auf den leeren String zu setzen, daher sollte dies erlaubt sein (IMHO). Ich habe die Klammern angebracht, danke.declare
ist ungefähr so gefährlich wieeval
(man kann sogar noch Schlimmeres sagen, da es nicht so offensichtlich ist, dass es so gefährlich ist). Versuchen Sie zum Beispiel, das mit'DIRSTACK=($(echo rm -rf ~))'
als Argument aufzurufen .+x
ist "nicht-x
".-a
= indiziertes Array,-A
= assoziatives Array,-i
= ganzzahlige Variable. Also: kein indiziertes Array, kein assoziatives Array, keine ganze Zahl.bash
möglicherweise hinzufügen müssen+c
, um zusammengesetzte Variablen+F
zu deaktivieren oder um schwebende Variablen zu deaktivieren. Ich würde immer noch verwenden,eval
wo Sie wissen, wo Sie stehen.Ein POSIX ein (Sets
$<prefix>var
statt$var
zu vermeiden Probleme mit speziellen Variablen wieIFS
/PATH
...):Genannt als
myscript x=1 PATH=/tmp/evil %=3 blah '=foo' 1=2
, würde es zuweisen:quelle
Die Lösung von lcd047 wurde mit einem fest codierten
DD_OPT_
Präfix überarbeitet :frostschutz verdient die Anerkennung für die meisten Umgestaltungen .
Ich habe dies in eine Quelldatei mit folgender globalen Variable eingefügt:
eval "$DD_OPTS_PARSE"
macht die ganze Magie.Eine Version für Funktionen wäre:
DD_OPTS_PARSE_LOCAL="${PARSE_AND_REMOVE_DD_OPTS/DD_OPT_/local DD_OPT_}"
In Benutzung:
eval "$DD_OPTS_PARSE_LOCAL"
Ich habe ein Repo daraus gemacht, komplett mit Tests und einer README.md. Dann habe ich dies in einem Github API CLI Wrapper Ich schrieb, und ich verwendet , um die gleiche Wrapper für das Einrichten eines Github Klon des Repo (Bootstrapping ist Spaß).
Sichere Parameterübergabe für Bash-Skripte in nur einer Zeile. Genießen. :)
quelle
*=*
und aufhören, key / val zu ersetzen, wenn es kein = gibt. (seit du umgestaltet hast): Pkey
undval
, und nur schreibeneval "${1%%=*}"=\${1#*=}
. Aber das ist so ziemlich so weit wie es geht,eval "$1"
denn in @ ricideclare "$arg"
wird es offensichtlich nicht funktionieren. Achten Sie auch darauf, Dinge wiePATH
oder einzustellenPS1
.case
. Wahrscheinlich ist es egal, aber nur für den Fall, dass Sie nicht wussten ...Die klassische Bourne-Shell wird unterstützt, und die Bash- und Korn-Shell wird weiterhin unterstützt
-k
. Wenn dies derdd
Fall ist, werden alle " ähnlichen" Befehlsoptionen an einer beliebigen Stelle in der Befehlszeile automatisch in Umgebungsvariablen konvertiert, die an den Befehl übergeben werden:Es ist etwas schwieriger, davon zu überzeugen, dass es sich um Umgebungsvariablen handelt. Laufen dies funktioniert für mich:
Der erste
env | grep
zeigt keine Umgebungsvariablen mit einem einzelnen Kleinbuchstaben. Die erstebash
zeigt, dass keine Argumente an das Skript übergeben wurden, das über ausgeführt wurde-c
, und die Umgebung enthält die drei Variablen mit einem Buchstaben. Der Befehlset +k
bricht den-k
Befehl ab und zeigt an, dass demselben Befehl jetzt Argumente übergeben wurden. (Diea=1
wurde wie$0
für das Drehbuch behandelt; das können Sie auch durch entsprechendes Echo beweisen.)Dies führt zu dem, was die Frage stellt - dass das Tippen
./script.sh a=1 b=2
dasselbe sein sollte wie das Tippena=1 b=2 ./script.sh
.Seien Sie sich bewusst, dass Sie auf Probleme stoßen, wenn Sie Tricks wie diese in einem Skript ausprobieren:
Das
"$@"
wird wörtlich behandelt; Es wird nicht erneut analysiert, um Variablen im Zuweisungsstil zu finden (sowohl inbash
als auchksh
). Ich habe es versucht:und nur die
already_invoked_with_minus_k
Umgebungsvariable wird imexec
'd-Skript festgelegt.quelle
Mein Versuch:
Es funktioniert mit (fast) beliebigem Müll auf der RHS:
quelle
shift
stattshift 1
). Ansonsten danke!Vor einiger Zeit habe ich mich
alias
für diese Art von Arbeit entschieden. Hier ist eine andere Antwort von mir:Es kann jedoch manchmal möglich sein, die Auswertung und Ausführung solcher Anweisungen zu trennen. Zum Beispiel
alias
kann ein Befehl vorab ausgewertet werden. Im folgenden Beispiel wird die Variablendefinition in einem Alias gespeichert, der nur dann erfolgreich deklariert werden kann, wenn die$var
auszuwertende Variable keine Bytes enthält, die nicht mit ASCII-Alphanumerik oder _ übereinstimmen.eval
wird hier verwendet, um das Aufrufen des Neuenalias
aus einem Kontext mit dem angegebenen Variablennamen heraus zu handhaben - nicht für die genaue Zuweisung. Undeval
wird überhaupt nur aufgerufen, wenn die vorherigealias
Definition erfolgreich ist, und obwohl ich weiß, dass viele verschiedene Implementierungen viele verschiedene Arten von Werten für Aliasnamen akzeptieren, habe ich noch keine Shell gefunden, die eine vollständig leere akzeptiert .Die Definition innerhalb des Alias ist jedoch für
_$var
, und dies soll sicherstellen, dass keine signifikanten Umgebungswerte überschrieben werden. Ich kenne keine nennenswerten Umgebungswerte, die mit einem _ beginnen, und dies ist normalerweise eine sichere Option für halbprivate Deklarationen.Wenn die Aliasdefinition erfolgreich ist, wird ein Alias mit dem Namen des
$var
Werts deklariert . Undeval
ruft das nur auf,alias
wenn es auch nicht mit einer Zahl beginnt - sonsteval
bekommt man nur ein Nullargument. Wenn also beide Bedingungen erfüllt sind, werden dieeval
Aufrufealias
und die in der gesicherte Variablendefinition durchgeführtalias
, wonach der neue Alias sofort aus der Hash-Tabelle entfernt wird.alias
In diesem Zusammenhang ist es auch nützlich, dass Sie Ihre Arbeit drucken können.alias
gibt eine doppelt zitierte Safe-for-Shell-Wiederausführungsanweisung aus , wenn Sie dazu aufgefordert werden.AUSGABE
quelle