在脚本中使用“ $ {a:-b}”进行变量分配


426

我一直在看别人写的一些脚本(特别是Red Hat),其中许多变量是使用以下表示法分配的, VARIABLE1="${VARIABLE1:-some_val}" 或者扩展了其他变量 VARIABLE2="${VARIABLE2:-`echo $VARIABLE1`}"

使用这种表示法而不是直接声明值(例如VARIABLE1=some_val)有什么意义?

这种表示法是否有好处,还是可以避免的错误?

:-在此上下文中是否具有特定含义?


看看man bash; 搜索块“ Parameter Expansion”(大约28%)。这些分配例如是默认功能:“仅当尚未设置默认值时才使用默认值”。
Hauke Laging

Answers:


695

如果另一个变量为空或未定义,则此技术允许为变量分配值。注意:此“其他变量”可以相同或另一个变量。

摘抄

${parameter:-word}
    If parameter is unset or null, the expansion of word is substituted. 
    Otherwise, the value of parameter is substituted.

注意:此表格也可以使用${parameter-word}。如果您想查看Bash中可用的所有形式的参数扩展的完整列表,那么我强烈建议您在Bash Hacker Wiki的标题为“ Parameter extension ”的主题中进行阅读。

例子

变量不存在
$ echo "$VAR1"

$ VAR1="${VAR1:-default value}"
$ echo "$VAR1"
default value
存在变量
$ VAR1="has value"
$ echo "$VAR1"
has value

$ VAR1="${VAR1:-default value}"
$ echo "$VAR1"
has value

可以通过评估其他变量或在表示法的默认值部分内运行命令来完成同一件事。

$ VAR2="has another value"
$ echo "$VAR2"
has another value
$ echo "$VAR1"

$

$ VAR1="${VAR1:-$VAR2}"
$ echo "$VAR1"
has another value

更多例子

您也可以在处使用稍微不同的表示法VARX=${VARX-<def. value>}

$ echo "${VAR1-0}"
has another value
$ echo "${VAR2-0}"
has another value
$ echo "${VAR3-0}"
0

在上面的$VAR1&中$VAR2,已经使用字符串“ has another value” $VAR3进行了定义,但是尚未定义,因此使用默认值0

另一个例子

$ VARX="${VAR3-0}"
$ echo "$VARX"
0

使用:=符号检查和分配

最后,我将提到方便的运算符:=。如果被测变量为空或未定义,这将进行检查并分配一个值。

请注意,$VAR1现在已设置。操作员:=只需一次操作即可完成测试和分配。

$ unset VAR1
$ echo "$VAR1"

$ echo "${VAR1:=default}"
default
$ echo "$VAR1"
default

但是,如果该值是事先设置的,则将其保留。

$ VAR1="some value"
$ echo "${VAR1:=default}"
some value
$ echo "$VAR1"
some value

方便的丹迪参考表

    表的ss

参考文献


8
请注意,并非所有这些扩展都记录在中bash${var:-word}Q中的一个是,但不是${var-word}上面的。POSIX文档中有一张漂亮的表格,可能值得将其复制到此答案中-pubs.opengroup.org/onlinepubs/9699919799/utilities/…–
Graeme

5
@Graeme,有文档记录,您只需要注意在未设置参数的测试中省略冒号结果即可。
斯特凡Chazelas

7
echo "${FOO:=default}"如果您确实想要使用,则使用很棒echo。但是,如果您不这样做,请尝试使用:内置的... : ${FOO:=default}$FOO的设置default如上(即,如果尚未设置)。但是$FOO在此过程中没有回声。
fbicknel

2
好的,找到答案:stackoverflow.com/q/24405606/1172302。使用${4:-$VAR}将起作用。
Nikos Alexandris

1
在这里,您可以+1达到500。恭喜!:)
XtraSimplicity

17

@slm已经包含了POSIX文档 -非常有用-但它们并没有真正扩展这些参数如何相互影响的组合。这里还没有提及这种形式:

${var?if unset parent shell dies and this message is output to stderr}

这是我的另一个答案的摘录,我认为它很好地展示了它们是如何工作的:

    sh <<-\CMD
    _input_fn() { set -- "$@" #redundant
            echo ${*?WHERES MY DATA?}
            #echo is not necessary though
            shift #sure hope we have more than $1 parameter
            : ${*?WHERES MY DATA?} #: do nothing, gracefully
    }
    _input_fn heres some stuff
    _input_fn one #here
    # shell dies - third try doesnt run
    _input_fn you there?
    # END
    CMD
heres some stuff
one
sh: line :5 *: WHERES MY DATA?

