set variável dentro heredoc e usá-los fora

2

Estou tentando definir a variável 'count' ao executar o comando dentro de um heredoc junto com o tempo limite, mas não consigo obter a variável 'count' fora do heredoc.

Como posso conseguir isso?

  • Meu script é mais complexo, mas achei que a resposta seria suficiente.

    timeout 10 bash << EOC
       count=$(ls -l /tmp/ | wc -l)
    EOC
    
    echo "count: $count"
    
por Asaf Magen 01.05.2016 / 17:30

3 respostas

3

Você não pode. Variáveis atribuídas em um sub-shell não têm efeito no shell pai.

Faça isso:

count=$(timeout 10 ls -l /tmp/ | wc -l)
echo "count: $count"
    
por 02.05.2016 / 02:32
1

O que você está tentando fazer não pode funcionar, você terá que encontrar outro caminho. Quando você executa outro programa, ele tem seu próprio espaço de memória, ele não pode influenciar as variáveis no shell atual. Isso é verdade mesmo que o outro programa seja uma instância do mesmo shell que você está executando.

Usar um documento here em vez de bash -c não altera esse fato. Seu exemplo é equivalente a timeout 10 bash -c "count=$(ls -l /tmp/ | wc -l)" . (A propósito, isso executa ls -l /tmp/ | wc -l no shell externo, não na instância de bash que você gera: se você quisesse fazer o equivalente a timeout 10 bash -c "count=$(ls -l /tmp/ | wc -l)" , precisaria usar <<\EOF ou <<'EOF' ou algo parecido.)

Se você só precisa obter o valor de uma variável, pode usar uma substituição de comando:

count=$(timeout 10 bash -c '…')

Se você precisar definir muitas variáveis ou uma matriz, precisará fazer alguma codificação e decodificação. Você pode obter o bash para fazer isso por você: declare -p foo bar imprime uma maneira de definir foo e bar que foram citados corretamente para o shell de chamada.

eval "$(bash -c '…; declare foo bar')"

Note que isto declara variáveis localmente, então se você executá-lo em uma função, as variáveis não estarão disponíveis quando a função retornar. Se você precisar que as variáveis estejam disponíveis no retorno, será necessário atribuí-las novamente com declare -g ; isso só funciona para escalares:

f () {
  eval "$(bash -c '…; declare foo bar')"
  declare -g foo="$foo" bar="$bar"
}

Como alternativa, se você sabe que os valores das variáveis não podem conter novas linhas, remova declare -… do início de cada linha na saída de declare -p .

    
por 02.05.2016 / 02:44
0

Eu não acho que você pode conseguir isso. O grande problema é que você tem um processo bash avaliando um pipeline e, em seguida, armazenando o valor desse pipeline na variável count da shell. timeout em si não é um shell embutido no meu laptop Arch, então há um terceiro nível de processo. Como timeout bifurca o comando que aguarda, há um terceiro nível de processo.

Isso é shell-que-invoca-timeout - > tempo limite - > bash-invoked-by-timeout - > valor-de- count

Parece-me que você precisa reorganizar seu script de shell para poder usar o valor de count (ou seja o que for que você deseja realizar).

Se você realmente precisar do timeout no comando, provavelmente deverá enviar a saída do comando para um arquivo e depois ler esse arquivo:

if timeout ls -l /tmp > /tmp/some.well.known.name
then
    VAR=$(wc -l /tmp/some.well.known.name)
else
    : handle timeout
fi
    
por 01.05.2016 / 18:25