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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/917260/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-09 18:13:12  来源:igfitidea点击:

Can ${var} parameter expansion expressions be nested in bash?

bash

提问by user71918

What I have is this:

我有的是这个:

progname=${0%.*}
progname=${progname##*/}

Can this be nested (or not) into one line, i.e. a single expression?

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

I'm trying to strip the path and extension off of a script name so that only the base name is left. The above two lines work fine. My 'C' nature is simply driving me to obfuscate these even more.

我试图从脚本名称中去除路径和扩展名,以便只留下基本名称。以上两行工作正常。我的“C”性质只是驱使我更加混淆这些。

采纳答案by Tim

If by nest, you mean something like this:

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

#!/bin/bash

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

echo ${${HELLO}WORLD}

Then no, you can't nest ${var}expressions. The bash syntax expander won't understand it.

那么不,你不能嵌套${var}表达式。bash 语法扩展器不会理解它。

However, if I understand your problem right, you might look at using the basenamecommand - it strips the path from a given filename, and if given the extension, will strip that also. For example, running basename /some/path/to/script.sh .shwill return script.

但是,如果我理解您的问题,您可能会考虑使用该basename命令 - 它会从给定的文件名中剥离路径,如果给定扩展名,也会将其剥离。例如,运行basename /some/path/to/script.sh .sh将返回script

回答by user1956358

Bash supports indirect expansion:

Bash 支持间接扩展:

$ FOO_BAR="foobar"
$ foo=FOO
$ foobar=${foo}_BAR
$ echo ${foobar}
FOO_BAR
$ echo ${!foobar}
foobar

This should support the nesting you are looking for.

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

回答by luferbraho

The following option has worked for me:

以下选项对我有用:

NAME="par1-par2-par3"
echo $(TMP=${NAME%-*};echo ${TMP##*-})

Output is:

输出是:

par2

回答by Deepak

An old thread but perhaps the answer is the use of Indirection:${!PARAMETER}

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

For e.g., consider the following lines:

例如,考虑以下几行:

H="abc"
PARAM="H"
echo ${!PARAM} #gives abc

回答by Nathan Kitchen

This nesting does not appear to be possible in bash, but it works in zsh:

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

progname=${${0%.*}##*/}

回答by jmw86069

Actually it is possible to create nested variables in bash, using two steps.

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

Here is a test script based upon the post by Tim, using the idea suggested by user1956358.

这是一个基于 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}

The output is:

输出是:

Hello, world!

There are lots of neat tricks explained by running 'info bash' from the command line, then searching for 'Shell Parameter Expansion'. I've been reading a few myself today, just lost about 20 minutes of my day, but my scripts are going to get a lot better...

通过从命令行运行“ info bash”,然后搜索“ Shell Parameter Expansion” ,可以解释很多巧妙的技巧。我今天自己读了一些,每天只浪费了大约 20 分钟,但我的脚本会变得更好......

Update: After more reading I suggest this alternative per your initial question.

更新:经过更多阅读后,我建议根据您最初的问题使用此替代方法。

progname=${0##*/}

It returns

它返回

bash

回答by Gavin Smith

Expressions like ${${a}}do not work. To work around it, you can use eval:

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

b=value
a=b
eval aval=$$a
echo $aval

Output is

输出是

value

value

回答by Stephen Quan

There is a 1 line solution to the OP's original question, the basename of a script with the file extension stripped:

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

progname=$(tmp=${0%.*} ; echo ${tmp##*/})

Here's another, but, using a cheat for basename:

这是另一个,但是,对 basename 使用作弊:

progname=$(basename ${0%.*})

Other answers have wandered away from the OP's original question and focused on whether it's possible to just expand the result of expressions with ${!var}but came across the limitation that varmust explicitly match an variable name. Having said that, there's nothing stopping you having a 1-liner answer if you chain the expressions together with a semicolon.

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

ANIMAL=CAT
BABYCAT=KITTEN
tmp=BABY${ANIMAL} ; ANSWER=${!tmp} # ANSWER=KITTEN

If you want to make this appear like a single statement, you can nest it in a subshell, i.e.

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

ANSWER=$( tmp=BABY${ANIMAL) ; echo ${!tmp} ) # ANSWER=KITTEN

An interesting usage is indirection works on arguments of a bash function. Then, you can nest your bash function calls to achieve multilevel nested indirection because we are allowed to do nested commands:

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

Here's a demonstration of indirection of an expression:

这是一个表达式的间接演示:

deref() { echo ${!1} ; }
ANIMAL=CAT
BABYCAT=KITTEN
deref BABY${ANIMAL} # Outputs: KITTEN

Here's a demonstration of multi level indirection thru nested commands:

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

deref() { echo ${!1} ; }
export AA=BB
export BB=CC
export CC=Hiya
deref AA # Outputs: BB
deref $(deref AA) # Outputs: CC
deref $(deref $(deref AA)) # Outputs: Hiya

回答by diegog

I know this is an ancient thread, but here are my 2 cents.

我知道这是一个古老的线程,但这是我的 2 美分。

Here's an (admittedly kludgy) bash function which allows for the required functionality:

这是一个(不可否认的笨拙)bash 函数,它允许所需的功能:

read_var() {
  set | grep ^\b | sed s/^=//
}

Here's a short test script:

这是一个简短的测试脚本:

#!/bin/bash

read_var() {
  set | grep ^\b | sed s/^=//
}

FOO=12
BAR=34

ABC_VAR=FOO
DEF_VAR=BAR

for a in ABC DEF; do
  echo $a = $(read_var $(read_var ${a}_VAR))
done

The output is, as expected:

正如预期的那样,输出是:

ABC = 12
DEF = 34

回答by user985675

Though this is a very old thread, this device is ideal for either directly or randomly selecting a file/directory for processing (playing tunes, picking a film to watch or book to read, etc).

尽管这是一个非常古老的线程,但该设备非常适合直接或随机选择文件/目录进行处理(播放音乐、挑选电影或书籍阅读等)。

In bash I believe it is generally true that you cannot directly nest any two expansions of the same type, but if you can separate them with some different kind of expansion, it can be done.

在 bash 中,我相信通常不能直接嵌套任何两个相同类型的扩展,但是如果您可以用某种不同类型的扩展将它们分开,就可以做到。

e=($(find . -maxdepth 1 -type d))
c=${2:-${e[$((RANDOM%${#e[@]}))]}}

Explanation: e is an array of directory names, c the selected directory, either named explicitly as $2,

说明:e 是一个目录名称数组,c 是选定的目录,或者明确命名为 $2,

${2:-...}  

where ... is the alternative random selection given by

其中 ... 是由以下给出的替代随机选择

${e[$((RANDOM%${#e[@]}))]}  

where the

哪里

$((RANDOM%...))  

number generated by bash is divided by the number of items in array e, given by

bash 生成的数字除以数组 e 中的项目数,由下式给出

${#e[@]}  

yielding the remainder (from the % operator) that becomes the index to array e

产生成为数组 e 索引的余数(来自 % 运算符)

${e[...]}

Thus you have four nested expansions.

因此,您有四个嵌套的扩展。