来自相同的另一个示例:

    sh <<-\CMD
    N= #N is NULL
    _test=$N #_test is also NULL and
    v="something you would rather do without"    
    ( #this subshell dies
        echo "v is ${v+set}: and its value is ${v:+not NULL}"
        echo "So this ${_test:-"\$_test:="} will equal ${_test:="$v"}"
        ${_test:+${N:?so you test for it with a little nesting}}
        echo "sure wish we could do some other things"
    )
    ( #this subshell does some other things 
        unset v #to ensure it is definitely unset
        echo "But here v is ${v-unset}: ${v:+you certainly wont see this}"
        echo "So this ${_test:-"\$_test:="} will equal NULL ${_test:="$v"}"
        ${_test:+${N:?is never substituted}}
        echo "so now we can do some other things" 
    )
    #and even though we set _test and unset v in the subshell
    echo "_test is still ${_test:-"NULL"} and ${v:+"v is still $v"}"
    # END
    CMD
v is set: and its value is not NULL
So this $_test:= will equal something you would rather do without
sh: line 7: N: so you test for it with a little nesting
But here v is unset:
So this $_test:= will equal NULL
so now we can do some other things
_test is still NULL and v is still something you would rather do without

上述例子采用的所有4所形成POSIX参数替换的优点和它们的各种:colon nullnot null测试。上面的链接中有更多信息,这里又是

人们经常不考虑的另一件事${parameter:+expansion}是,此文档在本文档中有多么有用。这是另一个答案的摘录:

最佳

在这里,您将设置一些默认值,并准备在调用时打印它们。

#!/bin/sh
    _top_of_script_pr() ( 
        IFS="$nl" ; set -f #only split at newlines and don't expand paths
        printf %s\\n ${strings}
    ) 3<<-TEMPLATES
        ${nl=
}
        ${PLACE:="your mother's house"}
        ${EVENT:="the unspeakable."}
        ${ACTION:="heroin"}
        ${RESULT:="succeed."}
        ${strings:="
            I went to ${PLACE} and saw ${EVENT}
            If you do ${ACTION} you will ${RESULT}
        "}
    #END
    TEMPLATES

中间

您可以在此处定义其他函数,以根据它们的结果调用打印函数...

    EVENT="Disney on Ice."
    _more_important_function() { #...some logic...
        [ $((1+one)) -ne 2 ] && ACTION="remedial mathematics"
            _top_of_script_pr
    }
    _less_important_function() { #...more logic...
        one=2
        : "${ACTION:="calligraphy"}"
        _top_of_script_pr
    }

底部

现在已完成所有设置,因此您将在这里执行并提取结果。

    _less_important_function
    : "${PLACE:="the cemetery"}" 
    _more_important_function
    : "${RESULT:="regret it."}" 
    _less_important_function    

结果

稍后,我将探讨为什么,但是运行上面的代码会产生以下结果:

_less_important_function()'s 首轮:

我去了你母亲的家,在冰上看到了迪斯尼。

如果您做书法,您将成功。

然后 _more_important_function():

我去了公墓,在冰上看到迪斯尼。

如果您参加补习数学,您将获得成功。

_less_important_function() 再次:

我去了公墓,在冰上看到迪斯尼。

如果您修数学,您会后悔的。

这个怎么运作:

这里的主要功能是以下概念:conditional ${parameter} expansion.您可以使用以下格式将变量设置为未设置或为null的值:

${var_name:=desired_value}

相反,如果您只希望设置一个未设置的变量,则可以忽略:colon和保留空值。

范围:

您可能会注意到,在上面的示例中$PLACE,即使已经调用过$RESULTvia,它parameter expansion也会被更改_top_of_script_pr(),大概是在运行时对其进行设置。起作用的原因是它_top_of_script_pr()是一个( subshelled )函数-我将其包含在其中,parens而不是{ curly braces }用于其他函数。因为它是在子locally scoped外壳中调用的,所以它设置的每个变量都是,当返回其父外壳时,这些值将消失。

但是当_more_important_function()设置$ACTIONglobally scoped它会影响_less_important_function()'s第二次评估,$ACTION因为_less_important_function()设置$ACTION仅通过${parameter:=expansion}.


1
高兴

8

个人经验。

我有时在脚本中使用这种格式来临时覆盖值,例如,如果我有:

$ cat script.sh
SOMETHING="${SOMETHING:-something}"; echo "$SOMETHING"; 

我可以跑:

$ env SOMETHING="something other than the default value" ./script.sh` 

无需更改的原始默认值SOMETHING

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.