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

${var}参数扩展表达式是否可以嵌套在bash中?,bash,Bash,我所拥有的是: progname=${0%.*} progname=${progname##*/} 是否可以将其嵌套(或不嵌套)到一行,即单个表达式中 我试图去掉脚本名的路径和扩展名,以便只剩下基本名称。以上两行工作正常。我的“C”特性让我更加困惑这些问题。这种嵌套在bash中似乎不可能实现,但它在zsh中工作: progname=${${0%.*}##*/} 如果说巢穴,你的意思是这样的: #!/bin/bash export HELLO="HELLO" export HELLOWORL

我所拥有的是:

progname=${0%.*}
progname=${progname##*/}
是否可以将其嵌套(或不嵌套)到一行,即单个表达式中


我试图去掉脚本名的路径和扩展名,以便只剩下基本名称。以上两行工作正常。我的“C”特性让我更加困惑这些问题。

这种嵌套在bash中似乎不可能实现,但它在zsh中工作:

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

如果说巢穴,你的意思是这样的:

#!/bin/bash

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

echo ${${HELLO}WORLD}
那么不,您不能嵌套
${var}
表达式。bash语法扩展器无法理解它


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

basename bultin可能有助于实现这一点,因为您专门将其拆分为一个部分:

user@host# var=/path/to/file.extension
user@host# basename ${var%%.*}
file
user@host#

它实际上并不比两行版本快,但它只是使用内置功能的一行。或者,使用zsh/ksh,它可以进行模式嵌套操作。:)

我知道这是一根古老的线,但这是我的2美分

下面是一个(公认的笨拙)bash函数,它允许实现所需的功能:

read_var() {
  set | grep ^$1\\b | sed s/^$1=//
}
下面是一个简短的测试脚本:

#!/bin/bash

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

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
正如预期的那样,输出为:

ABC = 12
DEF = 34

Bash支持间接扩展:

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

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

实际上,可以使用两个步骤在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}
输出为:

Hello, world!
通过从命令行运行“info bash”,然后搜索“Shell参数扩展”,可以解释许多巧妙的技巧。今天我自己也读了几篇,一天只花了大约20分钟,但我的剧本会好很多

更新:经过更多的阅读,我建议根据您最初的问题,这个替代方案

progname=${0##*/}
它回来了

bash

${${a}}
这样的表达式不起作用。要解决此问题,可以使用
eval

b=value
a=b
eval aval=\$$a
echo $aval
输出为

value

如果动机是按照Python的“理解”精神“模糊”(我会说简化)数组处理,那么创建一个按顺序执行操作的助手函数

function fixupnames()
   {
   pre=$1 ; suf=$2 ; shift ; shift ; args=($@)
   args=(${args[@]/#/${pre}-})
   args=(${args[@]/%/-${suf}})
   echo ${args[@]}
   }
您可以将结果与漂亮的一行代码一起使用

$ echo $(fixupnames a b abc def ghi)
a-abc-b a-def-b a-ghi-b

一个旧线程,但答案可能是使用间接寻址:${!PARAMETER}

例如,考虑以下几行:

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

以下选项对我有效:

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

par2

eval将允许您做您想做的事情:

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

eval echo "\${${HELLO}WORLD}"

输出:
Hello,world

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

progname=$(tmp=${0%.*};echo${tmp}
下面是另一个,但是,对basename使用欺骗:

progname=$(basename${0%.*})
其他答案偏离了OP的原始问题,重点是是否可以仅用
${!var}
扩展表达式的结果,但遇到了
var
必须显式匹配变量名的限制。话虽如此,如果用分号将表达式连成一行,没有什么能阻止你得到一个一行的答案

ANIMAL=CAT
BABYCAT=KITTEN
tmp=BABY${ANIMAL} ; ANSWER=${!tmp} # ANSWER=KITTEN
如果您想让它看起来像一条语句,您可以将它嵌套在子shell中,即

ANSWER=$( tmp=BABY${ANIMAL) ; echo ${!tmp} ) # ANSWER=KITTEN
一个有趣的用法是间接处理bash函数的参数。然后,您可以嵌套bash函数调用以实现多级嵌套间接寻址,因为我们可以执行嵌套命令:

下面是表达式间接寻址的演示:

deref(){echo${!1};}
动物=猫
BABYCAT=小猫
deref BABY${ANIMAL}#输出:小猫
下面是通过嵌套命令进行多级间接寻址的演示:

deref(){echo${!1};}
出口AA=BB
导出BB=CC
导出CC=Hiya
deref AA#输出:BB
deref$(deref AA)#输出:CC
deref$(deref$(deref AA))#输出:你好

虽然这是一个非常古老的线程,但该设备非常适合直接或随机选择文件/目录进行处理(播放曲调、选择要观看的电影或要阅读的书籍等)

在bash中,我相信不能直接嵌套同一类型的任何两个扩展是正确的,但是如果可以用不同类型的扩展将它们分开,就可以完成

e=($(find . -maxdepth 1 -type d))
c=${2:-${e[$((RANDOM%${#e[@]}))]}}
说明:e是一个目录名数组,c是所选目录,或者显式命名为$2

${2:-...}  
在哪里。。。是由以下公式给出的备选随机选择:

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

$((RANDOM%...))  
bash生成的数字除以数组e中的项数,由

${e[$((RANDOM%${#e[@]}))]}  
${#e[@]}  
产生成为数组e索引的余数(来自%运算符)

${e[...]}

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

如果您按照下面所示的方式进行中间步骤,它将起作用:

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

varname=${HELLO}WORLD
echo ${!varname}

由于已经有很多答案,我只想介绍两种不同的方法来实现这两种操作:嵌套参数扩展和变量名操作。(所以你会在这里找到四个不同的答案:)

参数扩展不是真正嵌套的,而是在一行中完成的: 没有分号(
)或换行符: 另一种方法:您可以使用fork来
basename
这将使工作顺利进行

关于连接变量名 如果要构造varname,可以

使用间接扩展 或者使用nameref
很抱歉格式化。试试看。:)var=$(basename${var%%.*})或使用特定于bash的basename扩展删除,正如Tim所说,我错过了…:如果你使用的是索引,它们可能是,对吗?e、 例如,
ARR=('foo''条''bogus');i=0;while/bin/true;do echo${ARR[$i
foobar="baz"
varname="foo"
varname+="bar"
echo ${!varname}
baz
foobar="baz"
bar="foo"
declare -n reffoobar=${bar}bar
echo $reffoobar
baz