wie verschiebt man einen Parameter und wirft ihn vollständig aus den Argumenten ls?

wie verschiebt man einen Parameter und wirft ihn vollständig aus den Argumenten ls?

Ich habe ein Skript, das N Parameter abruft. Es analysiert sie zuerst (extrahiert einen bestimmten Wert X) und ruft dann ein anderes Programm mit diesem Wert auf:

function main() {
    parse "$@"
    run "$@"
}
main "$@"

Ich möchte am Anfang der Argumentliste einen optionalen Parameter hinzufügen (Parameter zum Festlegen der von mir ausgeführten Python-Version). Daher habe ich Folgendes zur Analysefunktion hinzugefügt:

if [ "$1" = '2' ] || [ "$1" = '3' ]; then version=$1 && shift; else version=2; fi

Nachdem die Analyse beendet ist, stecke ich jedoch fest, da dies shiftdie Ausführungsfunktion nicht beeinflusst. Wie kann ich dies tun, ohne den Wert des ersten Werts erneut zu überprüfen (was den gesamten Zweck einer Analysefunktion zunichte machen würde)?

Antwort1

Der Umfang jeder Shell-Funktion (sowie der Umfang des Top-Level-Codes im Skript) hat seine eigenePositionsparameterund kann nur direkt auf sich selbst zugreifen. Die sauberste Lösung besteht darin, die Werte der Positionsparameter, an denen Sie interessiert sind, ineinAnordnung. Sie können dieses Array dann in mehreren Funktionsbereichen lesen und auch ändern.

Beispielsweise könnte dieser Code am Anfang Ihres Skripts erscheinen:

declare -a args=("$@")
  • Geben Sie dem Array einen beliebigen Namen. Es muss nicht heißen args.
  • Sie können es sogar weglassen declare -a, wenn Sie möchten.
  • Es muss nicht unbedingt am Anfang erscheinen. Es muss nurlaufenbevor der Code ausgeführt wird, der darauf zugreift args. Es könnte sogar unter den Definitionen von Shell-Funktionen erscheinen, die verwenden args. Der Übersichtlichkeit halber schlage ich vor, es irgendwo am Anfang zu platzieren.

Dann können Sie das argsArray von mehreren Funktionen aus bearbeiten. Sie müssen es nicht an die Funktionen übergeben; diese können bereits darauf zugreifen. Wenn Code in einer Shell-Funktion den Inhalt ändert argsund dann zurückkehrt, kann Code im Aufrufer die Änderungen beobachten.

Positionsparameter in Shells im Bourne-Stil, einschließlich Bash, verwenden eine 1-basierte Indizierung. (Das liegt daran , dass $0, das zum Programmnamen erweitert wird, technisch gesehen kein Positionsparameter ist und sich in Funktionsbereichen nicht ändert.) Arrays in Bash verwenden jedoch eine 0-basierte Indizierung. Nach stimmt also args=("$@"), mit , mit , mit , mit usw. überein. stimmt immer noch wie erwartet überein.$1${args[0]}$2${args[1]}$3${args[2]}$@${args[@]}

Ich habe sie der Lesbarkeit halber so ohne Anführungszeichen geschrieben. Natürlich werden Sie Erweiterungen, die Ihr argsArray betreffen, fast immer in doppelte Anführungszeichen setzen wollen, so wie Sie Erweiterungen, die Positionsparameter betreffen, fast immer in doppelte Anführungszeichen setzen wollen.

Wenn Sie sich für diesen Ansatz entscheiden, dann anstelle von:

shift

Sie würden schreiben:

args=("${args[@]:1}")

Wenn Sie mit Arrays in Bash noch nicht vertraut sind, sollten Sie einen Blick aufder entsprechende Teil des Bash-Referenzhandbuchs. Vielleicht möchten Sie auch interaktiv experimentieren. Zum Beispiel:

ek@Cord:~$ args=('foo bar' 'baz quux' 'ham spam')
ek@Cord:~$ printf '[%s]\n' "${args[@]}"
[foo bar]
[baz quux]
[ham spam]
ek@Cord:~$ printf '[%s]\n' "${args[@]:1}"
[baz quux]
[ham spam]

Der Code entspricht

if [ "$1" = 2 ] || [ "$1" = 3 ]; then
    version="$1"
    shift
else
    version=2
fi

wäre:

if [ "${args[0]}" = 2 ] || [ "${args[0]}" = 3 ]; then
    version="${args[0]}"
    args=("${args[@]:1}")
else
    version=2
fi

Die Verwendung eines Arrays ist syntaktisch umständlicher, aber auch flexibler.

Andererseits, da Sie den größten Teil des Codes Ihres Skripts runohnehin in einer Funktion und ihren aufgerufenen Elementen organisiert zu haben scheinen, könnten Sie die Alternative in Betracht ziehen, alle speziellen Befehlszeilenargumente zu analysieren.VorRufen Sie runaußerhalb einer Shell-Funktion auf und rufen Sie dann run "$@"wie bisher auf.

Es gibt Programmiersprachen, deren Kulturen eine starke Ethik haben, fast alles in kleine (oder so kleine), in sich geschlossene Funktionen zu packen. Bash ist keine solche Sprache, und die begrenzten Möglichkeiten, komplexe Daten aus einer Shell-Funktion zurückzugeben, sind einer der Gründe. Sie sollten keine Angst davor haben, Shell-Funktionen zu schreiben, und Sie sollten sogar bereit sein, eine große Anzahl kleiner Shell-Funktionen zu schreiben. Aber ich denke, Sie sollten sich keine Sorgen machen, wenn sich herausstellt, dass die beste Form für Ihr Skript eine andere ist.

Weitere Informationen und einige Alternativen, einschließlich eines seltsamen Ansatzes, bei dem Sie die Ausgabe der Prozesssubstitution als Quelle verwenden, finden Sie unterGilles' AntwortZuPositionsparameter des Funktionsaufrufers.

verwandte Informationen