如何检查“if”语句中是否存在变量?

Int*_*... 98 bash test variable

我需要在if语句中检查变量是否存在。有以下作用:

if [ -v $somevar ]
then
    echo "Variable somevar exists!"
else
    echo "Variable somevar does not exist!"
Run Code Online (Sandbox Code Playgroud)

与此最接近的问题是this,它实际上并没有回答我的问题。

Chr*_*own 124

在现代 bash(4.2 及以上版本)中:

[[ -v name_of_var ]]
Run Code Online (Sandbox Code Playgroud)

来自help test

-v VAR, 如果设置了 shell 变量 VAR,则为真

  • 请注意,对于散列和数组,除非变量具有键/索引“0”的元素,否则它将返回 false。对于 namerefs,它测试目标是否已定义。它不适用于诸如 `$1`、`$-`、`$#` 之类的特殊参数...... (8认同)
  • 也适用于单括号:`[ -v name_of_var ]`。 (6认同)
  • 此功能仅在 bash 内置的 `test` 或 `[` 中;它在`/usr/bin/test` 中不可用。比较“man test”和“help test”。 (5认同)
  • 不知道为什么这是一个可以接受的答案。OP 并没有将 shell 限制为仅 bash。 (2认同)

Sté*_*las 37

取决于你的意思是exists

是否存在已声明但未赋值的变量?

是否存在已分配空列表的数组(或哈希)变量?

做了nameref变量指向一个变量,目前未分配存在

你考虑$-, $#,$1变量吗?(POSIX 没有)。

在类似 Bourne 的 shell 中,规范的方式是:

if [ -n "${var+set}" ]; then
  echo '$var was set'
fi
Run Code Online (Sandbox Code Playgroud)

这适用于标量变量和其他参数,以判断变量是否已分配值(空或非,自动,来自环境、分配readfor或其他)。

对于具有typesetordeclare命令的外壳,不会将已声明但未分配的变量报告为集合(请注意,在 中,声明变量会分配一个值,如果未指定则为默认值)。zsh

用于炮弹支撑阵列,除了yashzsh,不会作为报告集合,除非指数之0的元件已被设定数组变量。

对于bash(但不是ksh93也不zsh),类型变量关联数组,这将不报告它们作为一组,除非其关键的“0”元素设置。

对于ksh93and bash,对于nameref类型的变量,仅当 nameref 引用的变量本身被视为set时才返回 true 。

对于ksh,zshbash,可能更好的方法是:

if ((${#var[@]})); then
  echo '$var (or the variable it references for namerefs) or any of its elements for array/hashes has been set'
fi
Run Code Online (Sandbox Code Playgroud)

对于ksh93,zshbash4.4 或更高版本,还有:

if typeset -p var 2> /dev/null | grep -q '^'; then
  echo '$var exists'
fi
Run Code Online (Sandbox Code Playgroud)

这将报告已设置或声明的变量。

  • @antichris,这几乎不相关,在这两种情况下,它都是内置调用。当 shell 的工作是运行至少需要几毫秒的命令时,通过某种实现,您可以节省 10% 的几百纳秒调用。我不想陷入这种会降低可读性的微观优化。`[ -z ]`、`[ -n ]` 一起用于空和非空字符串测试。我不会将 `[ -z "$var" ]` 替换为 `[ ! "$var" ]` 或 `[ "$#" -ne 0 ]` 和 `[ "${1+x}" ]`,我们必须就我们的优先级达成一致。 (3认同)
  • `declare -p` / `typeset -p` 现在也适用于 `bash`。 (2认同)

shi*_*ams 13

正如在SO上的回答中提到的,这是一种检查方法:

if [ -z ${somevar+x} ]; then echo "somevar is unset"; else echo "somevar is set to '$somevar'"; fi
Run Code Online (Sandbox Code Playgroud)

其中 ${somevar+x} 是一个参数扩展,如果 var 未设置,则计算结果为 null,否则替换字符串“x”。

使用-n由其他答案的建议,只会检查变量包含空字符串。它不会检查它的存在。

  • 你需要引用 `$somevar` 来处理 `IFS=x`。要么是那个,要么引用`x`。 (2认同)
  • +1;当“set -u”生效且 Bash 版本为 4.2 之前的版本时,这似乎是最简单的方法。 (2认同)

cuo*_*glm 6

POSIXly:

! (: "${somevar?}") 2>/dev/null && echo somevar unset
Run Code Online (Sandbox Code Playgroud)

或者您可以让 shell 为您显示消息:

(: "${somevar?}")
zsh: somevar: parameter not set
Run Code Online (Sandbox Code Playgroud)

  • 好吧,我知道,但这正是因为您必须在子 shell 中执行此操作,这表明它可能不是此处测试的最佳方法 - 这是失败时的停止操作,它不允许任何简单的方法来处理失败。可移植的是,即使是“陷阱”也只能在退出时起作用。这就是我要说的——它只是不能很好地适用于通过/失败。这也不是我在说——我以前就做过这样的事,只是像这样进行了一些评论聊天才说服了我。所以,我只是想我会先付钱。 (3认同)