2009-05-27 20 views
42

Lo que tengo es la siguiente:

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

puede esto ser anidada (o no) en una sola línea, es decir, una sola expresión?

Estoy tratando de quitar la ruta y la extensión de un nombre de script para que solo quede el nombre base. Las dos líneas anteriores funcionan bien. Mi naturaleza 'C' simplemente me está conduciendo a ofuscar estos aún más.

Respuesta

35

Si por nido, que quiere decir algo como esto:

#!/bin/bash 

export HELLO="HELLO" 
export HELLOWORLD="Hello, world!" 

echo ${${HELLO}WORLD}

Pues no, que pueda 't nest ${var} expresiones. El expansor de sintaxis bash no lo entenderá.

Sin embargo, si entiendo bien su problema, podría utilizar el comando basename - quita la ruta de un nombre de archivo dado, y si se le da la extensión, también lo eliminará. Por ejemplo, ejecutar basename /some/path/to/script.sh .sh devolverá script.

+2

+1 para la referencia de la base de datos. –

+0

Sin embargo, si usa índices, pueden ser correctos. por ejemplo, 'ARR = ('foo' 'bar' 'falso'); i = 0; while/bin/true; hacer eco $ {ARR [$ i]}; i = (((i + 1)% 3)); done' que obviamente es inútil como código, pero funciona como un ejemplo. –

+2

En realidad, este * es * compatible en ciertos casos, al menos en 'bash' y' ksh'. Esto funciona: 'x = yyy; y = xxxyyy; echo $ {y% $ {x}} '. Creo que lo importante es que la expansión anidada es un argumento de uno de los operadores. Sin embargo, no he visto que esté documentado realmente bien. – twalberg

6

Este anidamiento no parece ser posible en bash, pero funciona en zsh:

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

El nombre base bultin podría ayudar con esto, ya que está dividiendo específicamente en/en una parte:

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

En realidad no es más rápido que la variante de dos líneas, pero es sólo una línea utilizando incorporado en funcionalidad O bien, use zsh/ksh, que puede hacer la anidación del patrón. :)

+0

disculpa por el formateo. Solo inténtalo. :) var = $ (nombre base $ {var %%. *}) – dannysauer

+0

o usa la eliminación de la extensión basename específica de bash como dijo Tim y extrañé ...: D – dannysauer

1

Sé que este es un hilo antiguo, pero aquí están mis 2 centavos.

He aquí un (la verdad kludgy) Función de fiesta que permite la funcionalidad requerida:

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

Aquí hay un script de prueba corta:

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

La salida es, como era de esperar:

ABC = 12 
DEF = 34 
30

Bash admite expansión indirecta:

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

Esto debería ser compatible con la anidación que está buscando.

+0

Hola, ¿qué hace el! significa en shell? ¿Significa reemplazar con el valor de foobar aquí? – Mike

+1

@Mike http://wiki.bash-hackers.org/syntax/pe#indirection – Sparhawk

+0

Gran ejemplo. ¿Qué haría uno en este caso si no tuvieran la expansión de parámetros de indirección disponible? –

5

En realidad, es posible crear variables anidadas en bash, utilizando dos pasos.

Aquí hay un script de prueba basado en la publicación de Tim, utilizando la idea sugerida por 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} 

La salida es:

Hello, world! 

Hay un montón de truquitos explicados mediante la ejecución de 'info bash' desde la línea de comandos, a continuación, la búsqueda de 'Shell parámetro de expansión'. He estado leyendo algunos hoy, perdí unos 20 minutos de mi día, pero mis guiones van a mejorar mucho ...

Actualización: Después de leer más sugiero esta alternativa según su pregunta inicial.

progname=${0##*/} 

Devuelve

bash 
1

Expresiones como ${${a}} no funcionan. Para trabajar alrededor de ella, puede utilizar eval:

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

salida es

value

0

Si la motivación es "ocultar" (que diría línea de corriente) de procesamiento de matriz en el espíritu de Python " comprehensions ", crea una función auxiliar que realiza las operaciones en secuencia.

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

Puede usar el resultado con un buen trazador de líneas.

$ echo $(fixupnames a b abc def ghi) 
a-abc-b a-def-b a-ghi-b 
+0

Al llamar con una matriz, no olvide: http://stackoverflow.com/q/16461656. – nobar

8

Un hilo viejo, pero tal vez la respuesta es el uso de Indirección: {! PARÁMETROS} $

Por ejemplo, considere las siguientes líneas:

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

La siguiente opción ha trabajado para me:

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

de salida es:

par2 
+0

esta es la mejor respuesta –

-1

eval le permitirá hacer lo que está deseando:

export HELLO="HELLO" 
export HELLOWORLD="Hello, world!" 

eval echo "\${${HELLO}WORLD}" 

Salida: Hello, world

1

hay una solución 1 línea a la pregunta original de la OP, el nombre base de un guión con el archivo despojado de extensión:

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

Aquí hay otro, sino que, utilizando una trampa de nombre base:

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

Otras respuestas han desviado de la pregunta original del OP y centrado en si es posible ampliar simplemente el resultado de expresiones con ${!var} pero se encontró con la limitación de que var deben coincidir explícitamente un nombre de variable.Una vez dicho esto, no hay nada que le impida tener una respuesta de 1 línea si encadena las expresiones junto con un punto y coma.

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

Si usted quiere hacer este aparece como un solo estado, puede anidar en un subnivel, es decir

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

Un uso interesante es obra de indirección en argumentos de una función bash. A continuación, puede anidar la función de su fiesta insta a lograr indirecta anidada multinivel porque se nos permite hacer comandos anidados:

Esto es una demostración de indirección de una expresión:

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

Esto es una demostración de indirección multinivel a través de comandos anidados:

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 
+0

¡Gracias por la explicación indirecta! De hecho, es un poco desafortunado que solo se pueda usar para hacer referencia a nombres de variables existentes. Por supuesto, se puede hacer un oneliner pero lo que estaba tratando de evitar es la asignación de una variable temporal, al final del día. –

+0

@ steven-lu ¿qué ocurre con mi función 'deref()'? Si tiene eso declarado, ¿puede tener su oneliner sin una variable temporal? –

+0

Con cualquier medida razonable, eso es dos o tres veces más confuso para el mantenimiento que el uso de una variable de temperatura que me recuerda el abuso del preprocesador de C –

Cuestiones relacionadas