Nếu bạn thích các tham số được đặt tên, có thể (với một vài thủ thuật) thực sự chuyển các tham số được đặt tên cho các hàm (cũng có thể truyền các mảng và tham chiếu).
Phương thức tôi đã phát triển cho phép bạn xác định các tham số được đặt tên được truyền cho một hàm như thế này:
function example { args : string firstName , string lastName , integer age } {
echo "My name is ${firstName} ${lastName} and I am ${age} years old."
}
Bạn cũng có thể chú thích các đối số là @required hoặc @readonly, tạo ... phần còn lại đối số, tạo mảng từ các đối số tuần tự (sử dụng ví dụ string[4]
) và liệt kê tùy chọn các đối số trong nhiều dòng:
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[*]}"
}
Nói cách khác, không chỉ bạn có thể gọi các tham số của mình bằng tên của chúng (mà tạo ra lõi dễ đọc hơn), bạn thực sự có thể truyền các mảng (và tham chiếu đến các biến - mặc dù tính năng này chỉ hoạt động trong bash 4.3)! Thêm vào đó, các biến được ánh xạ đều nằm trong phạm vi cục bộ, chỉ là $ 1 (và các biến khác).
Mã làm cho công việc này khá nhẹ và hoạt động cả trong bash 3 và bash 4 (đây là những phiên bản duy nhất tôi đã thử nghiệm với nó). Nếu bạn quan tâm đến nhiều thủ thuật như thế này giúp phát triển bash đẹp hơn và dễ dàng hơn, bạn có thể xem Bash Infinity Framework của tôi , mã dưới đây có sẵn như là một trong những chức năng của nó.
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;'