Can ${var} parameter expansion expressions be nest

2019-01-01 07:17发布

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.

标签: bash
13条回答
无色无味的生活
2楼-- · 2019-01-01 07:42

The following option has worked for me:

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

Output is:

par2
查看更多
流年柔荑漫光年
3楼-- · 2019-01-01 07:44

Bash supports indirect expansion:

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

This should support the nesting you are looking for.

查看更多
爱死公子算了
4楼-- · 2019-01-01 07:46

If the motivation is to "obfuscate" (I would say streamline) array processing in the spirit of Python's "comprehensions", create a helper function that performs the operations in sequence.

function fixupnames()
   {
   pre=$1 ; suf=$2 ; shift ; shift ; args=($@)
   args=(${args[@]/#/${pre}-})
   args=(${args[@]/%/-${suf}})
   echo ${args[@]}
   }

You can use the result with a nice one-liner.

$ echo $(fixupnames a b abc def ghi)
a-abc-b a-def-b a-ghi-b
查看更多
旧时光的记忆
5楼-- · 2019-01-01 07:47

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

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

Here's another, but, using a cheat for 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 var must 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.

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.

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:

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
查看更多
姐姐魅力值爆表
6楼-- · 2019-01-01 07:48

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

For e.g., consider the following lines:

H="abc"
PARAM="H"
echo ${!PARAM} #gives abc
查看更多
美炸的是我
7楼-- · 2019-01-01 07:49

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.

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,

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

${#e[@]}  

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

${e[...]}

Thus you have four nested expansions.

查看更多
登录 后发表回答