Przekazywanie parametrów do funkcji Bash

Próbuję wyszukać, jak przekazać parametry w funkcji Bash, ale zawsze pojawia się, jak przekazać parametr z linii poleceń.

Chciałbym przekazać parametry w moim skrypcie. Próbowałem:

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

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

Ale składnia nie jest poprawna, jak przekazać parametr do mojej funkcji?

 703
Author: codeforester, 2011-06-02

7 answers

Istnieją dwa typowe sposoby deklarowania funkcji. Wolę drugie podejście.

function function_name {
   command...
} 

Lub

function_name () {
   command...
} 

Wywołanie funkcji z argumentami:

function_name "$arg1" "$arg2"

Funkcja odwołuje się do przekazywanych argumentów przez ich pozycję (nie przez nazwę), czyli $1, $2 itd. $0 to nazwa samego skryptu.

Przykład:

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

Należy również wywołać funkcję po zadeklarowaniu.

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

Wyjście:

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

Indeks: Advanced Bash-Scripting Guide .

 1218
Author: dogbane,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-03-02 19:27:15

Znajomość języków programowania wysokiego poziomu (C / C++ / Java / PHP/Python / Perl ...) sugerowałoby laikowi, że funkcje bash powinny działać tak, jak w tych innych językach. zamiast, funkcje bash działają jak polecenia powłoki i oczekują przekazania im argumentów w taki sam sposób, w jaki można przekazać opcję do polecenia powłoki (ls-l). W efekcie argumenty funkcji w bash są traktowane jako parametry pozycyjne ($1, $2..$9, ${10}, ${11}, i tak dalej). To żadna niespodzianka. biorąc pod uwagę, jak działa getopts. Nawiasy nie są wymagane do wywołania funkcji w bash.


(Notatka: akurat obecnie pracuję nad Open Solarisem.)

# 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
 46
Author: Anthony Rutledge,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-08-07 14:36:42

Jeśli wolisz parametry nazwane, możliwe jest (za pomocą kilku sztuczek) przekazanie nazwanych parametrów funkcjom (umożliwia również przekazywanie tablic i referencji).

Opracowana przeze mnie metoda pozwala na zdefiniowanie nazwanych parametrów przekazywanych do takiej funkcji:

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

Można również dodawać adnotacje jako @ required lub @ readonly, create ...rest arguments, tworzenie tablic z argumentów sekwencyjnych (używając np. string[4]) i opcjonalnie lista argumentów w wielu linie:

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[*]}"
}

Innymi słowy, nie tylko możesz wywoływać swoje parametry po ich nazwach (co stanowi bardziej czytelny rdzeń), ale możesz przekazać tablice (i odniesienia do zmiennych - ta funkcja działa tylko w bash 4.3)! Dodatkowo, wszystkie zmapowane zmienne znajdują się w zasięgu lokalnym, podobnie jak $1 (i inne).

Kod, który sprawia, że to działa jest dość lekki i działa zarówno w bash 3 i bash 4(są to jedyne wersje, które testowałem). Jeśli interesuje cię więcej triki takie jak ten, które sprawiają, że tworzenie z bash znacznie milsze i łatwiejsze, można spojrzeć na mój Bash Infinity Framework , poniższy kod jest dostępny jako jedna z jego funkcjonalności.

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;'
 28
Author: niieani,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-02-03 13:46:16

Pomiń pareny i przecinki:

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

A funkcja powinna wyglądać tak:

function myBackupFunction() {
   # here $1 is the first parameter, $2 the second etc.
}
 25
Author: Neil Butterworth,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-03-03 22:10:03

Mam nadzieję, że ten przykład może Ci pomóc. Pobiera dwie liczby od użytkownika, przekazuje je do funkcji o nazwie add (w ostatniej linijce kodu), a add sumuje je i drukuje.

#!/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
Author: Milad P.,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-02-02 19:29:27

Pomyślałem, że wspomnę o innym sposobie przekazywania nazwanych parametrów do Basha... przechodząc przez odniesienie. Jest to obsługiwane od 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];

Alternatywną składnią dla bash 4.3 jest użycie nameref

Chociaż nameref jest o wiele wygodniejszy, ponieważ bezproblemowo dereferuje, niektóre starsze wspierane dystrybucje nadal dostarczają starszą wersję , więc nie będę go jeszcze polecał.

 4
Author: Wil,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-02-20 20:19:46

Prosty przykład, który wyczyści zarówno podczas wykonywania skryptu, jak i wewnątrz skryptu podczas wywoływania funkcji.

#!/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
 2
Author: Adiii,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-11-23 13:12:22