bash - usage用法 - shell调用变量




如何检查变量是否在Bash中设置? (20)

Functions to check if variable is declared/unset

including empty $array=()


The following functions test if the given name exists as a variable

# The first parameter needs to be the name of the variable to be checked.
# (See example below)

var_is_declared() {
    { [[ -n ${!1+anything} ]] || declare -p $1 &>/dev/null;}
}

var_is_unset() {
    { [[ -z ${!1+anything} ]] && ! declare -p $1 &>/dev/null;} 
}
  • By first testing if the variable is (un)set, the call to declare can be avoided, if not necessary.
  • If however $1 contains the name of an empty $array=() , the call to declare would make sure we get the right result
  • There's never much data passed to /dev/null as declare is only called if either the variable is unset or an empty array.

This functions would test as showed in the following conditions:

a;       # is not declared
a=;      # is declared
a="foo"; # is declared
a=();    # is declared
a=("");  # is declared
unset a; # is not declared

a;       # is unset
a=;      # is not unset
a="foo"; # is not unset
a=();    # is not unset
a=("");  # is not unset
unset a; # is unset

更多细节

and a test script see my answer to the question "How do I check if a variable exists in bash?"

备注:declare -p正如的answer显示的,类似的用法确实是巧合。否则,我当然会相信它!

我如何知道是否在Bash中设置了一个变量?

例如,如何检查用户是否将第一个参数提供给函数?

function a {
    # if $1 is set ?
}

如果未设置,您想退出

这对我有效。 如果没有设置参数,我希望脚本退出并显示错误消息。

#!/usr/bin/env bash

set -o errexit

# Get the value and empty validation check all in one
VER="${1:?You must pass a version of the format 0.0.0 as the only argument}"

运行时会返回一个错误

[email protected]:~$ ./setver.sh
./setver.sh: line 13: 1: You must pass a version of the format 0.0.0 as the only argument

仅检查,不退出 - Empty和Unset无效

如果您只想检查set set = VALID或unset / empty = INVALID,请尝试使用此选项。

TSET="good val"
TEMPTY=""
unset TUNSET

if [ "${TSET:-}" ]; then echo "VALID"; else echo "INVALID";fi
# VALID
if [ "${TEMPTY:-}" ]; then echo "VALID"; else echo "INVALID";fi
# INVALID
if [ "${TUNSET:-}" ]; then echo "VALID"; else echo "INVALID";fi
# INVALID

或者,即使是短暂的测试;-)

[ "${TSET:-}"   ] && echo "VALID" || echo "INVALID"
[ "${TEMPTY:-}" ] && echo "VALID" || echo "INVALID"
[ "${TUNSET:-}" ] && echo "VALID" || echo "INVALID"

仅检查,不退出 - 只有空无效

这是问题的答案。 如果您只想检查set / empty = VALID或unset = INVALID,请使用此选项。

注意,“..- 1}”中的“1”不重要,它可以是任何东西(比如x)

TSET="good val"
TEMPTY=""
unset TUNSET

if [ "${TSET+1}" ]; then echo "VALID"; else echo "INVALID";fi
# VALID
if [ "${TEMPTY+1}" ]; then echo "VALID"; else echo "INVALID";fi
# VALID
if [ "${TUNSET+1}" ]; then echo "VALID"; else echo "INVALID";fi
# INVALID

简短的测试

[ "${TSET+1}"   ] && echo "VALID" || echo "INVALID"
[ "${TEMPTY+1}" ] && echo "VALID" || echo "INVALID"
[ "${TUNSET+1}" ] && echo "VALID" || echo "INVALID"

我把这个答案奉献给@ mklement0(评论),他挑战我准确地回答这个问题。

参考http://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_06_02


I like auxiliary functions to hide the crude details of bash. In this case, doing so adds even more (hidden) crudeness:

# The first ! negates the result (can't use -n to achieve this)
# the second ! expands the content of varname (can't do ${$varname})
function IsDeclared_Tricky
{
  local varname="$1"
  ! [ -z ${!varname+x} ]
}

