Captura a saída de uma função de shell sem um subshell

3

Eu tenho rbenv (gerenciador de versão do Ruby) instalado na máquina e funciona assim:

$ rbenv local
2.3.1

Escrevendo para stdout a versão local do meu ruby. Eu quero resgatar esta versão e declará-lo em uma variável para reutilizar em outra ocasião.

$ declare -r RUBY_DEFINED_VERSION=$(rbenv local)
$ echo Using ruby version $RUBY_DEFINED_VERSION
Using ruby version 2.3.1

Funciona!

Mas eu não quero usar um subshell para fazer o trabalho (usando $() ou '' ). Eu quero usar o mesmo shell e eu não quero criar um arquivo tmp para fazer o trabalho.

Existe uma maneira de fazer isso?

Observação: declare -r não é obrigatório, pode ser um simples var=FOOBAR .

    
por dgmike 03.01.2017 / 15:06

3 respostas

4

Existe um hack, mas acho que faz sentido se você precisar de um loop.

você pode abrir cat coproc assim: coproc CAT { cat; }

Isso iniciará um comando cat em segundo plano e definirá duas variáveis de ambiente: CAT_PID e CAT . A variável CAT é uma matriz com STDOUT e STDIN (nesta ordem) descritor de arquivo (pipes) usado por cat .

Assim, você pode executar qualquer coisa gravando a saída em &${CAT[1]} que representa o STDIN e usar o comando interno read para definir a leitura da variável em ${CAT[0]} , que é o STDOUT de cat. / p>

Aqui uma amostra:

coproc CAT { cat; }
echo 123 >&${CAT[1]}
read myvar <&${CAT[0]}

Para testar:

echo $myvar
123

Não se esqueça de parar o gato depois de usá-lo. Você pode fazer isso matando o processo.

kill $CAT_PID

Isso faz uma grande diferença no ajuste de desempenho.

Espero que ajude.

    
por 29.03.2017 / 16:51
0

Com o bash você também pode fazer assim:

read a < <(echo hello)
echo "$a"

Ou assim:

shopt -s lastpipe
echo hello | read a
shopt -u lastpipe
echo "$a"

Mas você ainda precisa lançar um subprocesso que executará o ruby, então eu realmente não entendo o que você está tentando evitar ...

    
por 03.01.2017 / 18:47
0

Se no Linux, com bash você poderia fazer:

{
  rbenv local > /dev/fd/3
  IFS= read -rd '' -u 3 variable
} 3<<< ''

Isso usa um arquivo temporário como todos os documentos here ou here-string, embora isso esteja oculto para você.

Se rbenv gerar menos dados que podem caber em um canal sem bloquear (normalmente 64 KiB), ainda no Linux e no Linux, você pode usar um canal em vez do arquivo temporário com:

{
  rbenv local > /dev/fd/3
  IFS= read -rd '' -u 3 variable
} 3< <(:)

Com ksh93 , use a forma de substituição de comando que não inicia um subshell:

variable=${
  rbenv local
}

Tenha em atenção que, ao contrário do IFS= read -rd '' , remove os caracteres da nova linha à direita na saída (como todas as substituições de comandos).

    
por 29.03.2017 / 17:25