J'essaie d'implémenter un type de mécanisme de fonctionnement à sec pour mon script et je suis confronté au problème de suppression des guillemets lorsqu'une commande est passée en argument à une fonction et entraîne un comportement inattendu.
dry_run () {
echo "$@"
#printf '%q ' "$@"
if [ "$DRY_RUN" ]; then
return 0
fi
"$@"
}
email_admin() {
echo " Emailing admin"
dry_run su - $target_username -c "cd $GIT_WORK_TREE && git log -1 -p|mail -s '$mail_subject' $admin_email"
echo " Emailed"
}
La sortie est:
su - webuser1 -c cd /home/webuser1/public_html && git log -1 -p|mail -s 'Git deployment on webuser1' user@domain.com
Attendu:
su - webuser1 -c "cd /home/webuser1/public_html && git log -1 -p|mail -s 'Git deployment on webuser1' [email protected]"
Avec printf activé au lieu de l'écho:
su - webuser1 -c cd\ /home/webuser1/public_html\ \&\&\ git\ log\ -1\ -p\|mail\ -s\ \'Git\ deployment\ on\ webuser1\'\ user@domain.com
Résultat:
su: invalid option -- 1
Cela ne devrait pas être le cas si les guillemets restaient là où ils étaient insérés. J'ai également essayé d'utiliser "eval", pas beaucoup de différence. Si je supprime l'appel dry_run dans email_admin et que j'exécute ensuite le script, cela fonctionne très bien.
Réponses:
Essayez d'utiliser
\"
au lieu de simplement"
.la source
"$@"
devrait marcher. En fait, cela fonctionne pour moi dans ce cas de test simple:Production:
Modifié pour ajouter: la sortie de
echo $@
est correcte. Le"
est un méta-caractère et ne fait pas partie du paramètre. Vous pouvez prouver qu'il fonctionne correctement en ajoutantecho $5
àdry_run()
. Il affichera tout après-c
la source
Ce n'est pas un problème trivial. Shell effectue la suppression des guillemets avant d'appeler la fonction, il n'y a donc aucun moyen que la fonction puisse recréer les guillemets exactement comme vous les avez tapés.
Cependant, si vous voulez simplement pouvoir imprimer une chaîne qui peut être copiée et collée pour répéter la commande, vous pouvez adopter deux approches différentes:
eval
et transmettez-la àdry_run
dry_run
avant d'imprimerEn utilisant
eval
Voici comment vous pouvez utiliser
eval
pour imprimer exactement ce qui est exécuté:Production:
Notez la quantité folle de citations - vous avez une commande dans une commande dans une commande, qui devient laide rapidement. Attention: le code ci-dessus aura des problèmes si vos variables contiennent des espaces ou des caractères spéciaux (comme des guillemets).
Citation de caractères spéciaux
Cette approche vous permet d'écrire du code plus naturellement, mais la sortie est plus difficile à lire pour les humains car la méthode rapide et sale
shell_quote
est implémentée:Production:
Vous pouvez améliorer la lisibilité de la sortie en
shell_quote
remplaçant les caractères spéciaux par une barre oblique inverse au lieu de tout mettre entre guillemets simples, mais c'est difficile à faire correctement.Si vous faites l'
shell_quote
approche, vous pouvez construire la commande à laquelle passer desu
manière plus sûre. Ce qui suit fonctionnerait même si${GIT_WORK_TREE}
,${mail_subject}
ou${admin_email}
contenait des caractères spéciaux (guillemets simples, des espaces, des astérisques, des points - virgules, etc.):Production:
la source
C'est délicat, vous pourriez essayer cette autre approche que j'ai vue:
de cette façon, vous définissez simplement DRY_RUN sur blanc ou "écho" en haut de votre script et il le fait ou le fait simplement écho.
la source
Beau défi :) Ça devrait être "facile" si vous avez assez bash pour supporter
$LINENO
et$BASH_SOURCE
Voici ma première tentative, en espérant qu'elle convienne à vos besoins:
la source