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.
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 grep
s 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.
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'")