web-dev-qa-db-fra.com

Comment capturer la sortie de variable Shell à utiliser dans ma tâche capistrano

J'utilise capistrano pour déployer une application Ruby sur Rails. J'utilisais auparavant Centos. En convertissant ma tâche pour qu'elle soit utilisée avec Ubuntu, j'ai utilisé une tâche que j'utilisais pour Centos:

 capture("env | grep ENV_VAR").split("=").last

Cela capturerait la sortie de cette variable sur le système distant à utiliser dans mon code. Cependant, ce code ne semble pas fonctionner avec Ubuntu. Quelqu'un peut-il me dire comment capturer la sortie d'une variable à l'aide de capistrano et d'ubuntu?

J'ai essayé

capture("echo $ENV_VAR")

Mais cela affiche une chaîne vide. Je suppose que le problème est réglé à "$" mais je ne suis pas sûr.

Merci d'avance pour toute aide.

2
Vell

Utilisez printenv à la place , qui ne nécessite pas de shell:

capture('printenv ENV_VAR')

Remplacez ENV_VAR par le nom de la variable d'environnement souhaitée. Ne pas ajouter $.

Bien que printenv soit pas POSIX , les systèmes GNU/Linux tels que Debian, Ubuntu, Fedora et CentOS le prennent en charge car GNU Coreutils le fournit et fonctionne sur beaucoup d'autres systèmes * nix , comme FreeBSD. La raison pour laquelle vous devez utiliser printenv au lieu de env est que printenv ENV_VAR génère la valeur de ENV_VAR, alors que env ENV_VAR tente d'exécuter une commande appelée ENV_VAR, ce qui n'est pas ce que vous voulez.


Le reste de cet article couvre les autres méthodes, leurs limites et les moyens de les améliorer. Cette lecture est facultative, car printenv est simple et résout complètement le problème.

Votre méthode d'origine , capture("env | grep ENV_VAR").split("=").last, ne doit pas être utilisé même sur un système où semble fonctionner, car il n'est pas fiable. Il greps pour le nom de la variable partout dans la ligne VAR=val et retournera donc les résultats des variables dont les noms - ou même les valeurs - contiennent le nom de la variable souhaitée. Utiliser ^ENV_VAR= au lieu de ENV_VAR résout ce problème en faisant correspondre le nom uniquement lorsqu'il apparaît au début de la ligne (^) et en exigeant une = caractère qui apparaît juste après. Toutefois, il est possible que la valeur d’une variable d’environnement contienne un caractère = et, puisque vous appelez split et last, vous obtenez en réalité la plus longue sous-chaîne de la valeur ne contient pas =. Même si vous corrigez cela, la méthode est toujours complexe lorsque tout ce dont vous avez besoin est printenv.

La solution que vous avez trouvée , capture("/bin/sh -c 'echo $ENV_VAR'"), fonctionnera la plupart du temps , mais renvoie une valeur incorrecte lorsque la variable (a) contient des espaces autres que des caractères d'espacement simple entourés par des espaces autres que des espaces, ou (b) contient des caractères globulants tels que *, ? et [ s’ils correspondent à n’importe quel nom de fichier. Le problème est que, dans la commande Shell echo $ENV_VAR, l’expansion du paramètre $ENV_VAR n’est pas entre guillemets , donc le fractionnement de mots et globbing sont effectués. echo réinsère les espaces mais pas toujours de la même façon: echo foo bar affiche foo bar, mais echo foo bar. Ce problème peut être résolu en plaçant des guillemets "" autour du développement, bien que vous deviez soit les échapper pour que l’interprète Ruby ne les prenne pas comme mettre fin à la chaîne "- citée et en commencer une nouvelle, ou vous pouvez '- citer la chaîne Ruby et échapper aux caractères internes '.

Vous obtenez également un résultat erroné dans la situation moins courante où la valeur de ENV_VAR commence par une option prise en charge par echo. Différentes implémentations de echo prennent en charge différentes options. -n et -e sont communs. La plupart des shells intègrent echo et peut prendre en charge des options différentes de celles des autres shells et de /bin/echo. Ceci pour dire que echo n'est pas très portable . Il est raisonnable d'inspecter les variables d'environnement de manière interactive, lorsque vous réaliserez probablement qu'il se passe quelque chose d'étrange, mais moins pour les scripts. Les problèmes de portabilité de echo sont exacerbés par le fait que /bin/sh n'est pas toujours bash. Dans Ubuntu, il s'agit de dash. Ceci peut être évité en utilisant printf '%s\n' ou printf "%s\n" au lieu de echo (ou, dans votre cas, printf %s pourrait suffire).

Ainsi, votre solution peut être améliorée à capture('/bin/sh -c \'printf "%s\n" "$ENV_VAR"\''). Cela peut sembler faux aux scripteurs expérimentés de Shell qui ne connaissent pas Ruby; Notez que Ruby, contrairement à Bash et aux autres shells de style Bourne, traite \' comme une valeur littérale ' dans une chaîne ''-. Bien que ce soit correct, vos collègues devront l'examiner deux fois pour s'en convaincre, même s'ils maîtrisent les scripts Ruby et Shell. capture('printenv ENV_VAR') est plus simple.

3
Eliah Kagan

Je suis finalement tombé sur cette réponse. Pour ce faire, chargez le shell bash et transmettez-lui la commande.

capture("/bin/sh -c 'echo $ENV_VAR'")
0
Vell