8
votes

Bash Paramètre Quotes et Eval

J'ai écrit une bibliothèque de journalisation Bash pour être implémentée avec des scripts complexes que mon entreprise utilise actuellement. J'ai été crédiguement sur la fourniture du nom de fichier de script ($ {bash_source}) et le numéro de ligne ($ {lineno}) du script d'appel lorsque vous apportez les appels de journaux. Cependant, je ne voulais pas avoir à fier à l'utilisateur ou à la mise en œuvre du script pour passer ces deux variables comme paramètres. S'il s'agissait de C / C ++, je créerais simplement une macro qui compense "__file__" et "__line__" à la liste des paramètres.

J'ai enfin pu faire fonctionner cette partie. Voici quelques résumés très simplifiés comme une preuve de concept: p>

voici la bibliothèque de journalisation: p> xxx pré>

et un script de test de mise en œuvre: P>

${LOG} "I'm thrilled that I got this working"
# ./test.sh: eval: line 5: unexected EOF while looking for matching `''
# ./test.sh: eval: line 6: syntax error: unexpected end of file


4 commentaires

Si vous utilisez des constructions spécifiques à bash, votre script de journalisation ne doit pas être appelé "log.sh". Il devrait être "log.bash".


@WilliamPursell - J'ai fait des recherches et je n'ai trouvé aucun type de norme concernant les conventions de nommage des scripts Shell. En fait, la plupart des gens semblent laisser un suffixe au total. Pour être honnête, je n'ai jamais rien vu autre que '* .sh' (ou un script sans extension / suffixe). Et dans toute la praticité, il ne devrait pas avoir d'impact, non? L'interpréteur est tiré de la première ligne du script ou de votre coque actuelle est utilisé. Il semble que cela vient essentiellement de la préférence personnelle. Mais peut-être "* .sh" peut impliquer à un utilisateur que le script utilise "sh."


Le seul impact pratique serait si un développeur utilise vos fonctions avec une coque différente. Avec un nom '*. .Sh', un développeur présumerait raisonnablement que votre bibliothèque peut être achetée dans un script ZSH.


Point pris, je vais garder cela à l'esprit. Merci!


3 Réponses :


16
votes

Je recommande d'éviter eval code> si possible. Pour votre cas d'utilisation de journalisation, vous pourriez jeter un coup d'œil sur la coquille intégrée appelant code>. Si vous avez besoin de plus d'informations, vous pouvez utiliser les variables bash_source code>, bash_lineno code> et funcname code>. Notez que toutes ces variables sont des matrices et contiennent la pile d'appels complète. Voir l'exemple suivant:

#! /bin/bash       

function log() {
    echo "[$( caller )] $*" >&2
    echo "BASH_SOURCE: ${BASH_SOURCE[*]}"
    echo "BASH_LINENO: ${BASH_LINENO[*]}"
    echo "FUNCNAME: ${FUNCNAME[*]}"
}

function foobar() {
    log "failed:" "$@"
}

foobar "$@"


4 commentaires

Je n'ai jamais eu l'idée que celles-ci étaient des matrices! Si j'avais su que, j'aurais monté une solution différente, il y a longtemps ... L'appelant est assez proche de ce que je veux, bien que je sois Nitpicky et préférerais probablement [nom de fichier ': "ligne"]. Cependant, je pourrais certainement vivre avec quel appelant a. Cependant, parce que ces variables intégrées sont toutes des tableaux, j'ai (comme vous l'avez dit) Ma trace de pile fonctionne avec. Je devrais pouvoir retirer les informations nécessaires à partir de là dans la fonction. Cela me permettra de revenir aux appels de fonction au lieu de macros variables. Merci!!!


Juste une note: Si vous souhaitez contrôler le formatage sur le nom de fichier: ligne, vous pouvez utiliser l'appelant dans une affectation de tableau et utiliser le nom de fichier et la ligne séparément: FL = ($ (appelant)); echo "Erreur à $ (FL [1]): $ (FL [0])"


@Floyd je pense que vous vouliez dire "erreur à $ {fl [1]}: $ {fl [0]}" à la place, non?


Oui, il devrait être des supports bouclés et non arrondis qui essaieront d'exécuter FL [1]: /



2
votes

(Remarque: cela résout le problème immédiat de la citation, mais la réponse de @ Nosid sur L'accès à la pile d'appels est bien meilleur)

Modifiez votre définition de _log code> légèrement, à lire à partir d'une entrée standard au lieu de Prenant le message du journal des paramètres de position: p> xxx pré>

puis transmettez votre message de journal via une entrée standard à l'aide d'une chaîne ici ou une chaîne ici: p>

${LOG} <<<"This is a log message"
${LOG} <<<"I'm thrilled this works, too!"
${LOG} <<HERE
Even this long
message works as
intended!
HERE


1 commentaires

Merci pour l'entrée! Je vais probablement aller avec la solution de Nosid, car je pouvais voir les développeurs se plaindre de quelque chose d'aussi insignifiant que "<<<". Mais, il est bon de savoir qu'il y a une solution avec moins d'impact disponible, devrais-je en avoir besoin.



0
votes

Pour votre cas de journalisation spécifique, vous voudrez peut-être regarder Cette fonction qui imprime la fonction de fichier du contexte de l'appelant et Numéro de ligne.

Fonction de citation réutilisable h2>

Cette fonction va corriger la citation pour vous: P>

$ set $(token_quote token 'single token' token)
$ eval printf '%s\\n' "$@"
token
single token
token
$


0 commentaires