我有一个 bash 函数可以$PATH
这样设置——
assign-path()
{
str=$1
# if the $PATH is empty, assign it directly.
if [ -z $PATH ]; then
PATH=$str;
# if the $PATH does not contain the substring, append it with ':'.
elif [[ $PATH != *$str* ]]; then
PATH=$PATH:$str;
fi
}
但问题是,我必须为不同的变量编写不同的函数(例如,为$CLASSPATH
类似的函数编写另一个函数assign-classpath()
等)。我找不到将参数传递给 bash 函数的方法,以便我可以通过引用访问它。
如果我有类似的东西那就更好了——
assign( bigstr, substr )
{
if [ -z bigstr ]; then
bigstr=substr;
elif [[ bigstr != *str* ]]; then
bigstr=bigstr:substr;
fi
}
知道如何在 bash 中实现类似上面的功能吗?
答案1
您bash
可以使用${!varname}
它来扩展另一个变量引用的内容。例如:
$ var=hello
$ foo () { echo "${!1}"; }
$ foo var
hello
从手册页:
${!prefix*}
${!prefix@}
Names matching prefix. Expands to the names of variables whose names
begin with prefix, separated by the first character of the IFS special
variable. When @ is used and the expansion appears within double quotes,
each variable name expands to a separate word.
另外,要设置内容引用的变量(没有 的危险eval
),您可以使用declare
。例如:
$ var=target
$ declare "$var=hello"
$ echo "$target"
hello
因此,您可以像这样编写函数(请小心,因为如果您declare
在函数中使用,则必须给出-g
,否则变量将是局部的):
shopt -s extglob
assign()
{
target=$1
bigstr=${!1}
substr=$2
if [ -z "$bigstr" ]; then
declare -g -- "$target=$substr"
elif [[ $bigstr != @(|*:)$substr@(|:*) ]]; then
declare -g -- "$target=$bigstr:$substr"
fi
}
并像这样使用它:
assign PATH /path/to/binaries
请注意,我还纠正了一个错误,其中 ifsubstr
已经是 的冒号分隔成员之一的子字符串bigstr
,但不是其自己的成员,则不会添加它。例如,这将允许添加/bin
到PATH
已经包含/usr/bin
.它使用extglob
集合来匹配字符串的开头/结尾或冒号,然后匹配其他任何内容。如果没有extglob
,替代方法是:
[[ $bigstr != $substr && $bigstr != *:$substr &&
$bigstr != $substr:* && $bigstr != *:$substr:* ]]
答案2
bash 4.3 中的新功能是&-n
选项:declare
local
func() {
local -n ref="$1"
ref="hello, world"
}
var='goodbye world'
func var
echo "$var"
打印出来的是hello, world
.
答案3
您可以用来eval
设置参数。可以找到该命令的说明这里。以下的用法eval
是错误的:
错误的(){ 评估 $1=$2 }
关于附加评估,eval
您应该使用
分配(){ 评估 $1='$2' }
检查使用这些函数的结果:
$X1='$X2' $X2='$X3' $ X3='xxx' $ $回声:$X1: :$X2: $回声:$X2: :$X3: $回声:$X3: :xxx: $ $ 错误 Y $X1 $回声:$Y: :$X3: $ $ 分配 Y $X1 $回声:$Y: :$X2: $ $ 分配 Y “hello world” $回声:$Y: :你好世界: $#以下内容可能会出乎意料 $ 分配 Z $Y $回显“:$Z:” :你好: $ # 因此如果第二个参数是变量,则必须引用它 $ 分配 Z "$Y" $回显“:$Z:” :你好世界:
但是您可以在不使用 的情况下实现您的目标eval
。我更喜欢这种更简单的方式。
以下函数以正确的方式进行替换(我希望)
增加(){ 本地电流=$1 本地增量=$2 本地新 如果 [[ -z $CURRENT ]];然后 新=$增强 埃利夫[[! ( ( $CURRENT = $AUGMENT ) || ( $CURRENT = $AUGMENT:* ) || \ ( $当前 = *:$AUGMENT ) || ( $当前 = *:$AUGMENT:* ) ) ]];然后 新=$当前:$增强 别的 新=$当前 菲 回显“$新” }
检查以下输出
扩充 /usr/bin /bin /usr/bin:/bin 扩充 /usr/bin:/bin /bin /usr/bin:/bin 扩充 /usr/bin:/bin:/usr/local/bin /bin /usr/bin:/bin:/usr/local/bin 增强 /bin:/usr/bin /bin /bin:/usr/bin 增强 /bin /bin /垃圾桶 扩充 /usr/bin: /bin /usr/bin::/bin 扩充 /usr/bin:/bin: /bin /usr/bin:/bin: 扩充 /usr/bin:/bin:/usr/local/bin:/bin /usr/bin:/bin:/usr/local/bin: 增强 /bin:/usr/bin: /bin /bin:/usr/bin: 增强/bin:/bin /垃圾桶: 增强:/bin ::/垃圾桶 扩充“/usr lib”“/usr bin” /usr lib:/usr bin 扩充“/usr lib:/usr bin”“/usr bin” /usr lib:/usr bin
现在您可以augment
通过以下方式使用该函数来设置变量:
PATH=`扩充 PATH /bin` CLASSPATH=`增加 CLASSPATH /bin` LD_LIBRARY_PATH=`扩展 LD_LIBRARY_PATH /usr/lib`
答案4
assign ()
{
if [ -z ${!1} ]; then
eval $1=$2
else
if [[ ${!1} != *$2* ]]; then
eval $1=${!1}:$2
fi
fi
}
$ echo =$x=
==
$ assign x y
$ echo =$x=
=y=
$ assign x y
$ echo =$x=
=y=
$ assign x z
$ echo =$x=
=y:z=
这个合适吗?