2009-05-27 4 views
42

Ce que j'est ceci:

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

peut-il être imbriquées (ou non) en une seule ligne, à savoir une seule expression?

J'essaie de supprimer le chemin et l'extension d'un nom de script afin que seul le nom de base reste. Les deux lignes ci-dessus fonctionnent bien. La nature de mon «C» me pousse simplement à masquer ces choses encore plus.

Répondre

35

Si par nid, vous voulez dire quelque chose comme ceci:

#!/bin/bash 

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

echo ${${HELLO}WORLD}

Alors non, vous pouvez 't nest ${var} expressions. L'expéditeur de syntaxe bash ne le comprendra pas. Cependant, si je comprends bien votre problème, vous pouvez utiliser la commande basename - elle supprime le chemin d'accès d'un nom de fichier donné et, en cas d'extension de l'extension, va également le dépouiller. Par exemple, l'exécution basename /some/path/to/script.sh .sh renverra script.

+2

+1 pour la référence de nom de base. –

+0

Si vous utilisez des indices, ils peuvent être corrects? par exemple, 'ARR = (' foo '' bar '' bogus '); i = 0; alors que/bin/true; fais écho $ {ARR [$ i]}; i = (((i + 1)% 3)); fait »qui est évidemment inutile comme code mais fonctionne comme un exemple. –

+2

En fait, ce * est * supporté dans certains cas, au moins dans 'bash' et' ksh'. Cela fonctionne: 'x = yyy; y = xxxyyy; echo $ {y% $ {x}} '. Je pense que le bit important est que l'expansion imbriquée est un argument de l'un des opérateurs. Je n'ai pas vu que c'est très bien documenté, cependant. – twalberg

6

Cette imbrication ne semble pas être possible dans bash, mais il travaille dans zsh:

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

Le bultin basename pourrait aider à cela, puisque vous partagez spécifiquement sur/dans une partie:

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

Ce n'est pas vraiment plus rapide que la variante deux lignes, mais il est juste une ligne à l'aide intégré dans la fonctionnalité. Ou, utilisez zsh/ksh qui peut faire l'imbrication du motif. :)

+0

désolé pour le formatage. Essayez-le. :) var = $ (basename $ {var %%. *}) – dannysauer

+0

ou utilisez la suppression de l'extension basename spécifique bash comme Tim dit et j'ai manqué ...: D – dannysauer

1

Je sais que c'est un fil ancien, mais voici mes 2 cents.

Voici un (certes kludgy) fonction bash qui permet la fonctionnalité requise:

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

Voici un script de test court:

#!/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 sortie est, comme prévu:

ABC = 12 
DEF = 34 
30

Bash prend en charge l'expansion indirecte:

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

Ceci devrait soutenir l'imbrication que vous recherchez.

+0

Salut, qu'est-ce que le! signifie en coquille? Cela signifie remplacer avec la valeur de foobar ici? – Mike

+1

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

+0

Bon exemple. Que ferions-nous dans ce cas s'ils n'avaient pas l'extension de paramètre d'indirection disponible? –

5

En fait, il est possible de créer des variables imbriquées dans bash, en utilisant deux étapes.

Voici un script de test basé sur le message de Tim, en utilisant l'idée suggérée par l'utilisateur1956358.

#!/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 sortie est:

Hello, world! 

Il y a beaucoup de trucs soignées expliqué en exécutant 'd'info bash' de la ligne de commande, la recherche puis pour 'extension paramètre Shell'. J'en ai lu quelques-uns aujourd'hui, j'ai perdu environ 20 minutes de ma journée, mais mes scripts vont s'améliorer ...

Mise à jour: Après une lecture plus approfondie, je suggère cette alternative par question initiale.

progname=${0##*/} 

Il retourne

bash 
1

expressions comme ${${a}} ne fonctionnent pas. Pour contourner, vous pouvez utiliser eval:

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

sortie est

value

0

Si la motivation est de « obscurcir » (je dirais Streamline) le traitement du tableau dans l'esprit de Python " compréhensions ", créer une fonction d'assistance qui effectue les opérations en séquence.

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

Vous pouvez utiliser le résultat avec un joli liner.

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

Lorsque vous appelez avec un tableau, n'oubliez pas: http://stackoverflow.com/q/16461656. – nobar

8

Un vieux fil, mais peut-être la réponse est l'utilisation de Indirection: {! PARAMETER} $

Pour exemple, tenez compte des lignes suivantes:

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

L'option suivante a travaillé pour moi:

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

sortie est:

par2 
+0

c'est la meilleure réponse –

-1

eval vous permettra de faire ce que vous voulez:

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

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

Sortie: Hello, world

1

Il y a une solution à 1 ligne à la question initiale de l'OP, le nom de base d'un script avec le fichier l'extension dépouillé:

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

Voici une autre, mais, en utilisant un tricheur pour basename:

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

D'autres réponses sont égarés loin de la question initiale de l'OP et vise à déterminer s'il est possible d'élargir simplement le résultat des expressions avec ${!var} mais il est venu à travers la limitation que var doit correspondre explicitement un nom de variable.Cela dit, rien ne vous empêche d'avoir une réponse 1-ligne si vous enchaînez les expressions avec un point-virgule.

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

Si vous voulez faire cela apparaître comme une seule déclaration, vous pouvez imbriquer dans un sous-shell, à savoir

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

Une utilisation intéressante est celle des travaux indirection sur des arguments d'une fonction bash. Ensuite, vous pouvez imbriquer votre fonction bash appelle à réaliser indirection imbriquée à plusieurs niveaux parce que nous sommes autorisés à faire des commandes imbriquées:

Voici une démonstration de indirection d'une expression:

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

Voici une démonstration de plusieurs niveaux indirection par le biais de commandes imbriquées:

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

Merci pour l'explication d'indirection! Il est en effet un peu dommage qu'il puisse seulement être utilisé pour référencer des noms de variables existants. Bien sûr, un oneliner peut être fait mais en impliquant l'attribution d'une variable temporaire est ce que j'essayais d'éviter, à la fin de la journée. –

+0

@ steven-lu qu'en est-il de ma fonction 'deref()'? Si vous avez déclaré cela, vous pouvez avoir votre oneliner sans une variable temporaire? –

+0

Par une mesure raisonnable, c'est deux fois à trois fois plus confus pour la maintenance que l'utilisation d'une variable temporaire qui me rappelle l'abus de préprocesseur C –

Questions connexes