Jika Anda lebih suka parameter bernama, dimungkinkan (dengan beberapa trik) untuk benar-benar meneruskan parameter bernama ke fungsi (juga memungkinkan untuk melewatkan array dan referensi).
Metode yang saya kembangkan memungkinkan Anda untuk menentukan parameter bernama yang diteruskan ke fungsi seperti ini:
function example { args : string firstName , string lastName , integer age } {
echo "My name is ${firstName} ${lastName} and I am ${age} years old."
}
Anda juga dapat membuat anotasi argumen sebagai @required atau @readonly, membuat ... sisanya argumen, membuat array dari argumen sekuensial (menggunakan misal string[4]
) dan secara opsional daftar argumen dalam beberapa baris:
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[*]}"
}
Dengan kata lain, tidak hanya Anda dapat memanggil parameter Anda dengan namanya (yang merupakan inti yang lebih mudah dibaca), Anda sebenarnya dapat melewatkan array (dan referensi ke variabel - fitur ini hanya bekerja di bash 4.3)! Plus, variabel yang dipetakan semuanya berada dalam lingkup lokal, sama seperti $ 1 (dan lainnya).
Kode yang membuat pekerjaan ini cukup ringan dan berfungsi baik di bash 3 dan bash 4 (ini adalah satu-satunya versi yang telah saya uji dengan). Jika Anda tertarik dengan lebih banyak trik seperti ini yang membuat pengembangan dengan bash jauh lebih baik dan lebih mudah, Anda dapat melihat pada Bash Infinity Framework saya , kode di bawah ini tersedia sebagai salah satu fungsinya.
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;'