同一个 bash 函数怎么能以多个名称为人所知?
How can the same bash-function be known under multiple names?
我们有几个相当大的函数,它们之间的差别很小——只有一行。
我想将它们全部替换为一个函数——其中一行由 FUNCNAME
:
决定
function single () {
....
case $FUNCNAME in
variant1)
foo=meow
;;
variant2)
foo=woof
;;
esac
....
}
处理不同名称的函数内代码很简单(见上文)。我的问题是以不同的名称注册相同的代码(函数体)...
如何让同一个函数在不同的别名下为人所知?简单地使用 alias variant1=single
是行不通的。例如,下面的代码运行后:
shopt -s expand_aliases
for v in variant1 variant2 ... variantN
do
alias $v=single
done
新变体不知何故仍然未知——即使 type -t variant1
正确打印 alias
.
除了通过 alias
.
之外,我(个人)不知道有什么方法可以为函数赋予多个名称
使用 alias
的一种(相对)简单的方法是将 'variant' 的名称作为第一个参数传递给函数调用。然后,您在函数中做的第一件事就是测试第一个参数是否为 'variant' 名称之一。
考虑:
func1 () {
case "" in
func2) currFUNCNAME="func2"; shift ;; # shift remaining args into positions , ... $n
func3) currFUNCNAME="func3"; shift ;; # shift remaining args into positions , ... $n
*) currFUNCNAME="${FUNCNAME}" ;; # func1 called directly so is not a known variant
esac
echo "currFUNCNAME = ${currFUNCNAME}"
}
定义几个变体:
alias func2='func1 func2'
alias func3='func1 func3'
现在进行一些测试:
$ func1
currFUNCNAME = func1
$ func2
currFUNCNAME = func2
$ func3
currFUNCNAME = func3
使用 OP 示例 shopt/for
代码动态创建函数:
shopt -s expand_aliases
for v in func2 func3
do
alias "$v"="func1 $v"
done
运行我们再次测试:
$ func1
currFUNCNAME = func1
$ func2
currFUNCNAME = func2
$ func3
currFUNCNAME = func3
虽然此时如果要在此脚本中使用这些函数,那么为什么不编辑脚本以使用额外的输入 arg 调用主要函数...?
效果可以模拟为:
#!/usr/bin/env bash
function single () {
case $FUNCNAME in
variant1)
foo=meow
;;
variant2)
foo=woof
;;
esac
echo $foo
}
for variant in variant1 variant2; do
eval "$(declare -f single|perl -pe 's/single/'$variant'/ if ($. == 1)')"
done
unset -f single
variant1
# meow
variant2
# woof
尽管功能代码重复,出于安全原因不建议使用eval
。
更新 1
第二种方法
#!/usr/bin/env bash
single(){
case ${FUNCNAME[1]} in
variant1)
foo=meow
;;
variant2)
foo=woof
;;
esac
echo $foo
}
variant1(){ single "$@"; }
variant2(){ single "$@"; }
variant1
# meow
variant2
# woof
另一个基于 alias
的选项依赖于用户定义的变量(而不是命令行参数)...
假设我们的用户定义变量命名为$myalias
:
func1 () {
currFUNCNAME="${myalias:-${FUNCNAME}}"
echo "currFUNCNAME = ${currFUNCNAME}"
}
注意:显然我们需要选择一个我们确定没有使用的变量;从 OP 的评论来看,这听起来不应该是一个问题(即,只需选择一个当前未在 OP 脚本中使用的新变量名称)
定义我们的别名首先给$myalias
赋值,然后调用主函数:
shopt -s expand_aliases
for v in func2 func3
do
alias "$v"="myalias='$v'; func1"
done
现在进行一些测试:
$ func1
currFUNCNAME = func1
$ func2
currFUNCNAME = func2
$ func3
currFUNCNAME = func3
您可以使用别名为同一函数定义新名称
# attach a bash shell to a running docker container
function dexb {
docker exec -it "" /bin/bash
}
# attach a sh shell to a running docker container
function dexs {
docker exec -it "" /sh
}
# Now instead of creating another function say 'dex' with the same
# content as the function 'dexb'
# I'll just create an alias
alias 'dex'='dexb'
我们有几个相当大的函数,它们之间的差别很小——只有一行。
我想将它们全部替换为一个函数——其中一行由 FUNCNAME
:
function single () {
....
case $FUNCNAME in
variant1)
foo=meow
;;
variant2)
foo=woof
;;
esac
....
}
处理不同名称的函数内代码很简单(见上文)。我的问题是以不同的名称注册相同的代码(函数体)...
如何让同一个函数在不同的别名下为人所知?简单地使用 alias variant1=single
是行不通的。例如,下面的代码运行后:
shopt -s expand_aliases
for v in variant1 variant2 ... variantN
do
alias $v=single
done
新变体不知何故仍然未知——即使 type -t variant1
正确打印 alias
.
除了通过 alias
.
使用 alias
的一种(相对)简单的方法是将 'variant' 的名称作为第一个参数传递给函数调用。然后,您在函数中做的第一件事就是测试第一个参数是否为 'variant' 名称之一。
考虑:
func1 () {
case "" in
func2) currFUNCNAME="func2"; shift ;; # shift remaining args into positions , ... $n
func3) currFUNCNAME="func3"; shift ;; # shift remaining args into positions , ... $n
*) currFUNCNAME="${FUNCNAME}" ;; # func1 called directly so is not a known variant
esac
echo "currFUNCNAME = ${currFUNCNAME}"
}
定义几个变体:
alias func2='func1 func2'
alias func3='func1 func3'
现在进行一些测试:
$ func1
currFUNCNAME = func1
$ func2
currFUNCNAME = func2
$ func3
currFUNCNAME = func3
使用 OP 示例 shopt/for
代码动态创建函数:
shopt -s expand_aliases
for v in func2 func3
do
alias "$v"="func1 $v"
done
运行我们再次测试:
$ func1
currFUNCNAME = func1
$ func2
currFUNCNAME = func2
$ func3
currFUNCNAME = func3
虽然此时如果要在此脚本中使用这些函数,那么为什么不编辑脚本以使用额外的输入 arg 调用主要函数...?
效果可以模拟为:
#!/usr/bin/env bash
function single () {
case $FUNCNAME in
variant1)
foo=meow
;;
variant2)
foo=woof
;;
esac
echo $foo
}
for variant in variant1 variant2; do
eval "$(declare -f single|perl -pe 's/single/'$variant'/ if ($. == 1)')"
done
unset -f single
variant1
# meow
variant2
# woof
尽管功能代码重复,出于安全原因不建议使用eval
。
更新 1 第二种方法
#!/usr/bin/env bash
single(){
case ${FUNCNAME[1]} in
variant1)
foo=meow
;;
variant2)
foo=woof
;;
esac
echo $foo
}
variant1(){ single "$@"; }
variant2(){ single "$@"; }
variant1
# meow
variant2
# woof
另一个基于 alias
的选项依赖于用户定义的变量(而不是命令行参数)...
假设我们的用户定义变量命名为$myalias
:
func1 () {
currFUNCNAME="${myalias:-${FUNCNAME}}"
echo "currFUNCNAME = ${currFUNCNAME}"
}
注意:显然我们需要选择一个我们确定没有使用的变量;从 OP 的评论来看,这听起来不应该是一个问题(即,只需选择一个当前未在 OP 脚本中使用的新变量名称)
定义我们的别名首先给$myalias
赋值,然后调用主函数:
shopt -s expand_aliases
for v in func2 func3
do
alias "$v"="myalias='$v'; func1"
done
现在进行一些测试:
$ func1
currFUNCNAME = func1
$ func2
currFUNCNAME = func2
$ func3
currFUNCNAME = func3
您可以使用别名为同一函数定义新名称
# attach a bash shell to a running docker container
function dexb {
docker exec -it "" /bin/bash
}
# attach a sh shell to a running docker container
function dexs {
docker exec -it "" /sh
}
# Now instead of creating another function say 'dex' with the same
# content as the function 'dexb'
# I'll just create an alias
alias 'dex'='dexb'