1404 votes

Passage de paramètres à une fonction Bash

J'essaie de chercher comment passer des paramètres dans une fonction Bash, mais ce qui apparaît, c'est toujours comment passer un paramètre à partir de la fonction ligne de commande .

Je voudrais passer des paramètres dans mon script. J'ai essayé :

myBackupFunction("..", "...", "xx")

function myBackupFunction($directory, $options, $rootPassword) {
     ...
}

Mais la syntaxe n'est pas correcte. Comment puis-je passer un paramètre à ma fonction ?

12 votes

"...mais ce qui revient toujours, c'est comment passer un paramètre depuis la ligne de commande" - Oui ! C'est parce que les scripts Bash sont fondamentalement des séquences de lignes de commande - invoquez une fonction dans un script Bash exactement comme si c'était une commande sur la ligne de commande ! :-) Votre appel serait myBackupFunction ".." "..." "xx" ; pas de parenthèses, pas de virgules.

4 votes

La contrepartie de cette question : valeur de retour d'une fonction bash

0 votes

2165voto

dogbane Points 85749

Il existe deux façons typiques de déclarer une fonction. Je préfère la deuxième approche.

function function_name {
   command...
} 

ou

function_name () {
   command...
} 

Pour appeler une fonction avec des arguments :

function_name "$arg1" "$arg2"

La fonction fait référence aux arguments passés par leur position (et non par leur nom), c'est-à-dire que $1 , $2 et ainsi de suite. $0 est le nom du script lui-même.

Exemple :

function_name () {
   echo "Parameter #1 is $1"
}

De plus, vous devez appeler votre fonction après il est déclaré.

#!/usr/bin/env sh

foo 1  # this will fail because foo has not been declared yet.

foo() {
    echo "Parameter #1 is $1"
}

foo 2 # this will work.

Sortie :

./myScript.sh: line 2: foo: command not found
Parameter #1 is 2

Référence : Guide avancé des scripts Bash .

2 votes

Quand j'écris function name(){} Je reçois une erreur à propos du '('. Mais lorsque j'écris name(){} cela fonctionne. Vous avez des idées ?

5 votes

Vous avez oublié les espaces, essayez function name() {} . Peut-être avec une "entrée" avant {}

32 votes

Bonne réponse. Mes deux centimes : pour les constructions shell qui résident dans un fichier dont on extrait la source (en pointillé) quand on en a besoin, je préfère utiliser l'attribut function mot-clé et le site () . Mon objectif (dans un fichier, pas en ligne de commande) est d'accroître la clarté, et non de réduire le nombre de caractères tapés, à savoir, function myBackupFunction() compound-statement .

160voto

Anthony Rutledge Points 280

La connaissance des langages de programmation de haut niveau (C/C++, Java, PHP, Python, Perl, etc.) laisse penser au profane que les fonctions du Bourne Again Shell (Bash) devraient fonctionner comme dans ces autres langages.

Au lieu de cela, Les fonctions Bash fonctionnent comme des commandes de l'interpréteur de commandes et s'attendent à ce que des arguments leur soient passés de la même manière que l'on passe une option à une commande de l'interpréteur de commandes (par ex. ls -l ). En effet, arguments de fonction dans Bash sont traités comme paramètres de position ( $1, $2..$9, ${10}, ${11} et ainsi de suite). Ce n'est pas une surprise si l'on considère que getopts travaux. N'utilisez pas de parenthèses pour appeler une fonction en Bash.


( Note : Je suis en train de travailler sur OpenSolaris pour le moment).

# Bash style declaration for all you PHP/JavaScript junkies. :-)
# $1 is the directory to archive
# $2 is the name of the tar and zipped file when all is done.
function backupWebRoot ()
{
    tar -cvf - "$1" | zip -n .jpg:.gif:.png "$2" - 2>> $errorlog &&
        echo -e "\nTarball created!\n"
}

# sh style declaration for the purist in you. ;-)
# $1 is the directory to archive
# $2 is the name of the tar and zipped file when all is done.
backupWebRoot ()
{
    tar -cvf - "$1" | zip -n .jpg:.gif:.png "$2" - 2>> $errorlog &&
        echo -e "\nTarball created!\n"
}

# In the actual shell script
# $0               $1            $2

backupWebRoot ~/public/www/ webSite.tar.zip

Utiliser des noms pour les variables ? Il suffit de faire quelque chose comme ça.

local filename=$1 # The keyword declare can be used, but local is semantically more specific.

Faites attention, cependant. Si l'argument d'une fonction contient un espace, vous pouvez faire ceci à la place ! Autrement, $1 pourrait ne pas être ce que vous pensez.

local filename="$1" # Just to be on the safe side. Although, if $1 was an integer, then what? Is that even possible? Humm.

Vous voulez passer un tableau à une fonction ?

callingSomeFunction "${someArray[@]}" # Expands to all array elements.

À l'intérieur de la fonction, traitez les arguments comme ceci.

function callingSomeFunction ()
{
    for value in "$@" # You want to use "$@" here, not "$*" !!!!!
    do
        :
    done
}

Vous avez besoin de transmettre une valeur et un tableau, mais vous devez toujours utiliser "$@" dans la fonction ?

function linearSearch ()
{
    local myVar="$1"

    shift 1 # Removes $1 from the parameter list

    for value in "$@" # Represents the remaining parameters.
    do
        if [[ $value == $myVar ]]
        then
            echo -e "Found it!\t... after a while."
            return 0
        fi
    done

    return 1
}

linearSearch $someStringValue "${someArray[@]}"

0 votes

Le dernier exemple affiché ne fonctionne pas, pour autant que je puisse en juger. J'ai essayé de l'exécuter sur bash v5+ et il me renvoie juste le tableau complet dans la boucle au lieu de chaque élément

1 votes

Après avoir testé à nouveau, j'ai trouvé que c'était mon erreur car je déclarais le tableau en ligne au lieu de le déclarer avant

3 votes

@iomv Néanmoins, il faut faire attention au problème de la "référence circulaire à une variable". Quel que soit le nom sous lequel vous déclarez le tableau à l'intérieur de la fonction, ne donnez PAS le même nom à l'argument du tableau dans le contexte d'appel ou le code client. Remarquez que j'ai modifié le dernier exemple pour aider les gens à éviter le problème de la "référence circulaire". Bien vu, même si vous avez fait une erreur de votre côté :-)

