可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
I am trying to search how to pass parameters in a Bash function, but what comes up is always how to pass parameter from the command line.
I would like to pass parameters within my script. I tried:
myBackupFunction(\"..\", \"...\", \"xx\")
function myBackupFunction($directory, $options, $rootPassword) {
...
}
But the syntax is not correct, how to pass a parameter to my function?
回答1:
There are two typical ways of declaring a function. I prefer the second approach.
function function_name {
command...
}
or
function_name () {
command...
}
To call a function with arguments:
function_name \"$arg1\" \"$arg2\"
The function refers to passed arguments by their position (not by name), that is $1, $2, and so forth. $0 is the name of the script itself.
Example:
function_name () {
echo \"Parameter #1 is $1\"
}
Also, you need to call your function after it is declared.
#!/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.
Output:
./myScript.sh: line 2: foo: command not found
Parameter #1 is 2
Reference: Advanced Bash-Scripting Guide.
回答2:
Knowledge of high level programming languages (C/C++/Java/PHP/Python/Perl ...) would suggest to the layman that bash functions should work like they do in those other languages. Instead, bash functions work like shell commands and expect arguments to be passed to them in the same way one might pass an option to a shell command (ls -l). In effect, function arguments in bash are treated as positional parameters ($1, $2..$9, ${10}, ${11}
, and so on). This is no surprise considering how getopts
works. Parentheses are not required to call a function in bash.
(Note: I happen to be working on Open Solaris at the 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
回答3:
If you prefer named parameters, it\'s possible (with a few tricks) to actually pass named parameters to functions (also makes it possible to pass arrays and references).
The method I developed allows you to define named parameters passed to a function like this:
function example { args : string firstName , string lastName , integer age } {
echo \"My name is ${firstName} ${lastName} and I am ${age} years old.\"
}
You can also annotate arguments as @required or @readonly, create ...rest arguments, create arrays from sequential arguments (using e.g. string[4]
) and optionally list the arguments in multiple lines:
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[*]}\"
}
In other words, not only you can call your parameters by their names (which makes up for a more readable core), you can actually pass arrays (and references to variables - this feature works only in bash 4.3 though)! Plus, the mapped variables are all in the local scope, just as $1 (and others).
The code that makes this work is pretty light and works both in bash 3 and bash 4 (these are the only versions I\'ve tested it with). If you\'re interested in more tricks like this that make developing with bash much nicer and easier, you can take a look at my Bash Infinity Framework, the code below is available as one of its functionalities.
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;\'
回答4:
Miss out the parens and commas:
myBackupFunction \"..\" \"...\" \"xx\"
and the function should look like this:
function myBackupFunction() {
# here $1 is the first parameter, $2 the second etc.
}
回答5:
I hope this example can help you. It takes two numbers from the user, feeds them to the function called add
(in the very last line of the code), and add
will sum them up and print them.
#!/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
回答6:
Thought I\'d pipe in with mention of another way to pass named parameters to bash... passing by reference. This is supported as of 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];
An alternative syntax for bash 4.3 is using a nameref
Although the nameref is a lot more convenient in that it seamlessly dereferences, some older supported distros still ship an older version so I won\'t recommend it quite yet.
回答7:
A simple example that will clear both during executing script or inside script while calling a function.
#!/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