${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