83voto

NIXin Points 44

Si vous préférez les paramètres nommés, il est possible (avec quelques astuces) de passer des paramètres nommés aux fonctions (cela permet également de passer des tableaux et des références).

La méthode que j'ai développée vous permet de définir des paramètres nommés passés à une fonction comme ceci :

function example { args : string firstName , string lastName , integer age } {
  echo "My name is ${firstName} ${lastName} and I am ${age} years old."
}

Vous pouvez aussi annoter les arguments comme étant @required ou @readonly, créer des arguments ...rest, créer des tableaux à partir d'arguments séquentiels (en utilisant par exemple string[4] ) et, éventuellement, de lister les arguments sur plusieurs lignes :

function example {
  args
    : @required string firstName
    : string lastName
    : integer age
    : string[] ...favoriteHobbies

  echo "My name is ${firstName} ${lastName} and I am ${age} years old."
  echo "My favorite hobbies include: ${favoriteHobbies[*]}"
}

En d'autres termes, non seulement vous pouvez appeler vos paramètres par leur nom (ce qui rend le noyau plus lisible), mais vous pouvez également passer des tableaux (et des références à des variables - cette fonctionnalité ne fonctionne toutefois que dans Bash 4.3) ! De plus, les variables mappées sont toutes dans la portée locale, tout comme les variables $1 (et autres).

