2008-10-23 134 views
134

如果我要检查空字符串我会做如何判断一个字符串是否未在bash shell脚本中定义?

[ -z $mystr ] 

但如果我要检查是否变量都被定义?或者在bash脚本中没有区别?

+26

请不要使用[-z“$ mystr”]而不是[-z $ mystr] – 2008-10-23 04:46:38

+0

如何做相反的事情?我的意思是当字符串不为空 – flow 2011-06-17 15:46:39

+1

@flow:怎么样`[-n“$ {VAR + x}”] && echo not null` – Lekensteyn 2011-08-16 17:49:31

回答

122

我认为你的回答是暗示(如果没有说明)Vinkoanswer,虽然它不是简单地拼写出来。为了区分VAR是否被设置,但空或没有设置,你可以使用:

if [ -z "${VAR+xxx}" ]; then echo VAR is not set at all; fi 
if [ -z "$VAR" ] && [ "${VAR+xxx}" = "xxx" ]; then echo VAR is set but empty; fi 

你也许可以在第二行的两个测试组合成一个具有:

if [ -z "$VAR" -a "${VAR+xxx}" = "xxx" ]; then echo VAR is set but empty; fi 

但是,如果你读Autoconf的文档,你会发现他们不建议将术语与'-a'相结合,并建议使用单独的简单测试结合&&。我没有遇到有问题的系统;这并不意味着他们过去并不存在(但他们现在可能非常罕见,即使它们在遥远的过去并不稀罕)。

您可以在Bash手册中找到这些的详细信息,以及其他相关的shell parameter expansionstest or [命令和conditional expressions


我最近通过电子邮件询问这个答案与问题:

您使用两个测试,据我所知,第二个好,但不是第一个。更确切地说,我不明白是否需要进行可变扩展

if [ -z "${VAR+xxx}" ]; then echo VAR is not set at all; fi 

难道这不会完成相同的工作吗?

if [ -z "${VAR}" ]; then echo VAR is not set at all; fi 

公平问题 - 答案是:“不,你更简单的替代不会做同样的事情。”

想我测试之前写:

VAR= 

您的测试会说:“VAR没有设置在所有”,但我会说(通过暗示,因为它呼应什么)“VAR设置,但其价值可能是空的“。尝试此脚本:

(
unset VAR 
if [ -z "${VAR+xxx}" ]; then echo JL:1 VAR is not set at all; fi 
if [ -z "${VAR}" ];  then echo MP:1 VAR is not set at all; fi 
VAR= 
if [ -z "${VAR+xxx}" ]; then echo JL:2 VAR is not set at all; fi 
if [ -z "${VAR}" ];  then echo MP:2 VAR is not set at all; fi 
) 

的输出是:

JL:1 VAR is not set at all 
MP:1 VAR is not set at all 
MP:2 VAR is not set at all 

在第二对测试中,变量设置,但是它被设置为空值。这是${VAR=value}${VAR:=value}表示法的区别。同上${VAR-value}${VAR:-value},和${VAR+value}${VAR:+value}等等。


由于Gili在他answer指出,如果你与set -o nounset选项运行bash,那么上面的基本答案失败,unbound variable。这是很容易纠正:

if [ -z "${VAR+xxx}" ]; then echo VAR is not set at all; fi 
if [ -z "${VAR-}" ] && [ "${VAR+xxx}" = "xxx" ]; then echo VAR is set but empty; fi 

或者,你可以取消set -o nounset选项与set +uset -u等同于set -o nounset)。

31
~> if [ -z $FOO ]; then echo "EMPTY"; fi 
EMPTY 
~> FOO="" 
~> if [ -z $FOO ]; then echo "EMPTY"; fi 
EMPTY 
~> FOO="a" 
~> if [ -z $FOO ]; then echo "EMPTY"; fi 
~> 

-z也适用于未定义的变量。要区分未定义和已定义,您将使用列出的内容here或更清晰的说明here

最干净的方式是使用像这些示例中的扩展。要获得所有选项,请检查手册的参数扩展部分。

替代字:

~$ unset FOO 
~$ if test ${FOO+defined}; then echo "DEFINED"; fi 
~$ FOO="" 
~$ if test ${FOO+defined}; then echo "DEFINED"; fi 
DEFINED 

默认值:

~$ FOO="" 
~$ if test "${FOO-default value}" ; then echo "UNDEFINED"; fi 
~$ unset FOO 
~$ if test "${FOO-default value}" ; then echo "UNDEFINED"; fi 
UNDEFINED 

当然你会使用其中的一个不同,把你想要的,而不是“默认值”的值,并使用扩张直接,如果适当的话。

+1

但我想区分字符串是“”还是一直未定义。那可能吗? – SetJmp 2008-10-23 04:32:51

+1

这个答案*确实*告诉如何区分这两种情况;按照它提供的bash faq链接进行更多讨论。 – 2008-10-23 04:45:07

+1

我补充说,他的评论后,查尔斯 – 2008-10-23 04:52:50

-3