Because I first had bugs in this implementation (inspired by the answers of Jens and Lionel), I came up with a different solution:

# Ask for the properties of the variable - fails if not declared
function IsDeclared()
{
  declare -p $1 &>/dev/null
}

I find it to be more straight-forward, more bashy and easier to understand/remember. Test case shows it is equivalent:

function main()
{
  declare -i xyz
  local foo
  local bar=
  local baz=''

  IsDeclared_Tricky xyz; echo "IsDeclared_Tricky xyz: $?"
  IsDeclared_Tricky foo; echo "IsDeclared_Tricky foo: $?"
  IsDeclared_Tricky bar; echo "IsDeclared_Tricky bar: $?"
  IsDeclared_Tricky baz; echo "IsDeclared_Tricky baz: $?"

  IsDeclared xyz; echo "IsDeclared xyz: $?"
  IsDeclared foo; echo "IsDeclared foo: $?"
  IsDeclared bar; echo "IsDeclared bar: $?"
  IsDeclared baz; echo "IsDeclared baz: $?"
}

main

The test case also shows that local var does NOT declare var (unless followed by '='). For quite some time I thought i declared variables this way, just to discover now that i merely expressed my intention... It's a no-op, i guess.

IsDeclared_Tricky xyz: 1
IsDeclared_Tricky foo: 1
IsDeclared_Tricky bar: 0
IsDeclared_Tricky baz: 0
IsDeclared xyz: 1
IsDeclared foo: 1
IsDeclared bar: 0
IsDeclared baz: 0

BONUS: usecase

I mostly use this test to give (and return) parameters to functions in a somewhat "elegant" and safe way (almost resembling an interface...):

#auxiliary functions
function die()
{
  echo "Error: $1"; exit 1
}

function assertVariableDeclared()
{
  IsDeclared "$1" || die "variable not declared: $1"
}

