Pregunta Pasar parámetros a una función Bash


Intento buscar cómo pasar parámetros en una función de Bash, pero lo que surge siempre es cómo pasar el parámetro desde la línea de comando.

Me gustaría pasar parámetros dentro de mi script. Lo intenté:

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

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

Pero la sintaxis no es correcta, ¿cómo pasar un parámetro a mi función?


672
2018-06-02 08:35


origen


Respuestas:


Hay dos formas típicas de declarar una función. Prefiero el segundo enfoque.

function function_name {
   command...
} 

o

function_name () {
   command...
} 

Para llamar a una función con argumentos:

function_name "$arg1" "$arg2"

La función se refiere a argumentos pasados ​​por su posición (no por nombre), es decir $ 1, $ 2, etc. $ 0 es el nombre del script en sí.

Ejemplo:

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

Además, debes llamar a tu función después es declarado.

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

Salida:

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

Referencia: Guía Avanzada de Bash-Scripting.


1173
2018-06-02 08:57



El conocimiento de lenguajes de programación de alto nivel (C / C ++ / Java / PHP / Python / Perl ...) sugeriría al profano que las funciones de bash deberían funcionar como lo hacen en esos otros lenguajes. En lugar, las funciones bash funcionan como comandos de shell y esperan que se les pasen argumentos de la misma manera que se podría pasar una opción a un comando de shell (ls -l). En efecto, argumentos de función en bash son tratados como parámetros posicionales ($1, $2..$9, ${10}, ${11}, y así). Esto no es sorprendente teniendo en cuenta cómo getopts trabajos. Los paréntesis no están obligados a llamar a una función en bash.


(Nota: Estoy trabajando en Open Solaris por el momento).

# 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

42
2018-05-10 20:30



No te pierdas los paréntesis y las comas:

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

y la función debería verse así:

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

25
2018-06-02 08:36



Si prefiere parámetros con nombre, es posible (con algunos trucos) pasar parámetros con nombre a funciones (también permite pasar matrices y referencias).

El método que desarrollé te permite definir parámetros con nombre pasados ​​a una función como esta:

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

También puede anotar argumentos como @required o @readonly, crear ... argumentos en reposo, crear matrices a partir de argumentos secuenciales (usando p. Ej. string[4]) y opcionalmente enumera los argumentos en múltiples líneas:

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 otras palabras, no solo puede llamar sus parámetros por sus nombres (lo que representa un núcleo más legible), sino que puede pasar matrices (y referencias a variables; ¡esta característica solo funciona en bash 4.3)! Además, las variables asignadas están todas en el ámbito local, al igual que $ 1 (y otros).

El código que hace este trabajo es bastante ligero y funciona tanto en bash 3 como en bash 4 (estas son las únicas versiones con las que lo he probado). Si estás interesado en más trucos como este que hacen que desarrollar con bash sea mucho más agradable y fácil, puedes echar un vistazo a mi Bash Infinity Framework, el siguiente código está disponible como una de sus funcionalidades.

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 param:
      shift
    fi
  done
  echo "${evalString} local -i __paramIndex=${paramIndex};"
}

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

23
2018-05-04 15:23



Espero que este ejemplo pueda ayudarte. Toma dos números del usuario, los alimenta a la función llamada add (en la última línea del código), y add los resumirá e imprimirá.

#!/bin/bash

read -p "Enter the first  value: " x
read -p "Enter the second value: " y

add(){
    arg1=$1 #arg1 gets to be the first  assigned argument (note there are no spaces)
    arg2=$2 #arg2 gets to be the second assigned argument (note there are no spaces)

    echo $(($arg1 + $arg2))
}

add x y #feeding the arguments

5
2017-10-24 06:49



Pensé en conectarme con la mención de otra forma de pasar los parámetros nombrados a bash ... pasando por referencia. Esto es compatible desde bash 4.0

#!/bin/bash
function myBackupFunction(){ # directory options destination filename
local directory="$1" options="$2" destination="$3" filename="$4";
  echo "tar cz ${!options} ${!directory} | ssh root@backupserver \"cat > /mnt/${!destination}/${!filename}.tgz\"";
}

declare -A backup=([directory]=".." [options]="..." [destination]="backups" [filename]="backup" );

myBackupFunction backup[directory] backup[options] backup[destination] backup[filename];

Una sintaxis alternativa para bash 4.3 es usar una nameref

Aunque el nameref es mucho más conveniente porque elimina las referencias de forma directa, algunas distribuciones más antiguas todavía envían un versión antigua así que no lo recomendaré todavía.


3
2018-02-20 20:19



Un ejemplo simple que se borrará durante la ejecución del script o dentro del script mientras se llama a una función.

#!/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 sparted value
#you can also pass paramter durign executing script
print_param_value "$1" "$2" #parameter $1 and $2 during executing

#suppose our script name is param_example
# call like this 
# ./param_example 5 5
# now the param will be $1=5 and $2=5

1
2017-11-23 13:12