【发布时间】:2018-10-20 23:28:27
【问题描述】:
我拥有的是这样的:
progname=${0%.*}
progname=${progname##*/}
这可以嵌套(或不)成一行,即单个表达式吗?
我正在尝试从脚本名称中去除路径和扩展名,以便只留下基本名称。以上两行工作正常。我的“C”天性只是驱使我更加混淆这些。
【问题讨论】:
标签: bash
我拥有的是这样的:
progname=${0%.*}
progname=${progname##*/}
这可以嵌套(或不)成一行,即单个表达式吗?
我正在尝试从脚本名称中去除路径和扩展名,以便只留下基本名称。以上两行工作正常。我的“C”天性只是驱使我更加混淆这些。
【问题讨论】:
标签: bash
这种嵌套在 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。
【讨论】:
ARR=('foo' 'bar' 'bogus'); i=0; while /bin/true ; do echo ${ARR[$i]} ; i=(( (i + 1) % 3 )); done 显然作为代码没有用,但可以作为示例使用。
bash和ksh。这有效:x=yyy; y=xxxyyy; echo ${y%${x}}。我认为重要的是嵌套扩展是其中一个运算符的参数。不过,我还没有看到它的文档记录得很好。
echo ${${HELLO}WORLD} 说明了这 不可能。
基本名称 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
【讨论】:
set | sed -n s/^$1=//p。顺便说一句,不错的 hack。
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 Parameter Expansion”,可以解释许多巧妙的技巧。我自己今天也读了几本,我一天只浪费了大约 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
【讨论】:
一个旧线程,但也许答案是使用 Indirection:${!PARAMETER}
例如,考虑以下几行:
H="abc"
PARAM="H"
echo ${!PARAM} #gives abc
【讨论】:
以下选项对我有用:
NAME="par1-par2-par3"
echo $(TMP=${NAME%-*};echo ${TMP##*-})
输出是:
par2
【讨论】:
echo 它将par2 视为命令?
eval 将允许你做你想做的事:
export HELLO="HELLO"
export HELLOWORLD="Hello, world!"
eval echo "\${${HELLO}WORLD}"
输出:Hello, world
【讨论】:
OP 的原始问题有一个 1 行的解决方案,即删除了文件扩展名的脚本的基本名称:
progname=$(tmp=${0%.*} ; echo ${tmp##*/})
这是另一个,但是,使用了 basename 的作弊:
progname=$(basename ${0%.*})
其他答案已经偏离了 OP 的原始问题,而是专注于是否可以使用 ${!var} 扩展表达式的结果,但遇到了 var 必须明确匹配变量名的限制。话虽如此,如果您将表达式与分号链接在一起,则没有什么可以阻止您获得 1-liner 答案。
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} ; }
ANIMAL=CAT
BABYCAT=KITTEN
deref BABY${ANIMAL} # Outputs: KITTEN
这是通过嵌套命令进行多级间接的演示:
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
【讨论】:
deref() 函数呢?如果你有这个声明,你可以让你的 oneliner 没有临时变量?
虽然这是一个非常古老的线程,但该设备非常适合直接或随机选择文件/目录进行处理(播放音乐、选择要观看的电影或要阅读的书等)。
在 bash 中,我认为通常不能直接嵌套任何两个相同类型的扩展是正确的,但如果你可以用某种不同类型的扩展将它们分开,就可以做到。
e=($(find . -maxdepth 1 -type d))
c=${2:-${e[$((RANDOM%${#e[@]}))]}}
说明:e是目录名数组,c是选定目录,或者显式命名为$2,
${2:-...}
其中 ... 是由
给出的替代随机选择${e[$((RANDOM%${#e[@]}))]}
在哪里
$((RANDOM%...))
bash 生成的数字除以数组 e 中的项目数,由
给出${#e[@]}
产生成为数组 e 索引的余数(来自 % 运算符)
${e[...]}
因此您有四个嵌套扩展。
【讨论】:
如果您按照下面显示的方式进行中间步骤,它将起作用:
export HELLO="HELLO"
export HELLOWORLD="Hello, world!"
varname=${HELLO}WORLD
echo ${!varname}
【讨论】:
由于那里已经有很多答案,我只想介绍两种两种不同的方法:嵌套参数扩展和 变量名操作。 (所以你会在那里找到四个不同的答案:)。
;) 也没有换行符:progname=${0%.*} progname=${progname##*/}
basename
progname=$(basename ${0%.*})
这将完成这项工作。
如果你想构造变量名,你可以
foobar="baz"
varname="foo"
varname+="bar"
echo ${!varname}
baz
foobar="baz"
bar="foo"
declare -n reffoobar=${bar}bar
echo $reffoobar
baz
【讨论】: