Le espressioni di espansione dei parametri $ {var} possono essere annidate in bash?

Quello che ho è questo:

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

Questo può essere annidato (o meno) in un’unica riga, cioè una singola espressione?

Sto provando a rimuovere il percorso e l’estensione da un nome di script in modo che venga lasciato solo il nome base. Le due linee precedenti funzionano bene. La mia natura “C” mi sta semplicemente costringendo a offuscare ancora di più queste cose.

Se per nido intendi qualcosa del genere:

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

Quindi no, non è ansible nidificare le espressioni ${var} . L’expander della syntax di bash non lo capirà.

Tuttavia, se capisco bene il tuo problema, potresti guardare usando il comando basename : esso estrae il percorso da un determinato nome di file e, se fornito l’estensione, lo eliminerà anche. Ad esempio, l’esecuzione di basename /some/path/to/script.sh .sh restituirà lo script .

Bash supporta l’espansione indiretta:

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

Questo dovrebbe supportare il nesting che stai cercando.

Un thread vecchio, ma forse la risposta è l’uso di Indirection: $ {! PARAMETER}

Ad esempio, considera le seguenti linee:

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

La seguente opzione ha funzionato per me:

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

L’output è:

  par2 

Questo nidificazione non sembra ansible in bash, ma funziona in zsh:

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

In realtà è ansible creare variabili nidificate in bash, usando due passaggi.

Ecco uno script di test basato sul post di Tim, usando l’idea suggerita dall’utente1956358.

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

L’output è:

 Hello, world! 

Ci sono molti trucchetti spiegati eseguendo ‘ info bash ‘ dalla riga di comando, quindi cercando ‘ Shell Parameter Expansion ‘. Ne ho letto alcuni oggi, ho perso solo 20 minuti della mia giornata, ma le mie sceneggiature andranno molto meglio …

Aggiornamento: dopo ulteriori letture suggerisco questa alternativa per la tua domanda iniziale.

 progname=${0##*/} 

Ritorna

 bash 

Espressioni come ${${a}} non funzionano. Per ovviare a questo, puoi usare eval :

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

L’output è

value

Il basename bultin potrebbe essere d’aiuto in questo modo, dal momento che in particolare si divide su / in una parte:

 [email protected]# var=/path/to/file.extension [email protected]# basename ${var%%.*} file [email protected]# 

Non è molto più veloce della variante a due linee, ma è solo una linea che usa la funzionalità integrata. Oppure usa zsh / ksh che può fare la cosa di annidamento del modello. 🙂

So che questo è un thread antico, ma qui ci sono i miei 2 centesimi.

Ecco una (basicamente kludgy) funzione bash che consente la funzionalità richiesta:

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

Ecco un breve script di test:

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

L’output è, come previsto:

 ABC = 12 DEF = 34 

C’è una soluzione a 1 riga alla domanda originale dell’OP, il nome di base di uno script con l’estensione del file spogliata:

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

Eccone un altro, ma, usando un cheat per basename:

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

Altre risposte si sono allontanate dalla domanda originale dell’OP e si sono concentrate sull’opportunità di espandere semplicemente il risultato delle espressioni con ${!var} ma si è imbattuto nella limitazione secondo la quale var deve corrispondere esplicitamente a un nome di variabile. Detto questo, non c’è nulla che ti impedisca di avere una risposta 1-liner se si concatenano le espressioni con un punto e virgola.

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

Se vuoi che appaia come una singola affermazione, puoi annidarla in una subshell, es

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

Un uso interessante è il lavoro indiretto su argomenti di una funzione bash. Quindi, puoi annidare le tue chiamate di funzione bash per ottenere un indirizzamento indiretto nidificato multilivello perché possiamo eseguire comandi nidificati:

Ecco una dimostrazione di riferimento indiretto di un’espressione:

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

Ecco una dimostrazione di riferimento indiretto a più livelli tramite comandi nidificati:

 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 

Se la motivazione è quella di “offuscare” (direi streamline) l’elaborazione dell’array nello spirito delle “comprensioni” di Python, creare una funzione di supporto che esegua le operazioni in sequenza.

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

Puoi usare il risultato con una bella copertina.

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

Anche se questo è un thread molto vecchio, questo dispositivo è l’ideale per selezionare direttamente o in modo casuale un file / directory per l’elaborazione (riproduzione di brani, scelta di un film da guardare o da leggere, ecc.).

In bash credo che sia generalmente vero che non è ansible nidificare direttamente due espansioni dello stesso tipo, ma se è ansible separarle con qualche tipo di espansione diversa, è ansible farlo.

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

Spiegazione: e è una matrice di nomi di directory, c la directory selezionata, denominata esplicitamente come $ 2,

 ${2:-...} 

dove … è la selezione casuale alternativa data da

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

dove il

 $((RANDOM%...)) 

il numero generato da bash è diviso per il numero di elementi nell’array e, dato da

 ${#e[@]} 

restituendo il resto (dall’operatore%) che diventa l’indice dell’array e

 ${e[...]} 

Quindi hai quattro espansioni annidate.

eval ti permetterà di fare ciò che vuoi:

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

Uscita: Hello, world