调用不带任何参数设置..它输出定义的所有瓦尔..
名单上的最后的将是那些在脚本定义..
,所以你能管其输出的东西,可以计算出什么东西被定义和什么不是

16

高级bash脚本指南,10.2。参数换人:

  • $ {变种+ blahblah}:如果变量被定义, 'blahblah' 为取代的 表达,否则返回null是取代
  • $ {VAR-blahblah}:如果变量被定义它本身被替换,否则 'blahblah'被替换
  • $ {var?blahblah}:如果var被定义,它将被替换,否则 函数存在'blahblah'作为错误消息。


立足于变量$ myStr中是否定义了你的程序逻辑或没有,你可以做到以下几点:

isdefined=0 
${mystr+ export isdefined=1} 

现在,如果isdefined = 0,则该变量undefined,如果isdefined = 1变量被定义为

这种检查变量的方式比上面的答案更好,因为它更优雅,更易读,而且如果你的bash shell被配置为出错使用未定义的变量(set -u),脚本将提前终止。


其他有用的东西:

有7默认值分配给$ myStr中,如果它是不确定的,并使其保持完好,否则:

mystr=${mystr- 7} 

打印错误消息并在变量未定义时退出函数:

: ${mystr? not defined} 

请注意,在这里我使用':',以便在定义时不会将$ mystr的内容作为命令执行。

0

这里是什么,我认为是来检查变量定义更清晰的方式:

var_defined() { 
    local var_name=$1 
    set | grep "^${var_name}=" 1>/dev/null 
    return $? 
} 

如下使用它:

if var_defined foo; then 
    echo "foo is defined" 
else 
    echo "foo is not defined" 
fi 
1

另一种选择:the "list array indices" expansion

$ unset foo 
$ foo= 
$ echo ${!foo[*]} 
0 
$ foo=bar 
$ echo ${!foo[*]} 
0 
$ foo=(bar baz) 
$ echo ${!foo[*]} 
0 1 

这个扩展到空字符串的唯一时间是当foo未被设置,所以你可以与串条件检查:

$ unset foo 
$ [[ ${!foo[*]} ]]; echo $? 
1 
$ foo= 
$ [[ ${!foo[*]} ]]; echo $? 
0 
$ foo=bar 
$ [[ ${!foo[*]} ]]; echo $? 
0 
$ foo=(bar baz) 
$ [[ ${!foo[*]} ]]; echo $? 
0 

应任何的bash版本> = 3.0

7

的测试总结可用。

[ -n "$var" ] && echo "var is set and not empty" 
[ -z "$var" ] && echo "var is unset or empty" 
[ "${var+x}" = "x" ] && echo "var is set" # may or may not be empty 
[ -n "${var+x}" ] && echo "var is set" # may or may not be empty 
[ -z "${var+x}" ] && echo "var is unset" 
[ -z "${var-x}" ] && echo "var is set and empty" 
1

不进一步摆脱这种自行车,但想补充

shopt -s -o nounset 

的东西,你可以添加到脚本的顶部,如果变量不是宣布任何地方,将错误在脚本中。您看到的消息是unbound variable,但正如其他人提到它不会捕获空字符串或空值。为确保任何单个值不为空,我们可以测试一个变量,因为它的扩展名为${mystr:?},也称为美元符号扩展,这会与parameter null or not set错误。

3

明确的方法检查确定将是一个变量被:

[ -v mystr ] 
5

https://stackoverflow.com/a/9824943/14731包含一个更好的答案(一说是更具可读性和启用set -o nounset作品)。它的工作方式大致如下:

if [ -n "${VAR-}" ]; then 
    echo "VAR is set and is not empty" 
elif [ "${VAR+DEFINED_BUT_EMPTY}" = "DEFINED_BUT_EMPTY" ]; then 
    echo "VAR is set, but empty" 
else 
    echo "VAR is not set" 
fi 
1

Bash Reference Manual是关于bash的权威信息来源。

下面是测试一个变量看,如果它存在的一个例子:

if [ -z "$PS1" ]; then 
     echo This shell is not interactive 
else 
     echo This shell is interactive 
fi 

(从section 6.3.2。)

请注意,打开[之后和]之前的空格是而非可选


提示的Vim用户

我有一个脚本,有几个声明如下:

export VARIABLE_NAME="$SOME_OTHER_VARIABLE/path-part" 

但我希望他们推迟到任何现有值。所以我重新写了他们看起来像这样:

if [ -z "$VARIABLE_NAME" ]; then 
     export VARIABLE_NAME="$SOME_OTHER_VARIABLE/path-part" 
fi 

我能够在VIM使用快速正则表达式来自动完成:

s/\vexport ([A-Z_]+)\=("[^"]+")\n/if [ -z "$\1" ]; then\r export \1=\2\rfi\r/gc 

这可以通过肉眼选择相关线路应用,然后打字:。命令栏预填充:'<,'>。粘贴上面的命令并回车。


测试这个版本的Vim:

VIM - Vi IMproved 7.3 (2010 Aug 15, compiled Aug 22 2015 15:38:58) 
Compiled by [email protected] 

Windows用户可能需要不同的行尾。

相关问题