Wie greife ich auf Befehlszeilenargumente des Aufrufers innerhalb einer Funktion zu?

95

Ich versuche, eine Funktion in bash zu schreiben, die auf die Befehlszeilenargumente der Skripte zugreift, aber sie werden durch die Positionsargumente für die Funktion ersetzt. Gibt es eine Möglichkeit für die Funktion, auf die Befehlszeilenargumente zuzugreifen, wenn diese nicht explizit übergeben werden?

# Demo function
function stuff {
  echo $0 $*
}

# Echo's the name of the script, but no command line arguments
stuff

# Echo's everything I want, but trying to avoid
stuff $*
DonGar
quelle
3
Ich bin irgendwie verwirrt, du willst die Argumente, ohne sie zu überholen?
Ravi Vyas
4
Ja, es geht darum, auch die Befehlszeilenargumente aus einer Funktion heraus abzurufen, ohne sie als funktionale Argumente zu übergeben. Es hat mit einer Fehlerbehandlungssituation zu tun, in der ich eine Fehlerbehandlung basierend auf Befehlszeilenargumenten unabhängig von den an die Funktion übergebenen Argumenten durchführen möchte.
DonGar
FYI, $*ist extrem buggy - es wird sich ändern ./yourScript "first argument" "second argument"zu ./yourscript "first" "argument" "second" "argument", ändern oder ./yourscript '*.txt'zu so etwas wie ./yourscript one.txt two.txttrotz der Zitate.
Charles Duffy

Antworten:

46

Meine Lektüre des Bash-Ref-Handbuchs besagt, dass dieses Zeug in BASH_ARGV erfasst ist, obwohl es viel über "den Stapel" spricht.

#!/bin/bash

function argv {
    for a in ${BASH_ARGV[*]} ; do
      echo -n "$a "
    done
    echo
}

function f {
    echo f $1 $2 $3
    echo -n f ; argv
}

function g {
    echo g $1 $2 $3
    echo -n g; argv
    f
}

f boo bar baz
g goo gar gaz

Speichern in f.sh.

$ ./f.sh arg0 arg1 arg2
f boo bar baz
farg2 arg1 arg0 
g goo gar gaz
garg2 arg1 arg0 
f
farg2 arg1 arg0 
mcarifio
quelle
5
Beachten Sie, dass eine solche Iteration des Arrays dazu führt, dass die Argumente in umgekehrter Reihenfolge von der Befehlszeile aus angezeigt werden.
Andrew Backer
93

Wenn Sie möchten, dass Ihre Argumente den C-Stil haben (Array von Argumenten + Anzahl der Argumente), können Sie $@und verwenden $#.

$#gibt Ihnen die Anzahl der Argumente.
$@gibt Ihnen alle Argumente. Sie können dies durch in ein Array verwandelnargs=("$@") .

Also zum Beispiel:

args=("$@")
echo $# arguments passed
echo ${args[0]} ${args[1]} ${args[2]}

Beachten Sie, dass hier ${args[0]}tatsächlich das erste Argument und nicht der Name Ihres Skripts angegeben ist.

stigi
quelle
5
Damit wird die Frage nicht beantwortet - es geht darum, die Befehlszeilenargumente an eine Shell-Funktion weiterzugeben.
Cascabel
6
@Jefromi, eigentlich beantwortet es die Frage perfekt. Sie können das argsArray innerhalb einer Funktion verwenden, wenn Sie es zuvor wie beschrieben initialisieren.
Vadipp
1
Ich finde das viel sauberer, als über die Argumente zu iterieren.
Félix Gagnon-Grenier
1
Das ist einfach und leicht. Gute Antwort. Sie haben dies vor über 7 Jahren gepostet, also hallo aus der Zukunft: Juli 2017
SDsolar
Noch besser wäre es, wie zu zitieren echo "${args[0]} ${args[1]} ${args[2]}", oder die Argumente unterliegen einer Dateinamenerweiterung.
Benjamin W.
17
#!/usr/bin/env bash

echo name of script is $0
echo first argument is $1
echo second argument is $2
echo seventeenth argument is $17
echo number of arguments is $#