function expectVariables()
{
  while (( $# > 0 )); do
    assertVariableDeclared $1; shift
  done
}

# actual example
function exampleFunction()
{
  expectVariables inputStr outputStr
  outputStr="$inputStr world!"
}

function bonus()
{
  local inputStr='Hello'
  local outputStr= # remove this to trigger error
  exampleFunction
  echo $outputStr
}

bonus

If called with all requires variables declared:

Hello world!

其他:

Error: variable not declared: outputStr


If you wish to test that a variable is bound or unbound, this works well, even after you've turned on the nounset option:

set -o noun set

if printenv variableName >/dev/null; then
    # variable is bound to a value
else
    # variable is unbound
fi

以下是如何测试参数是未设置还是为空(“空”)设置值

+--------------------+----------------------+-----------------+-----------------+
|                    |       parameter      |     parameter   |    parameter    |
|                    |   Set and Not Null   |   Set But Null  |      Unset      |
+--------------------+----------------------+-----------------+-----------------+
| ${parameter:-word} | substitute parameter | substitute word | substitute word |
| ${parameter-word}  | substitute parameter | substitute null | substitute word |
| ${parameter:=word} | substitute parameter | assign word     | assign word     |
| ${parameter=word}  | substitute parameter | substitute null | assign word     |
| ${parameter:?word} | substitute parameter | error, exit     | error, exit     |
| ${parameter?word}  | substitute parameter | substitute null | error, exit     |
| ${parameter:+word} | substitute word      | substitute null | substitute null |
| ${parameter+word}  | substitute word      | substitute word | substitute null |
+--------------------+----------------------+-----------------+-----------------+

来源: POSIX:参数扩展

在用“替代”显示的所有情况下,表达式都会替换为显示的值。 在使用“分配”显示的所有情况下,参数都会分配该值,该值也会替换表达式。


你可以做:

function a {
        if [ ! -z "$1" ]; then
                echo '$1 is set'
        fi
}

在bash中,你可以在[[ ]]内部使用-v

#! /bin/bash -u

if [[ ! -v SOMEVAR ]]; then
    SOMEVAR='hello'
fi

echo $SOMEVAR

在shell中,可以使用-z运算符,如果字符串的长度为零,则该运算符为True。

如果未设置默认MY_VAR ,可以使用简单的单行设置,否则可以选择显示消息:

[[ -z "$MY_VAR" ]] && MY_VAR="default"
[[ -z "$MY_VAR" ]] && MY_VAR="default" || echo "Variable already set."

如果var可以是数组,则[ -z "${var+x}" ]参数替换不正确。 要确定在Bash中你需要使用[ "${#var[@]}" = 0 ]这样的数组语法 ,如下所示。

is-var-set () {
    results="\${var+x}=${var+x}\t\${#var[@]}=${#var[@]}"
    if [ -z "${var+x}" ] && [ "${#var[@]}" = 0 ]; then
        echo -e "$1: var's unset.\t$results"
    elif [ -n "${var+x}" ] && [ "${#var[@]}" != 0 ]; then
        echo -e "$1: var is set. \t$results"
    else
        echo -e "$1: Is var set? \t$results"
    fi
    unset var # so we don't have to do it everywhere else
}

几乎在所有情况下,他们都同意。 我发现数组方法更精确的唯一情况是变量是位置为0的非空数组(例如,在下面的测试7A中)。 这种不一致来自于$var它是${var[0]}缩写,所以[ -z "${var+x}" ]不检查整个数组。

这里是我的测试用例。

unset var;      is-var-set 1 # var unset
var='';         is-var-set 2 # var[0] set to ''
var=foo;        is-var-set 3 # var[0] set to 'foo'
var=();         is-var-set 4 # var unset (all indices)
var=(foo);      is-var-set 5 # var[0] set to 'foo'
var=([0]=foo);  is-var-set 6 # var[0] set to 'foo'
var=([1]=foo);  is-var-set 7 # var[0] unset, but var[1] set to 'foo'
declare -a var; is-var-set 8 # var empty, but declared as an array
declare -A var; is-var-set 9 # var empty, but declared as an associative array
declare -A var  # Because is-var-set() conveniently unsets it
var=([xz]=foo); is-var-set A # var[xz] set to 'foo', but var's otherwise empty
declare -a var  # Demonstrate that Bash knows about var, even when there's
declare -A var; is-var-set B # apparently no way to just _check_ its existence

这是输出。

1: var's unset. ${var+x}=       ${#var[@]}=0
2: var is set.  ${var+x}=x      ${#var[@]}=1
3: var is set.  ${var+x}=x      ${#var[@]}=1
4: var's unset. ${var+x}=       ${#var[@]}=0
5: var is set.  ${var+x}=x      ${#var[@]}=1
6: var is set.  ${var+x}=x      ${#var[@]}=1
7: Is var set?  ${var+x}=       ${#var[@]}=1
8: var's unset. ${var+x}=       ${#var[@]}=0
9: var's unset. ${var+x}=       ${#var[@]}=0
A: Is var set?  ${var+x}=       ${#var[@]}=1
./foo.sh: line 26: declare: var: cannot convert indexed to associative array
B: var's unset. ${var+x}=       ${#var[@]}=0

总共:

  • 在大多数情况下, ${var+x}参数扩展语法的工作原理与${#var[@]}数组语法一样,例如检查函数的参数。 这种情况可能会破坏的唯一方式是如果未来版本的Bash添加了一种将数组传递给函数而不将内容转换为单个参数的方法。
  • 数组语法对于元素0设置的非空数组(需要关联或不需要)是必需的。
  • Neither syntax explains what's going on if declare -a var has been used without assigning even a null value somewhere in the array. Bash still distinguishes the case somewhere (as seen in test B above), so this answer's not foolproof. Fortunately Bash converts exported environment variables into strings when running a program/script, so any issues with declared-but-unset variables will be contained to a single script, at least if it's not sourcing other scripts.

如果你想检查[email protected]任何内容,我发现了一个(更好)更好的代码。

if [[ $1 = "" ]]
then
  echo '$1 is blank'
else
  echo '$1 is filled up'
fi

为什么这一切? [email protected]所有内容都存在于Bash中,但默认情况下它是空白的,所以test -ztest -n无法帮助你。

更新:您也可以统计参数中的字符数。

if [ ${#1} = 0 ]
then
  echo '$1 is blank'
else
  echo '$1 is filled up'
fi

当Bash选项set -u启用时,上面的答案不起作用。 另外,它们不是动态的,例如,如何测试变量是否具有名称“dummy”定义? 尝试这个:

is_var_defined()
{
    if [ $# -ne 1 ]
    then
        echo "Expected exactly one argument: variable name as string, e.g., 'my_var'"
        exit 1
    fi
    # Tricky.  Since Bash option 'set -u' may be enabled, we cannot directly test if a variable
    # is defined with this construct: [ ! -z "$var" ].  Instead, we must use default value
    # substitution with this construct: [ ! -z "${var:-}" ].  Normally, a default value follows the
    # operator ':-', but here we leave it blank for empty (null) string.  Finally, we need to
    # substitute the text from $1 as 'var'.  This is not allowed directly in Bash with this
    # construct: [ ! -z "${$1:-}" ].  We need to use indirection with eval operator.
    # Example: $1="var"
    # Expansion for eval operator: "[ ! -z \${$1:-} ]" -> "[ ! -z \${var:-} ]"
    # Code  execute: [ ! -z ${var:-} ]
    eval "[ ! -z \${$1:-} ]"
    return $?  # Pedantic.
}

相关: 在Bash中,如何测试变量是否在“-u”模式下定义


我总是使用这个,基于这样一个事实:任何人第一次看到代码似乎都很容易理解:

if [ "$variable" = "" ]
    then
    echo "Variable X is empty"
fi

而且,如果想检查是否不为空;

if [ ! "$variable" = "" ]
    then
    echo "Variable X is not empty"
fi

而已。


我最喜欢的方式是这样的:

$var=10
$if ! ${var+false};then echo "is set";else echo "NOT set";fi
is set
$unset var
$if ! ${var+false};then echo "is set";else echo "NOT set";fi
NOT set

所以基本上,如果设置了一个变量,它就变成了“否定所产生的false ”(将会设置为true )。

而且,如果未设置,它将变成“对结果true的否定”(因为空结果的计算结果为true )(因此,结束为false =“未设置”)。


有很多方法可以做到这一点,以下是其中之一:

if [ -z "$1" ]

如果$ 1为空或未设置,则成功


要检查变量是否设置为非空值,请使用[ -n "$x" ] ,如其他人已经指出的那样。

大多数情况下,最好是将未赋值的变量与空值相同的变量进行处理。 但是,如果您需要: [ -n "${x+set}" ]"${x+set}"扩展为set x设置,如果x未设置,则设为空字符串)。

要检查一个参数是否已经通过,请测试$# ,这是传递给函数的参数的数量(或不在函数中的脚本)(见Paul的答案 )。


要检查非空/非零字符串变量,即如果设置,请使用

if [ -n "$1" ]

这与-z相反。 我发现自己使用-n多于-z


阅读bash手册页的“参数扩展”部分。 参数扩展不会为正在设置的变量提供通用测试,但如果未设置参数,则可以对参数执行几个操作。

例如:

function a {
    first_arg=${1-foo}
    # rest of the function
}

first_arg设置first_arg等于$1如果它被分配,否则它使用值“foo”。 如果绝对必须采用单个参数,并且不存在良好的默认值,则可以在未给出参数时退出并显示错误消息:

function a {
    : ${1?a must take a single argument}
    # rest of the function
}

(注意使用:作为一个空命令,它只是扩展了它的参数的值,我们不想在这个例子中用$1做任何事情,如果没有设置,就退出)


[[ $foo ]]

要么

(( ${#foo} ))

要么

let ${#foo}

要么

declare -p foo

if [ "$1" != "" ]; then
  echo \$1 is set
else
  echo \$1 is not set
fi

尽管对于参数来说,在我看来,通常最好测试$#,这是参数的数量。

if [ $# -gt 0 ]; then
  echo \$1 is set
else
  echo \$1 is not set
fi

if [[ ${!xx[@]} ]] ; then echo xx is defined; fi






variables