$ {var}参数扩展表达式可以嵌套在bash中吗?

use*_*918 59 bash

我有的是这个:

progname=${0%.*}
progname=${progname##*/}
Run Code Online (Sandbox Code Playgroud)

这可以嵌套(或不嵌套)成一行,即单个表达式吗?

我正在尝试从脚本名称中删除路径和扩展名,以便只保留基本名称.以上两行都运行正常.我的"C"性质只是让我更加混淆这些.

Tim*_*Tim 46

如果是通过嵌套,你的意思是这样的:

#!/bin/bash

export HELLO="HELLO"
export HELLOWORLD="Hello, world!"

echo ${${HELLO}WORLD}
Run Code Online (Sandbox Code Playgroud)

然后不,你不能嵌套${var}表达式.bash语法扩展器不会理解它.

但是,如果我理解你的问题,你可能会看一下使用basename命令 - 它从给定的文件名中删除路径,如果给定扩展名,也会删除它.例如,运行basename /some/path/to/script.sh .sh将返回script.

  • 实际上,在某些情况下**支持*,至少在`bash`和`ksh`中.这有效:`x = yyy; Y = XXXYYY; echo $ {y%$ {x}}`.我认为重要的一点是嵌套扩展是其中一个运算符的参数.但是,我没有看到它的记录非常好. (2认同)
  • @CarlosBribiescas,正如@Tim 所说,“不,你不能嵌套表达式”。示例`echo ${${HELLO}WORLD}` 说明了*这* 不可能。 (2认同)

小智 42

Bash支持间接扩展:

$ FOO_BAR="foobar"
$ foo=FOO
$ foobar=${foo}_BAR
$ echo ${foobar}
FOO_BAR
$ echo ${!foobar}
foobar
Run Code Online (Sandbox Code Playgroud)

这应该支持您正在寻找的嵌套.

  • 嗨 是什么!在外壳中意味着什么?这意味着在这里用 foobar 的值替换? (4认同)
  • @Mike `${var}` 是存储在名为 `var` 的变量中的值,但 `${!var}` 是存储在名称存储在 `${var}` 中的变量中的值。这是一种间接形式。 (2认同)

小智 14

以下选项对我有用:

NAME="par1-par2-par3"
echo $(TMP=${NAME%-*};echo ${TMP##*-})
Run Code Online (Sandbox Code Playgroud)

输出是:

par2
Run Code Online (Sandbox Code Playgroud)

  • 这将创建一个子 shell。参数扩展本身不会创建子 shell。 (6认同)
  • 这是最好的答案 (2认同)

Dee*_*pak 11

一个旧线程,但也许答案是使用间接:$ {!PARAMETER}

例如,请考虑以下几行:

H="abc"
PARAM="H"
echo ${!PARAM} #gives abc
Run Code Online (Sandbox Code Playgroud)


Gav*_*ith 7

${${a}}这样的表达不起作用。要解决它,您可以使用eval

b=value
a=b
eval aval=\$$a
echo $aval
Run Code Online (Sandbox Code Playgroud)

输出是

value


Nat*_*hen 6

这种嵌套在bash中似乎不可能,但它在zsh中有效:

progname=${${0%.*}##*/}
Run Code Online (Sandbox Code Playgroud)


jmw*_*069 6

实际上,可以使用两个步骤在bash中创建嵌套变量.

这是一个基于Tim的帖子的测试脚本,使用user1956358建议的想法.

#!/bin/bash
export HELLO="HELLO"
export HELLOWORLD="Hello, world!"

# This command does not work properly in bash
echo ${${HELLO}WORLD}

# However, a two-step process does work
export TEMP=${HELLO}WORLD
echo ${!TEMP}
Run Code Online (Sandbox Code Playgroud)

输出是:

Hello, world!
Run Code Online (Sandbox Code Playgroud)

通过从命令行运行' info bash '然后搜索' Shell Parameter Expansion ' 来解释许多巧妙的技巧.我今天自己一直在读一些,只是失去了大约20分钟的一天,但我的剧本会变得更好......

更新:经过更多阅读后,我建议您根据初步问题选择此替代方案

progname=${0##*/}
Run Code Online (Sandbox Code Playgroud)

它回来了

bash
Run Code Online (Sandbox Code Playgroud)


F. *_*uri 6

由于那里已经有很多答案,我只想提出两种不同的方法来完成这两个任务:嵌套参数扩展 变量名操作。(所以你会在那里找到四个不同的答案:)。

参数扩展并不是真正嵌套的,而是在一行中完成的:

没有分号 ( ;) 也没有换行符:

progname=${0%.*} progname=${progname##*/}
Run Code Online (Sandbox Code Playgroud)

另一种方法:你可以用叉子basename

progname=$(basename ${0%.*})
Run Code Online (Sandbox Code Playgroud)

这将完成这项工作。

关于连接变量名

如果你想构造 varname,你可以

使用间接扩展

foobar="baz"
varname="foo"
varname+="bar"
echo ${!varname}
baz
Run Code Online (Sandbox Code Playgroud)

或使用nameref

foobar="baz"
bar="foo"
declare -n reffoobar=${bar}bar
echo $reffoobar
baz
Run Code Online (Sandbox Code Playgroud)


Ste*_*uan 5

对于OP的原始问题,有一个1行解决方案,即删除文件扩展名的脚本的基本名称:

progname=$(tmp=${0%.*} ; echo ${tmp##*/})
Run Code Online (Sandbox Code Playgroud)

这是另一个,但是,使用了作弊的基本名称:

progname=$(basename ${0%.*})
Run Code Online (Sandbox Code Playgroud)

其他答案已经偏离了OP的原始问题,而是集中在是否可以仅扩展表达式的结果,但遇到了必须显式匹配变量名称的${!var}限制。var话虽如此,如果您用分号将表达式链接在一起,就没有什么可以阻止您得到一行答案。

ANIMAL=CAT
BABYCAT=KITTEN
tmp=BABY${ANIMAL} ; ANSWER=${!tmp} # ANSWER=KITTEN
Run Code Online (Sandbox Code Playgroud)

如果你想让它看起来像一个单一的语句,你可以将它嵌套在一个子shell中,即

ANSWER=$( tmp=BABY${ANIMAL) ; echo ${!tmp} ) # ANSWER=KITTEN
Run Code Online (Sandbox Code Playgroud)

一个有趣的用法是间接作用于 bash 函数的参数。然后,您可以嵌套 bash 函数调用来实现多级嵌套间接,因为我们可以执行嵌套命令:

这是表达式间接的演示:

ANIMAL=CAT
BABYCAT=KITTEN
tmp=BABY${ANIMAL} ; ANSWER=${!tmp} # ANSWER=KITTEN
Run Code Online (Sandbox Code Playgroud)

以下是通过嵌套命令进行多级间接的演示:

ANSWER=$( tmp=BABY${ANIMAL) ; echo ${!tmp} ) # ANSWER=KITTEN
Run Code Online (Sandbox Code Playgroud)