Como disponibilizar uma variável de um subshell no shell pai

11

Eu escrevi um script rápido e sujo para cronometrar alguns relatórios de um serviço da Web:

BASE_URL='http://example.com/json/webservice/'
FIRST=1
FINAL=10000

for report_code in $(seq 1 $FINAL); do
  (time -p response=$(curl --write-out %{http_code} --silent -O ${BASE_URL}/${report_code}) ) 2> ${report_code}.time

  echo $response  # <------- this is out of scope!  How do I fix that?
  if [[ $response = '404' ]]; then
    echo "Deleting report # ${report_code}!"
    rm ${report_code}
  else
    echo "${report_code} seems to be good!"
  fi
done

Preciso agrupar o timecomando em um subshell para poder redirecionar sua saída, mas isso torna o valor $responseindisponível para o shell pai. Como contornar esse problema?

iconoclasta
fonte

Respostas:

11

Você não pode trazer o valor de uma variável de um subshell para seu pai, não sem realizar uma organização e uma comunicação complicada e propensa a erros.

Felizmente, você não precisa de um subconjunto aqui. Redirecionamento requer apenas comando agrupamento com { … }, não um subnível.

{ time -p response=$(curl --write-out '%{http_code}' --silent -O "${BASE_URL}/${report_code}"); } 2> "${report_code}.time"

(Não se esqueça de aspas duplas em torno de substituições de variáveis .)

Gilles 'SO- parar de ser mau'
fonte
é engraçado que toda linguagem de programação possa fazer isso. eu já gastei 1h pesquisando no Google sem nenhuma solução possível. Estou desapontado.
Para Kra
1
@ToKra No. Nenhuma linguagem de programação pode fazer isso. (Quase) qualquer linguagem de programação pode trazer o valor de uma variável de uma sub - rotina ou bloco de instruções para seu pai, e é exatamente isso que explico na minha resposta: use o agrupamento de comandos em { … }vez de um subshell ( … ).
Gilles 'SO- stop be evil'
4

Usuários de U&L: Antes de votar minha resposta para usar o estilo C com main()função, visite este link: https://unix.stackexchange.com/a/313561/85039 O uso de funções principais em scripts é uma prática comum, usada por muitos profissionais no campo.


Como Gilles apontou, os subshells não podem disponibilizar variáveis ​​fora de seu ambiente. Mas vamos abordar esse problema de outro ângulo - se você escrever seu script em funções, é possível declarar a variável como locale que pode ser editada.

Do manual do bash 4.3, localdescrição:

... Quando local é usado em uma função, faz com que o nome da variável tenha um escopo visível restrito a essa função e seus filhos ...

Exemplo:

#!/bin/bash

outter()
{
    for i in $(seq 1 3)
    do
        var=$i
    done
}

main()
{
    local var=0
    outter
    echo $var
}
main "$@"
$ ./testscript.sh                                                                                                        
3

Como você pode ver após 3 iterações da função de loop, a variável é modificada.

Sergiy Kolodyazhnyy
fonte
Hmm, comportamento não intuitivo para programadores em C. Eu normalmente esperaria outterme referir a uma instância global de var.
Ruslan
Esta resposta tem algumas falhas. "$var"não é necessário na chamada outter. Não faz nada. E também local var=0não faz nada; a chamada ouf outtersobrescreve var, como você afirmou.
Golar Ramblar
@GolarRamblar removi "$var"como argumento posicional para outter; para ser justo, isso é um hábito. Você pode elaborar quanto à local var=0 parte?
Sergiy Kolodyazhnyy