Comment accéder aux arguments de ligne de commande de l'appelant dans une fonction?

95

J'essaye d'écrire une fonction en bash qui accédera aux arguments de ligne de commande de scripts, mais ils sont remplacés par les arguments positionnels de la fonction. Existe-t-il un moyen pour la fonction d'accéder aux arguments de ligne de commande s'ils ne sont pas passés explicitement?

# 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
la source
3
Je suis un peu confus, vous voulez les arguments sans les passer?
Ravi Vyas
4
Oui, le but est d'obtenir également les arguments de ligne de commande depuis l'intérieur d'une fonction sans les passer en tant qu'arguments fonctionnels. Cela a à voir avec une situation de gestion des erreurs dans laquelle je veux faire une gestion des erreurs basée sur des arguments de ligne de commande indépendamment des arguments passés dans la fonction.
DonGar
Pour votre information, $*est extrêmement bogué - il va changer ./yourScript "first argument" "second argument"à ./yourscript "first" "argument" "second" "argument", ou un changement ./yourscript '*.txt'à quelque chose comme ./yourscript one.txt two.txtmalgré les citations.
Charles Duffy

Réponses:

46

Ma lecture du manuel bash ref dit que ce truc est capturé dans BASH_ARGV, bien qu'il parle beaucoup de "la pile".

#!/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

Enregistrer dans 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
la source
5
Notez que le fait d'itérer le tableau comme cela fait que les arguments sont dans l'ordre inverse de la ligne de commande.
Andrew Backer
93

Si vous voulez avoir vos arguments de style C (tableau d'arguments + nombre d'arguments) vous pouvez utiliser $@et $#.

$#vous donne le nombre d'arguments.
$@vous donne tous les arguments. Vous pouvez transformer cela en un tableau en args=("$@").

Donc par exemple:

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

Notez qu'il ${args[0]}s'agit en fait du 1er argument et non du nom de votre script.

stigi
la source
5
Cela ne répond pas à la question - il s'agit de transmettre les arguments de ligne de commande à une fonction shell.
Cascabel
6
@Jefromi, en fait, il répond parfaitement à la question. Vous pouvez utiliser le argstableau depuis l'intérieur d'une fonction, si vous l'initialisez au préalable comme décrit.
vadipp le
1
Je trouve cela beaucoup plus propre que d'itérer sur les arguments.
Félix Gagnon-Grenier
1
C'est simple et facile. Très bonne réponse. Vous avez posté ceci il y a plus de 7 ans, alors bonjour du futur: juillet 2017
SDsolar
Encore mieux serait de citer comme echo "${args[0]} ${args[1]} ${args[2]}", ou les arguments sont sujets à l'expansion du nom de fichier.
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 $#

Edit: s'il vous plaît voir mon commentaire sur la question

Ravi Vyas
la source
16

Le commentaire de Ravi est essentiellement la réponse. Les fonctions prennent leurs propres arguments. Si vous voulez qu'ils soient identiques aux arguments de ligne de commande, vous devez les transmettre. Sinon, vous appelez clairement une fonction sans arguments.

Cela dit, vous pouvez, si vous le souhaitez, stocker les arguments de ligne de commande dans un tableau global à utiliser dans d'autres fonctions:

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

commandline_args=("$@")

my_function

Vous devez accéder aux arguments de ligne de commande par la commandline_argsvariable non $@, $1, $2, etc., mais ils sont disponibles. Je ne connais aucun moyen d'assigner directement le tableau d'arguments, mais si quelqu'un en connaît un, veuillez m'éclairer!

Notez également la façon dont j'ai utilisé et cité $@- c'est ainsi que vous vous assurez que les caractères spéciaux (espaces blancs) ne sont pas salis.

Cascabel
la source
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
la source
2

On peut aussi le faire comme ça

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

Maintenant, appelez votre script comme

./function_test.sh argument1 argument2
Vikash Singh
la source
function print() {est un amalgame entre deux formes de déclaration de fonction différentes - function print {, qui est la syntaxe ksh héritée que bash prend en charge pour la compatibilité ascendante avec pré-POSIX (c'est-à-dire avant 1991) ksh, et print() {, qui est normalisé POSIX. Pensez à utiliser l'un ou l'autre pour une compatibilité plus large avec d'autres shells; voir aussi wiki.bash-hackers.org/scripting/obsolete
Charles Duffy
1

Vous pouvez utiliser le mot-clé shift (opérateur?) Pour les parcourir. Exemple:

#!/bin/bash
function print()
{
    while [ $# -gt 0 ]
    do
        echo $1;
        shift 1;
    done
}
print $*;
Marin Alcaraz
la source
2
function print() {est un amalgame entre deux formes de déclaration de fonction différentes - function print {, qui est la syntaxe ksh héritée que bash prend en charge pour la compatibilité ascendante avec pré-POSIX (c'est-à-dire avant 1991) ksh, et print() {, qui est normalisé POSIX. Pensez à utiliser l'un ou l'autre pour une compatibilité plus large avec d'autres shells; voir aussi wiki.bash-hackers.org/scripting/obsolete
Charles Duffy
1

Ma solution:

Créez un script de fonction appelé plus tôt que toutes les autres fonctions sans lui passer d'arguments, comme ceci:

! / bin / bash

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

Après cela, vous pouvez appeler init et utiliser la variable ORIGOPT au besoin, en plus, j'attribue toujours une nouvelle variable et copie le contenu d'ORIGOPT dans mes nouvelles fonctions, de cette façon vous pouvez vous assurer que personne ne la touchera ou changes le.

J'ai ajouté des espaces et des tirets pour faciliter son analyse avec «sed -E» aussi bash ne le passera pas comme référence et fera grandir ORIGOPT à mesure que les fonctions sont appelées avec plus d'arguments.

cabonamigo
la source