Can $ {var} parameter extension expressions be inserted into bash?

What I have:

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

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

I am trying to remove the path and extension from the script name so that only the base name remains. The above two lines work fine. My nature “C” just makes me confuse them even more.

+53
bash
May 27 '09 at 18:20
source share
14 answers

If by socket you mean something like this:

 #!/bin/bash export HELLO="HELLO" export HELLOWORLD="Hello, world!" echo ${${HELLO}WORLD} 

Then no, you cannot nest ${var} expressions. The bash syntax expander will not be able to understand it.

However, if I understand your problem correctly, you can look at the basename command - it removes the path from the given file name, and if the extension is given, it will also split. For example, running basename /some/path/to/script.sh .sh will return a script .

+42
May 27 '09 at 18:32
source share

Bash supports indirect extension:

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

This should support the nesting you are looking for.

+39
Jan 07 '13 at 9:53 on
source share

Old thread, but maybe the answer is to use Indirection: $ {! PARAMETER}

For example, consider the following lines:

 H="abc" PARAM="H" echo ${!PARAM} #gives abc 
+11
Dec 16 '15 at 9:36
source share

The following option worked for me:

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

Exit:

 par2 
+11
Feb 18 '16 at 19:38
source share

This attachment is not possible in bash, but it works in zsh:

 progname=${${0%.*}##*/} 
+6
May 27 '09 at 18:30
source share

In fact, you can create nested variables in bash using two steps.

Here is a test script based on Tim's record using an idea suggested by user 1956358.

 #!/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} 

Output:

 Hello, world! 

There are many neat tricks that are explained when you run ' info bash ' from the command line, then search for ' Enlarging shell options . Today I read a few, just lost about 20 minutes of my time, but my scripts will be much better ...

Update: after more details, I suggest this alternative to your original question.

 progname=${0##*/} 

He returns

 bash 
+6
Jan 10 '13 at 17:50
source share

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

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

Exit

value

+3
Apr 7 '13 at 10:32
source share

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

Here's a function (admittedly kludgy) of bash that allows you to use the required functions:

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

Here's a short test script:

 #!/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 

The output, as expected:

 ABC = 12 DEF = 34 
+2
Aug 16 2018-12-12T00:
source share

The base name bultin could help with this, since you deliberately split into / in one part:

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

This is not much faster than the two-line option, but it is only one line using the built-in functions. Or, use zsh / ksh, which can do objects nested in a template. :)

+1
May 27 '09 at 19:45
source share

There is 1 line to resolve the original OP question, the base name of the script with a file extension:

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

Here's another, but using the cheat for the base name:

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

Other answers moved away from the original OP question and focused on whether it is possible to simply extend the result of expressions with ${!var} but faced with the limitation that var must explicitly match the variable name. Having said that, nothing will stop you from getting a 1-line answer if you combine the expressions with a semicolon.

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

If you want this to look like a separate statement, you can nest it in a subshell, i.e.

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

An interesting use is indirect work on the arguments to the bash function. You can then nest your bash function calls to achieve multi-level nested indirection, because we are allowed to do nested commands:

Here is a demonstration of the indirectness of the expression:

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

Here is a demonstration of multi-level indirection through 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 
+1
Apr 24 '17 at 2:29 on
source share

If the motivation is to “obfuscate” (I would say, simplify) the processing of the array in the spirit of “understanding” Python, create a helper function that performs the sequence of operations.

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

You can use the result with a good one line.

 $ echo $(fixupnames ab abc def ghi) a-abc-b a-def-b a-ghi-b 
0
Sep 26 '14 at 3:49
source share

Although this is a very old topic, this device is ideal for directly or randomly selecting a file / directory for processing (playing tunes, selecting a movie to watch or a book to read, etc.).

In bash, I believe that it is generally true that you cannot directly attach any two extensions of the same type, but if you can separate them with some other type of extension, you can do this.

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

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

 ${2:-...} 

where ... alternate random choice given

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

Where

 $((RANDOM%...)) 

the number generated by bash is divided by the number of elements in the array e, defined as

 ${#e[@]} 

getting the remainder (from the% operator), which becomes the index for the array e

 ${e[...]} 

So you have four nested extensions.

0
Jun 21 '18 at 17:44
source share

This will work if you follow the steps below to complete the intermediate step:

 export HELLO="HELLO" export HELLOWORLD="Hello, world!" varname=${HELLO}WORLD echo ${!varname} 
0
Apr 30 '19 at 23:22
source share

eval will let you do what you want:

 export HELLO="HELLO" export HELLOWORLD="Hello, world!" eval echo "\${${HELLO}WORLD}" 

Exit: Hello, world

-one
May 16 '16 at 14:51
source share



All Articles