Bash参数扩展 [英] Bash parameter expansion

查看:104
本文介绍了Bash参数扩展的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个使用以下逻辑的脚本:

if [ ! -z "$1" ]; then         # if any parameter is supplied
    ACTION=                    # clear $ACTION
else
    ACTION=echo                # otherwise, set it to 'echo'
fi

按原样可以正常工作.但是,在阅读 Shell参数扩展部分在bash手册中,似乎应该可以一步完成.但是,我不太了解如何做.

我尝试过:

ACTION=${1:-echo}              # ends up with $1 in $ACTION

ACTION=${1:+}
ACTION=${ACTION:-echo}         # ends up always 'echo'

以及嵌套它们的几种方法,但是据我所知,嵌套似乎是不允许的.

我意识到我已经有了一个可行的解决方案,但是现在我真的很想知道这是否可行.对于三元运算符来说,这很简单,但是我不认为bash有一个.

如果可能的话,我想看看执行此步骤的逻辑,该过程分两步进行,没有if/else构造,但是仅使用

我只想ACTION=echo作为对我自己的健全性检查,因此,传递任何参数实际上都可以删除(通过使$ {ACTION}无效,而传递不带参数的参数则在那里留下回声.

我知道TIMTOWTDI;我想看看是否可以仅使用"Shell参数扩展"部分中的内容来完成:-)


编辑(针对Mikel):

$ cat honk.sh
#!/bin/bash
ACTION=${1-echo}
echo $ACTION
$ ./honk.sh
echo
$ ./honk.sh foo
foo

最后一个必须具有ACTION='',因此返回空行/空值.

解决方案

如果我坚持用少于4行且没有子shell的方式来执行此操作,那么我想我会使用:

ACTION=${1:+' '}
: ${ACTION:=echo}

这有点作弊-如果脚本有参数,它将创建一个空白动作而不是一个空动作.如果没有参数,则ACTION在第二行之前为空.在第二行,如果action为空,则将其设置为"echo".在扩展中,由于您(正确地)未引用$ ACTION,因此不会为空白传递任何参数.

测试器(xx.sh):

ACTION=${1:+' '}
: ${ACTION:=echo}

echo $ACTION rm -f a b c

测试:

$ sh xx.sh 1
rm -f a b c
$ sh xx.sh
echo rm -f a b c
$ sh xx.sh ''
echo rm -f a b c
$ 

如果最后一行不正确,请从加号前删除冒号.


如果可以接受子外壳,则可以使用以下两条单行之一:

ACTION=$([ -z "$1"     ] && echo echo)
ACTION=$([ -z "${1+X}" ] && echo echo)

第一个对应于上面显示的第一个版本(空的第一个参数被视为不存在);第二个处理目前存在的空参数.您可以这样写:

ACTION=$([ -z "${1:+X}" ] && echo echo)

使与第二个关系更清晰-除非您只使用其中一个,而不能同时使用两者.


由于我评论中的markdown标记使系统感到困惑(或者我弄错了,但没有足够快地对其进行修复),因此我的最后一条评论(稍作修改)应为:

表示法${var:+' '}表示'如果$var被设置并且不为空,则使用+后面的内容(在本例中为单个空格).符号${var+' '}表示如果设置了$var-不管它是否为空-都使用+之后的内容".这些其他扩展类似:

  • ${var:=X}-将$var设置为X,除非它已经具有非空值.
  • ${var:-X}-如果它具有非空值,则扩展为$var;如果$var未设置或为空,则扩展为X

删除结肠将删除测试的空"部分.

I have a script which uses the following logic:

if [ ! -z "$1" ]; then         # if any parameter is supplied
    ACTION=                    # clear $ACTION
else
    ACTION=echo                # otherwise, set it to 'echo'
fi

This works fine, as-is. However, in reading the Shell Parameter Expansion section of the bash manual, it seems this should be able to be done in a single step. However, I can't quite wrap my head around how to do it.

I've tried:

ACTION=${1:-echo}              # ends up with $1 in $ACTION

ACTION=${1:+}
ACTION=${ACTION:-echo}         # ends up always 'echo'

and a few ways of nesting them, but nesting seems to be disallowed as far as I can tell.

I realize I've already got a working solution, but now I'm genuinely curious if this is possible. It's something that would be straightforward with a ternary operator, but I don't think bash has one.

If this is possible, I'd like to see the logic to do this seeming two-step process, with no if/else constructs, but using only any combination of the Shell Parameter Expansion features.

Thank you.


EDIT for elderarthis:

The remainder of the script is just:

find . -name "*\?[NMSD]=[AD]" -exec ${ACTION} rm -f "{}" +

I just want ACTION=echo as a sanity check against myself, hence, passing any argument will actually do the deletion (by nullifying ${ACTION}, whereas passing no args leaves echo in there.

And I know TIMTOWTDI; I'm looking to see if it can be done with just the stuff in the Shell Parameter Expansion section :-)


EDIT for Mikel:

$ cat honk.sh
#!/bin/bash
ACTION=${1-echo}
echo $ACTION
$ ./honk.sh
echo
$ ./honk.sh foo
foo

The last needs to have ACTION='', and thus return a blank line/null value.

解决方案

If I insisted on doing it in fewer than 4 lines and no sub-shell, then I think I'd use:

ACTION=${1:+' '}
: ${ACTION:=echo}

This cheats slightly - it creates a blank action rather than an empty action if there is an argument to the script. If there is no argument, then ACTION is empty before the second line. On the second line, if action is empty, set it to 'echo'. In the expansion, since you (correctly) do not quote $ACTION, no argument will be passed for the blank.

Tester (xx.sh):

ACTION=${1:+' '}
: ${ACTION:=echo}

echo $ACTION rm -f a b c

Tests:

$ sh xx.sh 1
rm -f a b c
$ sh xx.sh
echo rm -f a b c
$ sh xx.sh ''
echo rm -f a b c
$ 

If the last line is incorrect, then remove the colon from before the plus.


If a sub-shell is acceptable, then one of these two single lines works:

ACTION=$([ -z "$1"     ] && echo echo)
ACTION=$([ -z "${1+X}" ] && echo echo)

The first corresponds to the first version shown above (empty first arguments are treated as absent); the second deals with empty arguments as present. You could write:

ACTION=$([ -z "${1:+X}" ] && echo echo)

to make the relation with the second clearer - except you're only going to use one or the other, not both.


Since the markdown notation in my comment confused the system (or I got it wrong but didn't get to fix it quickly enough), my last comment (slightly amended) should read:

The notation ${var:+' '} means 'if $var is set and is not empty, then use what follows the +' (which, in this case, is a single blank). The notation ${var+' '} means 'if $var is set - regardless of whether it is empty or not - then use what follows the +'. These other expansions are similar:

  • ${var:=X} - set $var to X unless it already has a non-empty value.
  • ${var:-X} - expands to $var if it has a non-empty value and expands to X if $var is unset or is empty

Dropping the colon removes the 'empty' part of the test.

这篇关于Bash参数扩展的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