Bearbeiten: siehe meinen Kommentar zur Frage

Ravi Vyas
quelle
16

Ravis Kommentar ist im Wesentlichen die Antwort. Funktionen haben ihre eigenen Argumente. Wenn Sie möchten, dass sie mit den Befehlszeilenargumenten identisch sind, müssen Sie sie übergeben. Andernfalls rufen Sie eindeutig eine Funktion ohne Argumente auf.

Sie können die Befehlszeilenargumente jedoch in einem globalen Array speichern, um sie in anderen Funktionen zu verwenden:

my_function() {
    echo "stored arguments:"
    for arg in "${commandline_args[@]}"; do
        echo "    $arg"
    done
}

commandline_args=("$@")

my_function

Sie müssen über die commandline_argsVariable auf die Befehlszeilenargumente zugreifen , nicht$@ , $1, $2etc., aber sie sind vorhanden. Ich kenne keine Möglichkeit, das Argumentarray direkt zuzuweisen, aber wenn jemand eines kennt, klären Sie mich bitte auf!

Beachten Sie auch die Art und Weise, wie ich verwendet und zitiert habe $@- so stellen Sie sicher, dass Sonderzeichen (Leerzeichen) nicht durcheinander geraten.

Cascabel
quelle
6
# Save the script arguments
SCRIPT_NAME=$0
ARG_1=$1
ARGS_ALL=$*

function stuff {
  # use script args via the variables you saved
  # or the function args via $
  echo $0 $*
} 


# Call the function with arguments
stuff 1 2 3 4
Peter Coulton
quelle
2

Das kann man auch so machen

#!/bin/bash
# script_name function_test.sh
function argument(){
for i in $@;do
    echo $i
done;
}
argument $@

Rufen Sie jetzt Ihr Skript wie auf

./function_test.sh argument1 argument2
Vikash Singh
quelle
function print() {ist ein Amalgam zwischen zwei verschiedenen Funktionsdeklarationsformen - function print {eine Legacy-ksh-Syntax, die bash unterstützt, um die Abwärtskompatibilität mit Pre-POSIX (dh vor 1991) ksh zu gewährleisten, und print() {die POSIX-standardisiert ist. Erwägen Sie die Verwendung des einen oder anderen, um eine bessere Kompatibilität mit anderen Schalen zu gewährleisten. siehe auch wiki.bash-hackers.org/scripting/obsolete
Charles Duffy
1

Sie können das Schlüsselwort shift (Operator?) Verwenden, um sie zu durchlaufen. Beispiel:

#!/bin/bash
function print()
{
    while [ $# -gt 0 ]
    do
        echo $1;
        shift 1;
    done
}
print $*;
Marin Alcaraz
quelle
2
function print() {ist ein Amalgam zwischen zwei verschiedenen Funktionsdeklarationsformen - function print {eine ältere ksh-Syntax, die bash unterstützt, um die Abwärtskompatibilität mit ksh vor POSIX (dh vor 1991) zu gewährleisten, und print() {die POSIX-standardisiert ist. Erwägen Sie die Verwendung des einen oder anderen, um eine bessere Kompatibilität mit anderen Schalen zu gewährleisten. siehe auch wiki.bash-hackers.org/scripting/obsolete
Charles Duffy
1

Meine Lösung:

Erstellen Sie ein Funktionsskript, das früher als alle anderen Funktionen aufgerufen wird, ohne Argumente wie folgt zu übergeben:

! / bin / bash

Funktion init () {ORIGOPT = "- $ @ -"}

Danach können Sie init aufrufen und die ORIGOPT-Variable nach Bedarf verwenden. Als Plus ordne ich immer eine neue Variable zu und kopiere den Inhalt von ORIGOPT in meine neuen Funktionen. Auf diese Weise können Sie sicher sein, dass niemand sie berühren wird oder ändern Sie es.

Ich habe Leerzeichen und Bindestriche hinzugefügt, um das Parsen mit 'sed -E' zu vereinfachen. Bash wird es nicht als Referenz übergeben und ORIGOPT wachsen lassen, wenn Funktionen mit mehr Argumenten aufgerufen werden.

Cabonamigo
quelle