将parameter passing给Bash函数

我正在尝试search如何在Bash函数中传递参数,但是总是如何从命令行传递参数。

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

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

但语法不正确,如何将parameter passing给我的函数?

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

 function function_name { command... } 

要么

 function_name () { command... } 

用参数调用一个函数:

 function_name $arg1 $arg2 

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

例:

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

另外,你需要声明之后调用你的函数。

 #!/bin/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 found Parameter #1 is 2 

参考:高级Bash脚本指南 。

对高级编程语言(C / C ++ / Java / PHP / Python / Perl …)的了解将会让外行知道bash函数应该像其他语言一样工作。 相反 ,bash函数像shell命令一样工作,并希望将parameter passing给它们,方法可能是将选项传递给shell命令(ls -l)。 实际上,bash中的函数参数被视为位置参数$1, $2..$9, ${10}, ${11}等)。 考虑到getopts如何工作,这并不奇怪。 圆括号不需要在bash中调用函数。


注意 :目前我正在开发Solaris。)

 # 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 

错过了parens和逗号:

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

和函数应该是这样的:

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

只是添加到已经说过的内容 – 如果你喜欢命名参数,可以(有一些技巧)实际上将命名parameter passing给函数(也可以传递数组)。

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

 testPassingParams() { @var hello l=4 @array anArrayWithFourElements l=2 @array anotherArrayWithTwo @var anotherSingle @reference table # references only work in bash >=4.3 @params anArrayOfVariedSize test "$hello" = "$1" && echo correct # test "${anArrayWithFourElements[0]}" = "$2" && echo correct test "${anArrayWithFourElements[1]}" = "$3" && echo correct test "${anArrayWithFourElements[2]}" = "$4" && echo correct # etc... # test "${anotherArrayWithTwo[0]}" = "$6" && echo correct test "${anotherArrayWithTwo[1]}" = "$7" && echo correct # test "$anotherSingle" = "$8" && echo correct # test "${table[test]}" = "works" table[inside]="adding a new value" # # I'm using * just in this example: test "${anArrayOfVariedSize[*]}" = "${*:10}" && echo correct } fourElements=( a1 a2 "a3 with spaces" a4 ) twoElements=( b1 b2 ) declare -A assocArray assocArray[test]="works" testPassingParams "first" "${fourElements[@]}" "${twoElements[@]}" "single with spaces" assocArray "and more... " "even more..." test "${assocArray[inside]}" = "adding a new value" 

换句话说,不仅可以通过名字来调用你的参数(这可以构成一个更可读的核心),你实际上可以传递数组(以及对variables的引用 – 这个特性只能在bash 4.3中使用)! 另外,映射的variables都在本地范围内,就像$ 1(和其他)一样。

使这个工作的代码是相当轻的,并在bash 3和bash 4(这是我testing过的唯一版本)。 如果你对这样的技巧更感兴趣,那就是用bash进行开发的更好,更容易,你可以看看我的Bash Infinity Framework ,下面的代码就是为这个目的而开发的。

 Function.AssignParamLocally() { local commandWithArgs=( $1 ) local command="${commandWithArgs[0]}" shift if [[ "$command" == "trap" || "$command" == "l="* || "$command" == "_type="* ]] then paramNo+=-1 return 0 fi if [[ "$command" != "local" ]] then assignNormalCodeStarted=true fi local varDeclaration="${commandWithArgs[1]}" if [[ $varDeclaration == '-n' ]] then varDeclaration="${commandWithArgs[2]}" fi local varName="${varDeclaration%%=*}" # var value is only important if making an object later on from it local varValue="${varDeclaration#*=}" if [[ ! -z $assignVarType ]] then local previousParamNo=$(expr $paramNo - 1) if [[ "$assignVarType" == "array" ]] then # passing array: execute="$assignVarName=( \"\${@:$previousParamNo:$assignArrLength}\" )" eval "$execute" paramNo+=$(expr $assignArrLength - 1) unset assignArrLength elif [[ "$assignVarType" == "params" ]] then execute="$assignVarName=( \"\${@:$previousParamNo}\" )" eval "$execute" elif [[ "$assignVarType" == "reference" ]] then execute="$assignVarName=\"\$$previousParamNo\"" eval "$execute" elif [[ ! -z "${!previousParamNo}" ]] then execute="$assignVarName=\"\$$previousParamNo\"" eval "$execute" fi fi assignVarType="$__capture_type" assignVarName="$varName" assignArrLength="$__capture_arrLength" } Function.CaptureParams() { __capture_type="$_type" __capture_arrLength="$l" } alias @trapAssign='Function.CaptureParams; trap "declare -i \"paramNo+=1\"; Function.AssignParamLocally \"\$BASH_COMMAND\" \"\$@\"; [[ \$assignNormalCodeStarted = true ]] && trap - DEBUG && unset assignVarType && unset assignVarName && unset assignNormalCodeStarted && unset paramNo" DEBUG; ' alias @param='@trapAssign local' alias @reference='_type=reference @trapAssign local -n' alias @var='_type=var @param' alias @params='_type=params @param' alias @array='_type=array @param' 

我希望这个例子能帮助你。 它从用户获取两个数字,将它们提供给名为add的函数(在代码的最后一行),然后add将它们汇总并打印出来。

 #!/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 xy #feeding the arguments 

以为我会提到另一种方式来传递命名参数bash …传递参考。 这是从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]; 

bash 4.3的替代语法是使用nameref

尽pipenameref可以更方便地无缝地解除引用,但是一些较老的受支持的发行版仍然会发布一个较老的版本,所以我现在不会推荐它。