我想实现一个bash函数,其中test是第一个参数,实际上是一个变量,在某处定义。
例如,在我的.bashrc
中:
customPrompt='yes';
syntaxOn='no';
[...]
function my_func {
[...]
# I want to test if the string $1 is the name of a variable defined up above
# so something like:
if [[ $$1 == 'yes' ]];then
echo "$1 is set to yes";
else
echo "$1 is not set or != to yes";
fi
# but of course $$1 doesn't work
}
所需输出:
$ my_func customPrompt
> customPrompt is set to yes
$ my_func syntaxOn
> syntaxOn is set but != to yes
$ my_func foobar
> foobar is not set
我尝试了很多测试,如-v "$1"
, -z "$1"
, -n "$1"
,但它们都将$1测试为字符串而不是变量。(如果我说得不够清楚,请纠正)
在bash
中,您可以使用间接变量替换。
t1=some
t2=yes
fufu() {
case "${!1}" in
yes) echo "$1: set to yes. Value: ${!1}";;
'') echo "$1: not set. Value: ${!1:-UNDEF}";;
*) echo "$1: set to something other than yes. Value: ${!1}";;
esac
}
fufu t1
fufu t2
fufu t3
打印
t1: set to something other than yes. Value: some
t2: set to yes. Value: yes
t3: not set. Value: UNDEF
bash中的${!variablename}
表示indirect variable expansion
。如https://www.gnu.org/software/bash/manual/html_node/Shell-Parameter-Expansion.html
Whrere:
参数展开的基本形式是${parameter}。的价值参数被替换。当parameter为a时,需要使用大括号位置参数有一个以上的数字,或者参数为后面跟着一个字符,该字符不被解释为其名字。
如果parameter的第一个字符是感叹号介绍了可变间接等级。的值由参数的其余部分组成的变量作为变量;然后展开该变量,并将该值用于替换的其余部分,而不是参数本身的值。这被称为间接膨胀。例外情况是${!前缀}和${!名称[@]}如下所述。的感叹号必须紧跟着左括号,以便间接介绍。
还有,查看这个:https://stackoverflow.com/a/16131829/632407如何在函数中修改间接传递的变量的值
您可以简单地像
这样检查变量是否已设置if [[ $var ]]
then
echo "Sorry First set variable"
else
echo $var
fi
你可以为你的脚本
做这样的事情customPrompt='yes';
syntaxOn='no';
function my_func
{
if [[ ${!1} ]];then
echo "$1 is set to ${!1}";
else
echo "$1 is not set";
fi
}
my_func customPrompt
my_func syntaxOn
my_func foobar
输出:customPrompt is set to yes
syntaxOn is set to no
foobar is not set
您可以根据自己的需要定制函数,只需设置一些比较条件。
详细信息请查看
如果你真的想检查你的变量是否被设置或未设置(而不仅仅是空的),使用这种格式:
function my_func {
if [[ -z ${!1+.} ]]; then
echo "$1 is not set."
elif [[ ${!1} == yes ]]; then
echo "$1 is set to yes"
else
echo "$1 is set to "${!1}"."
fi
}
你会有问题的…
Bash外壳是一个非常狡猾的生物。在执行任何操作之前,Bash会插入您的命令。您的命令或shell脚本永远不会看到您是否有一个变量作为参数。
$ set -x
set -x
$ foo=bar
+ foo=bar
$ echo "$foo"
+ echo bar
bar
$ set +x
set -x
在shell中打开调试模式。它向您展示命令实际执行的内容。例如,我设置foo=bar
,然后执行echo $foo
。我的echo
命令看不到$foo
。相反,在echo
执行之前,它用bar
插入 $foo
。所有echo
在这一点上看到的是,它应该把bar
作为它的参数(而不是$foo
)。
这是非常强大的。这意味着您的程序不必坐在那里解释命令行。如果您输入echo *.txt
, echo
不必扩展*.txt
,因为shell已经完成了脏工作。
#! /bin/sh
if [[ $1 = "*" ]]
then
echo "The first argument was '*'"
else
"I was passed in $# parameters"
fi
现在,我将运行shell脚本:
$ test.sh *
I was passed in 24 parameters
什么?我的脚本的第一个参数不是*
吗?不。shell抓取*
并将其扩展为我目录中的所有文件和目录。我的shell脚本从未看到*
。但是,我可以这样做:
$ test.sh '*'
The first argument was '*'
单引号告诉shell不要插入任何内容。(双引号可以防止全局化,但仍然允许环境变量展开)。
如果我想看看我的第一个参数是否是一个变量,我必须传入单个引号:
$ test.sh '$foo'
并且,我可以这样做作为测试:
if [[ $1 != ${1#$} ]]
then
echo "The first parameter is the variable '$1'"
fi
${1#$}
看起来有点奇怪,但它只是${var#pattern}
。这将从$var
的最左侧删除pattern
。我正在采取$1
并删除$
,如果它存在。在shell中展开为:
if [[ $foo != foo ]]
有几点:
- 首先,您必须阻止shell插入您的变量。这意味着你必须在名称周围使用单引号。
- 您必须使用模式匹配来验证第一个参数以
$
开头。 一旦你这样做了,你应该能够在你的脚本中使用
${$1}
变量。