Le code qui permet ce fonctionnement est assez léger et fonctionne à la fois dans Bash 3 et Bash 4 (ce sont les seules versions avec lesquelles je l'ai testé). Si vous êtes intéressé par d'autres astuces de ce genre qui rendent le développement avec Bash plus agréable et plus facile, vous pouvez jeter un coup d'oeil à mon Cadre Bash Infinity le code ci-dessous est disponible comme l'une de ses fonctionnalités.

shopt -s expand_aliases

function assignTrap {
  local evalString
  local -i paramIndex=${__paramIndex-0}
  local initialCommand="${1-}"

  if [[ "$initialCommand" != ":" ]]
  then
    echo "trap - DEBUG; eval \"${__previousTrap}\"; unset __previousTrap; unset __paramIndex;"
    return
  fi

  while [[ "${1-}" == "," || "${1-}" == "${initialCommand}" ]] || [[ "${#@}" -gt 0 && "$paramIndex" -eq 0 ]]
  do
    shift # First colon ":" or next parameter's comma ","
    paramIndex+=1
    local -a decorators=()
    while [[ "${1-}" == "@"* ]]
    do
      decorators+=( "$1" )
      shift
    done

    local declaration=
    local wrapLeft='"'
    local wrapRight='"'
    local nextType="$1"
    local length=1

    case ${nextType} in
      string | boolean) declaration="local " ;;
      integer) declaration="local -i" ;;
      reference) declaration="local -n" ;;
      arrayDeclaration) declaration="local -a"; wrapLeft= ; wrapRight= ;;
      assocDeclaration) declaration="local -A"; wrapLeft= ; wrapRight= ;;
      "string["*"]") declaration="local -a"; length="${nextType//[a-z\[\]]}" ;;
      "integer["*"]") declaration="local -ai"; length="${nextType//[a-z\[\]]}" ;;
    esac

    if [[ "${declaration}" != "" ]]
    then
      shift
      local nextName="$1"

      for decorator in "${decorators[@]}"
      do
        case ${decorator} in
          @readonly) declaration+="r" ;;
          @required) evalString+="[[ ! -z \$${paramIndex} ]] || echo \"Parameter '$nextName' ($nextType) is marked as required by '${FUNCNAME[1]}' function.\"; " >&2 ;;
          @global) declaration+="g" ;;
        esac
      done

      local paramRange="$paramIndex"

      if [[ -z "$length" ]]
      then
        # ...rest
        paramRange="{@:$paramIndex}"
        # trim leading ...
        nextName="${nextName//\./}"
        if [[ "${#@}" -gt 1 ]]
        then
          echo "Unexpected arguments after a rest array ($nextName) in '${FUNCNAME[1]}' function." >&2
        fi
      elif [[ "$length" -gt 1 ]]
      then
        paramRange="{@:$paramIndex:$length}"
        paramIndex+=$((length - 1))
      fi

      evalString+="${declaration} ${nextName}=${wrapLeft}\$${paramRange}${wrapRight}; "

      # Continue to the next parameter:
      shift
    fi
  done
  echo "${evalString} local -i __paramIndex=${paramIndex};"
}

alias args='local __previousTrap=$(trap -p DEBUG); trap "eval \"\$(assignTrap \$BASH_COMMAND)\";" DEBUG;'

0 votes

Quels sont les @var , @reference , @params variables ? Que dois-je rechercher sur Internet pour en savoir plus ?

1 votes

Salut @niieani quand j'essaie de créer une fonction bash sous la forme que vous utilisez dans votre réponse, il me dit que je dois installer ucommon utils depuis apt. Est-ce ainsi que votre bash script fonctionne ? Est-ce que je fais cela correctement ? Si je comprends bien, vous ou quelqu'un d'autre a fondamentalement construit le programme ucommon util pour permettre une extension de Bash, correct ?

0 votes

@DavidA.French non, cela ne devrait pas arriver. Il n'y a pas de relation entre ucommon et mon code. Il est possible que vous ayez installé un outil qui cause le problème que vous avez mentionné, mais je n'ai aucune idée de ce que cela peut être.

50voto

nbt Points 15965

Laissez tomber les parenthèses et les virgules :

 myBackupFunction ".." "..." "xx"

Et la fonction devrait ressembler à ça :

function myBackupFunction() {
    # Here $1 is the first parameter, $2 the second, etc.
}

19voto

Adiii Points 5246

Un exemple simple qui effacera à la fois pendant l'exécution de script ou à l'intérieur de script en appelant une fonction.

#!/bin/bash
echo "parameterized function example"
function print_param_value(){
    value1="${1}" # $1 represent first argument
    value2="${2}" # $2 represent second argument
    echo "param 1 is  ${value1}" # As string
    echo "param 2 is ${value2}"
    sum=$(($value1+$value2)) # Process them as number
    echo "The sum of two value is ${sum}"
}
print_param_value "6" "4" # Space-separated value
# You can also pass parameters during executing the script
print_param_value "$1" "$2" # Parameter $1 and $2 during execution

# Suppose our script name is "param_example".
# Call it like this:
#
# ./param_example 5 5
#
# Now the parameters will be $1=5 and $2=5

0 votes

Pour ce que cela vaut, je suis également ce formulaire, mais je me demande s'il y a un avantage supplémentaire ?

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X