bash - usage用法 - shell调用变量
如何检查变量是否在Bash中设置? (20)
我如何知道是否在Bash中设置了一个变量?
例如,如何检查用户是否将第一个参数提供给函数?
function a {
# if $1 is set ?
}
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显示的,类似的用法确实是巧合。否则,我当然会相信它!
如果未设置,您想退出
这对我有效。 如果没有设置参数,我希望脚本退出并显示错误消息。
#!/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
的非空数组(例如,在下面的测试7
和A
中)。 这种不一致来自于$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 testB
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 -z
和test -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