在Bash函数中:如何检查参数是否是一个已设置的变量?

5

我希望实现一个bash函数,测试第一个参数是否真的是某个地方定义的变量。

例如,在我的.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测试为字符串而不是变量。 (如果我表达不清楚,请纠正我)

4个回答

5
在中,您可以使用间接变量替换。
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}表示间接变量扩展。参见https://www.gnu.org/software/bash/manual/html_node/Shell-Parameter-Expansion.html
其中:
基本的参数扩展形式是${parameter}。替换了parameter的值。当parameter是一个具有超过一位数字的位置参数时,或者在parameter后面跟着不能被解释为其名称一部分的字符时,必须使用大括号。
如果parameter的第一个字符是感叹号(!),那么就会引入变量间接性。Bash使用从parameter的其余部分组成的变量的值作为变量的名称;然后这个变量被扩展并且该值在其余的替换中使用,而不是parameter本身的值。这称为间接扩展。以下是${!prefix}和${!name[@]}扩展的例外情况。感叹号必须紧随左花括号之后才能引入间接性。
此外,请查看此链接:https://dev59.com/OHHYa4cB1Zd3GeqPIzYL#16131829,了解如何在函数中修改通过间接方式传递的变量的值。

我喜欢这种方法,做得很好!你能否编辑一下你的回答并解释一下 "${!VAR}" 是什么(可以附上链接)?我知道它是如何工作的,因为那正是我在寻找的东西,但我没有找到。 :) - 4wk_
@Ash_ 添加了基本的Bash链接,更多可以通过“Bash间接变量扩展”进行查找。 - clt60
太好了。你在链接问题上的另一个答案也非常有趣!谢谢伙计。 - 4wk_
@Ash_ 愉快地享受吧,我很高兴能够帮助。 :) - clt60

2
您可以通过以下方式简单地检查变量是否设置:

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

您可以通过简单地设置一些比较条件来根据自己的需求定制函数。

如需更多详细信息,请查看此答案


1
如果您真的想检查变量是否设置或未设置(不仅仅是空),请使用以下格式:
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
}

1
你需要面对的问题是...
Bash shell 是一种非常狡猾的工具。在执行任何命令之前,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 *.txtecho不必扩展*.txt,因为shell已经完成了这项繁重的工作。
例如,这是一个测试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}变量。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接