在 Bash 函数中:如何检查参数是否是集合变量?

问题描述 投票:0回答:5

我想实现一个 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 variables if-statement
5个回答
5
投票

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

哪里:

参数扩展的基本形式是${parameter}。的价值 参数被替换。当参数是 a 时需要大括号 位置参数多于一位,或者参数为 后跟一个不被解释为其一部分的字符 名字。

如果参数第一个字符是感叹号(!),则 引入了变量间接级别。 Bash 使用的值 由其余参数形成的变量作为名称 多变的;然后扩展该变量并在中使用该值 其余的替换,而不是参数本身的值。 这称为间接扩展。例外情况是 ${!prefix } 和 ${!name[@]} 的扩展如下所述。这 感叹号必须紧跟在左大括号之后才能 引入间接。

另外,请检查:https://stackoverflow.com/a/16131829/632407如何在函数中修改间接传递的变量的值。


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

您只需设置一些比较条件即可根据您的要求定制功能。

更多详情可以查看这个answer


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
执行之前,它会用 $foo
插值 
bar
。此时
echo
所看到的只是它应该以
bar
作为其参数(而不是
$foo
)。

这太强大了。这意味着您的程序不必坐在那里解释命令行。如果您输入

echo *.txt
,则
echo
不必展开
*.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}
而已。这将从
pattern
最左侧删除
$var
。我正在获取
$1
并删除
$
(如果存在)。这在 shell 中扩展为:

if [[ $foo != foo ]]

这是真的。

所以,有几件事:

  • 首先,您必须阻止 shell 插入变量。这意味着您必须在名称周围使用单引号。
  • 您必须使用模式匹配来验证第一个参数是否以
    $
    开头。
  • 完成此操作后,您应该能够在脚本中通过
    ${$1}
    使用变量。

0
投票

$ 声明 -p VAR &>/dev/null ||回显未定义

© www.soinside.com 2019 - 2024. All rights reserved.