将参数传递给Bash函数

我试图搜索如何在Bash函数中传递参数,但出现的总是如何从命令行传递参数。

我想在我的脚本中传递参数。我尝试了:

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

但是语法不正确。如何将参数传递给我的函数?

1574894 次浏览

删除括号和逗号:

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

函数应该看起来像这样:

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

有两种典型的声明函数的方法。我更喜欢第二种方法。

function function_name {command...}

function_name () {command...}

使用参数调用函数:

function_name "$arg1" "$arg2"

该函数通过它们的位置(而不是名称)引用传递的参数,即$1$2等。#2是脚本本身的名称。

示例:

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

此外,您需要调用已声明的函数之后

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

输出:

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

参考:高级Bash脚本指南

对高级编程语言(C/C++、Java、PHP、Python、Perl等)的了解会向外行人建议Bourne再次Shell(Bash)函数应该像其他语言一样工作。

相反,Bash函数的工作方式类似shell命令,并期望参数以与将选项传递给shell命令相同的方式传递给它们(例如ls -l)。实际上,Bash中的函数参数被视为位置参数$1, $2..$9, ${10}, ${11},依此类推)。考虑到getopts的工作方式,这并不奇怪。不要在Bash中使用括号调用函数。


说明:我碰巧正在做OpenSolaris。)

# 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

想为变量使用名称吗?只需这样做。

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

不过要小心。如果函数的参数中有一个空格,你可能想要这样做!否则,$1可能不是你认为的那样。

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

想要通过值将数组传递给函数?

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

在函数内部,像这样处理参数。

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

需要传递一个值和一个数组,但在函数内部仍然使用“$@”?

function linearSearch (){local myVar="$1"
shift 1 # Removes $1 from the parameter list
for value in "$@" # Represents the remaining parameters.doif [[ $value == $myVar ]]thenecho -e "Found it!\t... after a while."return 0fidone
return 1}
linearSearch $someStringValue "${someArray[@]}"

在Bash 4.3及更高版本中,您可以通过使用-n选项定义函数的参数通过引用将数组传递给函数。

function callingSomeFunction (){local -n someArray=$1 # also ${1:?} to make the parameter mandatory.
for value in "${someArray[@]}" # Nice!do:done}
callingSomeFunction myArray # No $ in front of the argument. You pass by name, not expansion / value.

如果您更喜欢命名参数,则可以(通过一些技巧)实际将命名参数传递给函数(也可以传递数组和引用)。

我开发的方法允许您定义传递给函数的命名参数,如下所示:

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

您还可以将参数注释为@所需或@readOnly,创建… rest参数,从顺序参数创建数组(例如使用string[4]),并可选择在多行中列出参数:

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

换句话说,你不仅可以通过参数的名字来调用参数(这是一个更具可读性的核心),你实际上可以传递数组(和对变量的引用-这个特性只在Bash 4.3中起作用)!另外,映射的变量都在局部范围内,就像$1(和其他)一样。

使这项工作成为现实的代码非常简单,并且可以在Bash 3和Bash 4中工作(这是我测试过的唯一版本)。如果你对更多这样的技巧感兴趣,让使用bash开发变得更好、更容易,你可以看看我的bash infinity框架,下面的代码可作为它的功能之一提供。

shopt -s expand_aliases
function assignTrap {local evalStringlocal -i paramIndex=${__paramIndex-0}local initialCommand="${1-}"
if [[ "$initialCommand" != ":" ]]thenecho "trap - DEBUG; eval \"${__previousTrap}\"; unset __previousTrap; unset __paramIndex;"returnfi
while [[ "${1-}" == "," || "${1-}" == "${initialCommand}" ]] || [[ "${#@}" -gt 0 && "$paramIndex" -eq 0 ]]doshift # First colon ":" or next parameter's comma ","paramIndex+=1local -a decorators=()while [[ "${1-}" == "@"* ]]dodecorators+=( "$1" )shiftdone
local declaration=local wrapLeft='"'local wrapRight='"'local nextType="$1"local length=1
case ${nextType} instring | 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}" != "" ]]thenshiftlocal nextName="$1"
for decorator in "${decorators[@]}"docase ${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" ;;esacdone
local paramRange="$paramIndex"
if [[ -z "$length" ]]then# ...restparamRange="{@:$paramIndex}"# trim leading ...nextName="${nextName//\./}"if [[ "${#@}" -gt 1 ]]thenecho "Unexpected arguments after a rest array ($nextName) in '${FUNCNAME[1]}' function." >&2fielif [[ "$length" -gt 1 ]]thenparamRange="{@:$paramIndex:$length}"paramIndex+=$((length - 1))fi
evalString+="${declaration} ${nextName}=${wrapLeft}\$${paramRange}${wrapRight}; "
# Continue to the next parameter:shiftfidoneecho "${evalString} local -i __paramIndex=${paramIndex};"}
alias args='local __previousTrap=$(trap -p DEBUG); trap "eval \"\$(assignTrap \$BASH_COMMAND)\";" DEBUG;'

它从用户那里获取两个数字,将它们提供给名为add的函数(在代码的最后一行),add将对它们进行求和并打印它们。

#!/bin/bash
read -p "Enter the first  value: " xread -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

另一种将命名参数传递给Bash…的方法是通过引用传递。这在Bash 4.0中得到支持

#!/bin/bashfunction myBackupFunction(){ # directory options destination filenamelocal 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];

Bash 4.3的另一种语法是使用名字

尽管nameref更方便,因为它无缝地取消引用,但一些较旧的支持发行版仍然提供旧版本,所以我还不太推荐它。

一个简单的示例,在执行脚本期间或调用函数时清除脚本内部。

#!/bin/bashecho "parameterized function example"function print_param_value(){value1="${1}" # $1 represent first argumentvalue2="${2}" # $2 represent second argumentecho "param 1 is  ${value1}" # As stringecho "param 2 is ${value2}"sum=$(($value1+$value2)) # Process them as numberecho "The sum of two value is ${sum}"}print_param_value "6" "4" # Space-separated value# You can also pass parameters during executing the scriptprint_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