Je voulais initialiser certaines chaînes en haut de mon script avec des variables qui n'ont pas encore été définies, telles que:
str1='I went to ${PLACE} and saw ${EVENT}'
str2='If you do ${ACTION} you will ${RESULT}'
puis plus tard PLACE
, EVENT
, ACTION
et RESULT
sera réglé. Je veux ensuite pouvoir imprimer mes chaînes avec les variables développées. Est ma seule option eval
? Cela semble fonctionner:
eval "echo ${str1}"
est-ce standard? Y a-t-il une meilleure manière de faire cela? Ce serait bien de ne pas exécuter eval
car les variables pourraient être n'importe quoi.
Si je comprends bien votre sens, je ne crois pas que ces réponses soient correctes.
eval
n'est en aucun cas nécessaire, et vous n'avez même pas besoin d'évaluer deux fois vos variables.C'est vrai, @Gilles s'en approche de très près, mais il ne résout pas le problème de la substitution éventuelle des valeurs et comment elles devraient être utilisées si vous en avez besoin plusieurs fois. Après tout, un modèle doit être utilisé plusieurs fois, non?
Je pense que c'est plus l'ordre dans lequel vous les évaluez qui est important. Considérer ce qui suit:
HAUT
Ici, vous allez définir des valeurs par défaut et vous préparer à les imprimer lors de l'appel ...
MILIEU
C'est ici que vous définissez d'autres fonctions pour faire appel à votre fonction d'impression en fonction de leurs résultats ...
BAS
Vous avez tout configuré maintenant, alors voici où vous exécuterez et tirerez vos résultats.
RÉSULTATS
Je vais expliquer pourquoi dans un instant, mais l'exécution de ce qui précède produit les résultats suivants:
COMMENT ÇA FONCTIONNE:
La caractéristique clé ici est le concept de
conditional ${parameter} expansion.
Vous pouvez définir une variable sur une valeur uniquement si elle est non définie ou nulle en utilisant le formulaire:Si, à la place, vous souhaitez définir uniquement une variable non définie, vous omettriez les
:colon
valeurs nulles et resteraient telles quelles.SUR LA PORTÉE:
Vous remarquerez peut-être que dans l'exemple ci-dessus
$PLACE
et que$RESULT
vous vous changez lorsqu'il est défini via,parameter expansion
même s'il_top_of_script_pr()
a déjà été appelé, il est probable qu'il soit défini lors de son exécution. La raison pour laquelle cela fonctionne est que_top_of_script_pr()
c'est une( subshelled )
fonction - je l'ai incluseparens
plutôt que celle{ curly braces }
utilisée pour les autres. Parce qu'elle est appelée dans un sous-shell, chaque variable qu'elle définit estlocally scoped
et lorsqu'elle retourne à son shell parent, ces valeurs disparaissent.Mais quand des
_more_important_function()
jeux ,$ACTION
il estglobally scoped
donc elle affecte_less_important_function()'s
deuxième évaluation de$ACTION
car_less_important_function()
ensembles$ACTION
uniquement par${parameter:=expansion}.
:NUL
Et pourquoi dois-je utiliser le premier
:colon?
Eh bien, laman
page vous dira que: does nothing, gracefully.
vous voyez,parameter expansion
c'est exactement ce que cela ressemble -expands
à la valeur de${parameter}.
Donc, lorsque nous définissons une variable avec${parameter:=expansion}
nous nous retrouvons avec sa valeur - que le shell tenter d'exécuter en ligne. S'il essayait de s'exécuter,the cemetery
il vous cracherait juste quelques erreurs.PLACE="${PLACE:="the cemetery"}"
produirait les mêmes résultats, mais c'est aussi redondant dans ce cas et j'ai préféré que la coque: ${did:=nothing, gracefully}.
Cela vous permet de faire ceci:
ICI-DOCUMENTS
Et en passant - la définition en ligne d'une variable nulle ou non définie est également la raison pour laquelle les éléments suivants fonctionnent:
La meilleure façon de penser à un
here-document
est comme un fichier réel diffusé vers un descripteur de fichier d'entrée. C'est plus ou moins ce qu'ils sont, mais différents shells les implémentent légèrement différemment.Dans tous les cas, si vous ne citez pas le,
<<LIMITER
vous l'obtenez en flux continu et évalué pourexpansion.
Ainsi, déclarer une variable dans unhere-document
peut fonctionner, mais uniquement viaexpansion
ce qui vous limite à définir uniquement des variables qui ne sont pas déjà définies. Pourtant, cela correspond parfaitement à vos besoins tels que vous les avez décrits, car vos valeurs par défaut seront toujours définies lorsque vous appelez la fonction d'impression de votre modèle.POURQUOI PAS
eval?
Eh bien, l'exemple que j'ai présenté fournit un moyen sûr et efficace d'accepter
parameters.
Parce qu'il gère la portée, chaque variable dans set via${parameter:=expansion}
est définissable de l'extérieur. Donc, si vous mettez tout cela dans un script appelé template_pr.sh et que vous exécutez:Vous obtiendriez:
Cela ne fonctionnerait pas pour les variables qui ont été définies littéralement dans le script, comme
$EVENT, $ACTION,
et$one,
mais je les ai définies de cette manière uniquement pour démontrer la différence.Dans tous les cas, l'acceptation d'une entrée inconnue dans une
evaled
instruction est intrinsèquement dangereuse, alors qu'elleparameter expansion
est spécifiquement conçue pour le faire.la source
Vous pouvez utiliser des espaces réservés pour les modèles de chaîne au lieu de variables non développées. Cela deviendra désordonné assez rapidement. Si ce que vous faites est très chargé en modèles, vous voudrez peut-être envisager un langage avec une véritable bibliothèque de modèles.
L'inconvénient de ce qui précède est que la variable de modèle doit être son propre mot (par exemple, vous ne pouvez pas le faire
"%prefix%foo"
). Cela pourrait être corrigé avec quelques modifications, ou simplement en codant en dur la variable de modèle au lieu d'être dynamique.la source