Ich habe eine Bash-Funktion, um das $PATH
wie folgt einzustellen -
assign-path()
{
str=$1
# if the $PATH is empty, assign it directly.
if [ -z $PATH ]; then
PATH=$str;
# if the $PATH does not contain the substring, append it with ':'.
elif [[ $PATH != *$str* ]]; then
PATH=$PATH:$str;
fi
}
Aber das Problem ist, ich muss unterschiedliche Funktionen für unterschiedliche Variablen schreiben (zum Beispiel eine andere Funktion für $CLASSPATH
Ähnliches assign-classpath()
usw.). Ich konnte keine Möglichkeit finden, Argumente an die Bash-Funktion zu übergeben, damit ich per Referenz darauf zugreifen kann.
Es wäre besser, wenn ich etwas hätte wie -
assign( bigstr, substr )
{
if [ -z bigstr ]; then
bigstr=substr;
elif [[ bigstr != *str* ]]; then
bigstr=bigstr:substr;
fi
}
Irgendeine Idee, wie man so etwas in bash erreicht?
bash
bash-script
Ramgorur
quelle
quelle
assign-path /abc
nicht anhängen/abc
zu PATH , wenn bereits $ PATH enthält/abc/def
,/abcd
,/def/abc
etc. Besonders hinzufügen Sie können nicht ,/bin
wenn PATH bereits enthält/usr/bin
.$PATH
und negieren Test gegen Ihre Argumente wie:add=/bin dir=/usr/bin ; [ -z "${dir%"$add"}" ] || dir="${dir}:${add}"
. In meiner Antwort mache ich es so mit so vielen Argumenten, wie Sie nur verwenden möchtenIFS=:
.$PATH
? und Verzeichnis hinzufügen,$PATH
falls es noch nicht vorhanden ist (unter Super User ).Antworten:
In können
bash
Sie verwenden${!varname}
, um die Variable zu erweitern, auf die durch den Inhalt einer anderen verwiesen wird. Z.B:Von der Manpage:
Sie können auch eine Variable festlegen, auf die durch den Inhalt verwiesen wird (ohne die Gefahren von
eval
)declare
. Z.B:So könnten Sie Ihre Funktion wie folgt schreiben (Vorsicht, wenn Sie sie
declare
in einer Funktion verwenden, müssen Sie angeben,-g
sonst ist die Variable lokal):Und benutze es wie folgt:
Beachten Sie, dass ich auch einen Fehler behoben habe, bei dem, wenn
substr
bereits eine Teilzeichenfolge eines durch Doppelpunkte getrennten Mitgliedsbigstr
, aber kein eigenes Mitglied vorhanden ist, diese nicht hinzugefügt wird. Dies würde beispielsweise das Hinzufügen/bin
zu einerPATH
Variablen ermöglichen, die bereits enthält/usr/bin
. Es verwendet dieextglob
Mengen, um entweder den Anfang / das Ende der Zeichenfolge oder einen Doppelpunkt als irgendetwas anderes abzugleichen. Ohneextglob
wäre die Alternative:quelle
-g
indeclare
ist in der älteren version von bash nicht verfügbar, gibt es eine möglichkeit, diese abwärtskompatibel zu machen?export
, um es in Ihre Umgebung zu stellen (auf die Gefahr hin, etwas Wichtiges zu überschreiben) odereval
(verschiedene Probleme, einschließlich der Sicherheit, wenn Sie nicht vorsichtig sind). Wenneval
Sie es verwenden, sollten Sie in Ordnung sein, wenn Sie es mögeneval "$target=\$substr"
. Wenn Sie das\
allerdings vergessen , wird möglicherweise ein Befehl ausgeführt, wenn der Inhalt von ein Leerzeichen enthältsubstr
.Neu in Bash 4.3 ist die
-n
Option zudeclare
&local
:Das druckt aus
hello, world
.quelle
Mit können Sie
eval
einen Parameter einstellen. Eine Beschreibung dieses Befehls finden Sie hier . Die folgende Verwendung voneval
ist falsch:In Bezug auf die zusätzliche Bewertung
eval
sollten Sie verwendenÜberprüfen Sie die Ergebnisse der Verwendung dieser Funktionen:
Aber Sie können Ihr Ziel ohne die Verwendung von erreichen
eval
. Ich bevorzuge diesen einfacheren Weg.Die folgende Funktion macht die Substitution richtig (hoffe ich)
Überprüfen Sie die folgende Ausgabe
Jetzt können Sie die
augment
Funktion folgendermaßen verwenden, um eine Variable festzulegen:quelle
v='echo "OHNO!" ; var' ; l=val ; eval $v='$l'
- würde vor dem Zuweisen von var "OHNO!" Ausgeben. Sie könnten "$ {v ## * [;" $ IFS "]} = '$ l'", um sicherzustellen, dass die Zeichenfolge nicht zu etwas anderem erweitert werden kann wird nicht bewertet mit =.=
Assignment-Anweisung verwendet wird. Sie können argumentieren, dass mein Skript sein Argument nicht überprüft. Das ist wahr. Ich überprüfe nicht einmal, ob es ein Argument gibt oder ob die Anzahl der Argumente gültig ist. Aber das war beabsichtigt. Der OP kann solche Prüfungen hinzufügen, wenn er möchte.v
(besser seinen Wert) als zweites Argument der Assign-Funktion verwenden möchte . Sein Wert sollte sich also auf der rechten Seite einer Zuordnung befinden. Es ist notwendig, das Argument der Funktion zu zitierenassign
. Ich habe diese Feinheit zu meinem Posting hinzugefügt.Mit ein paar Tricks können Sie benannte Parameter zusammen mit Arrays (getestet in Bash 3 und 4) an Funktionen übergeben.
Mit der von mir entwickelten Methode können Sie auf Parameter zugreifen, die an eine Funktion wie die folgende übergeben wurden:
Mit anderen Worten, Sie können Ihre Parameter nicht nur nach ihrem Namen aufrufen (was einen besser lesbaren Kern ausmacht), sondern Sie können auch Arrays (und Verweise auf Variablen - diese Funktion funktioniert jedoch nur in Bash 4.3) übergeben! Außerdem befinden sich die zugeordneten Variablen alle im lokalen Bereich, ebenso wie $ 1 (und andere).
Der Code, mit dem dies funktioniert, ist ziemlich leicht und funktioniert sowohl in Bash 3 als auch in Bash 4 (dies sind die einzigen Versionen, mit denen ich es getestet habe). Wenn Sie an weiteren Tricks wie diesen interessiert sind, die das Entwickeln mit Bash viel schöner und einfacher machen, können Sie sich mein Bash Infinity Framework ansehen. Der folgende Code wurde zu diesem Zweck entwickelt.
quelle
Passt das
quelle
eval
ist anfällig für die Ausführung beliebiger Befehle.eval
Linien sicherer zu machen ? Normalerweise entscheide ich mich, wenn ich denke, dass ich eval brauche, nicht * sh zu verwenden und stattdessen zu einer anderen Sprache zu wechseln. Wenn Sie dies in Skripten verwenden, um Einträge an einige PATH-ähnliche Variablen anzuhängen, wird es mit Zeichenfolgenkonstanten und nicht mit Benutzereingaben ausgeführt ...eval
sicher tun - aber es erfordert viel Nachdenken. Wenn Sie nur versuchen, auf einen Parameter zu verweisen, möchten Sie Folgendes tun: Aufeval "$1=\"\$2\""
diese Weise wird beimeval's
ersten Durchgang nur 1 US-Dollar ausgewertet und beim zweiten Wert = "2 US-Dollar". Aber Sie müssen noch etwas tun - das ist hier nicht nötig."${1##*[;"$IFS"]}=\"\$2\""
- und selbst das kommt ohne Garantie. Odereval "$(set -- $1 ; shift $(($#-1)) ; echo $1)=\"\$2\""
. Es ist nicht einfach.Benannte Argumente entsprechen einfach nicht der Syntax von Bash. Bash wurde als iterative Verbesserung der Bourne-Shell entwickelt. Als solches muss es sicherstellen, dass bestimmte Dinge so gut wie möglich zwischen den beiden Schalen funktionieren. So ist es nicht gemeint mit insgesamt leichter sein Skript, es ist nur gemeint , besser als Bourne sein , während das zu sichern , wenn Sie ein Skript von einer Bourne - Umgebung übernehmen , um
bash
es so einfach wie möglich ist. Das ist nicht trivial, da viele Shells Bourne immer noch als De-facto-Standard behandeln. Da die Benutzer ihre Skripte so schreiben, dass sie Bourne-kompatibel sind (für diese Portabilität), bleibt der Bedarf bestehen und wird sich wahrscheinlich nie ändern.Sie sind wahrscheinlich besser dran, sich ein anderes Shell-Skript (wie
python
oder so) vollständig anzusehen, wenn es überhaupt machbar ist. Wenn Sie auf die Einschränkungen einer Sprache stoßen, müssen Sie eine neue Sprache verwenden.quelle
bash
. Jetzt werden jedoch besondere Vorkehrungen getroffen. Vollständige Referenzvariablen sind jetzt in verfügbarbash 4.3
- siehe die Antwort von derobert .Mit der Standardsyntax
sh
(würde funktionierenbash
und nicht nur inbash
) können Sie Folgendes tun:Wie für Lösungen mit
bash
‚sdeclare
, dann ist es sicher , solange$1
ein gültigen Variablennamen enthält.quelle
AUF NAMED ARGS:
Dies ist sehr einfach und überhaupt
bash
nicht erforderlich - dies ist das grundlegende POSIX-festgelegte Zuweisungsverhalten über die Parametererweiterung:So führen Sie eine Demo ähnlich wie bei @Graeme durch, jedoch auf tragbare Weise:
Und da mache ich nur,
str=
um sicherzustellen, dass es einen Nullwert hat, weil die Parametererweiterung den eingebauten Schutz gegen Neuzuweisung der Shell-Umgebung inline hat, wenn sie bereits gesetzt ist.LÖSUNG:
Für Ihr spezifisches Problem glaube ich nicht, dass benannte Argumente notwendig sind, obwohl sie zweifellos möglich sind. Verwenden Sie
$IFS
stattdessen:Folgendes bekomme ich, wenn ich es starte:
Beachten Sie, dass nur die Argumente hinzugefügt wurden, die noch nicht vorhanden waren
$PATH
oder die zuvor kamen? Oder sogar, dass es überhaupt mehr als ein Argument gab?$IFS
ist praktisch.quelle
assign
hier sehen kann. Bei Fragen zur Funktionsweise stehe ich gerne zur Verfügung. Übrigens, wenn Sie wirklich benannte Argumente wollen, schauen Sie sich vielleicht meine andere Antwort an, in der ich zeige, wie man eine Funktion deklariert, die für die Argumente einer anderen Funktion benannt ist: unix.stackexchange.com/a/120531/52934Ich kann nichts wie Rubin, Python usw. finden, aber das kommt mir näher
Die Lesbarkeit ist meiner Meinung nach besser, 4 Zeilen reichen nicht aus, um Ihre Parameternamen zu deklarieren. Betrachtet auch moderne Sprachen näher.
quelle
a=$1 b=$2 ...
funktioniert genauso gut.