Como posso capturar a saída da variável shell para usar na minha tarefa capistrano?

2

Estou usando o capistrano para implantar um aplicativo Ruby on Rails. Eu já estava usando o Centos. Ao converter minha tarefa para ser usada com o Ubuntu, tenho uma tarefa que estava usando para o Centos:

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

Isso capturaria a saída dessa variável no sistema remoto a ser usada no meu código. No entanto, este código não parece funcionar com o Ubuntu. Alguém pode me dizer como eu posso capturar a saída de uma variável usando capistrano e Ubuntu?

Eu tentei

capture("echo $ENV_VAR")

Mas isso imprime uma string vazia. Eu estou supondo que o problema é tratado como "$", mas não tenho certeza.

Obrigado por qualquer ajuda antecipadamente.

    
por Vell 28.04.2015 / 20:16

2 respostas

3

Use printenv em vez , que não requer um shell:

capture('printenv ENV_VAR')

Substitua ENV_VAR pelo nome da variável de ambiente desejada. Não prefixar $ .

Embora printenv seja não POSIX , GNU / Linux sistemas como Debian, Ubuntu, Fedora e CentOS suportam porque GNU Coreutils fornece, e funciona em muitos outros sistemas * nix , como o FreeBSD. O motivo pelo qual você precisa usar printenv em vez de env é que printenv ENV_VAR gera o valor de ENV_VAR , enquanto env ENV_VAR tenta executar um comando chamado ENV_VAR , que não é o que você quer.

O restante deste post abrange outros métodos, suas limitações e como eles podem ser melhorados. Esta é uma leitura opcional, já que printenv é simples e resolve completamente o problema.

Seu método original , capture("env | grep ENV_VAR").split("=").last , não deve ser usado nem mesmo em um sistema em que parece funcionar, porque não é confiável. É grep s para o nome da variável em todos os lugares na linha VAR=val , e assim retornará resultados para variáveis cujos nomes - ou mesmo valores - contenham o nome da variável desejada. Usar ^ENV_VAR= em vez de ENV_VAR corrige esse problema, combinando o nome apenas quando ele aparecer na início da linha ( ^ ) e exigir que um caractere = apareça logo após. No entanto, é possível que o valor de uma variável de ambiente contenha um caractere = e, como você chama split e last , na verdade, você obtém a substring posterior mais longa do valor que não contém = . Mesmo se você consertou isso, o método ainda é desnecessariamente complexo quando tudo que você precisa é printenv .

A solução que você encontrou , capture("/bin/sh -c 'echo $ENV_VAR'") , funcionará mais de o tempo , mas retornará um valor incorreto quando a variável (a) contiver espaço em branco diferente de caracteres de espaço simples cercados por espaços não brancos, ou (b) contém caracteres globbing como * , ? e [ se eles corresponderem a qualquer nome de arquivo. O problema é que, no comando shell echo $ENV_VAR , a expansão do parâmetro $ENV_VAR não é citado , então divisão de palavras e globbing são executados. echo reinsere o espaço em branco, mas nem sempre da mesma maneira: echo foo bar imprime foo bar , mas echo foo bar . Esse problema pode ser resolvido colocando-se " " citações ao redor da expansão, embora você tenha que escapar delas para que o interpretador Ruby não as conclua como finalizando o " -quoted string e iniciando um novo, ou você pode ' -quote a string Ruby e escape de qualquer caractere ' interno.

Você também obtém um resultado errado na situação menos comum em que o valor ENV_VAR começa com uma opção que echo suporta. Diferentes implementações de echo suportam diferentes opções; -n e -e são comuns. A maioria dos shells tem echo como um builtin e pode suportar diferentes opções de outros shells e de /bin/echo . Isso é para dizer que echo não é muito portátil . É razoável inspecionar as variáveis de ambiente de forma interativa, quando você provavelmente perceberá se algo estranho está acontecendo, mas menos para o script. Os problemas de portabilidade de echo são exacerbados pela forma como /bin/sh nem sempre é bash . No Ubuntu ele é dash . Isso pode ser evitado usando printf '%s\n' ou printf "%s\n" em vez de echo (ou , no seu caso, printf %s pode ser suficiente).

Assim, sua solução pode ser melhorada para capture('/bin/sh -c \'printf "%s\n" "$ENV_VAR"\'') . Isso pode parecer errado para os shell scripters experientes que não conhecem Ruby; Observe que, ao contrário do Bash e de outros shells no estilo Bourne, Ruby trata \' como uma literal ' dentro de uma string ' ' -quoted. Mesmo que esteja correto, seus colegas terão que examiná-lo duas vezes para se certificarem disso, mesmo que sejam proficientes em scripts de shell e Ruby. capture('printenv ENV_VAR') é mais simples.

    
por Eliah Kagan 27.09.2017 / 08:03
0

Eu finalmente encontrei essa resposta. A maneira de fazer isso é carregar o shell bash e passar o comando para ele.

capture("/bin/sh -c 'echo $ENV_VAR'")
    
por Vell 28.04.2015 / 20:46