Manter os valores das variáveis globais pipeando através das funções

3

Eu escrevi um pequeno script bash usando sed em algumas páginas html para extrair algumas URLs.

Para evitar cada vez que pegar sed resulta em uma variável e depois lê-la novamente, eu simplesmente fiz 3 funções e cansei juntas.

first_function $1 | second_function | third_function

Digamos que:

  • a primeira função encontra urls de itens em uma lista de um dado href ( $1 )
  • a segunda função extrai de cada url canalizado uma imagem src
  • a terceira função monta o HTML de saída

no momento, eu faço eco de $lot_url em second_function , então posso read em third_function junto com $img_url e colocá-lo em HTML.

Seria mais limpo se eu pudesse mantê-lo como uma variável global acessível de second_function para third_function , mas parece que não posso.

Isso se torna mais necessário à medida que o número de valores a passar entre as funções aumenta.

Aqui está um código de amostra completo:

first_function(){
    curl -s "$1" | sed -nr '
        #extract sub urls
    '
}

second_function(){
    while read lot_url; do
        echo "$lot_url"
        curl -s "$lot_url" | sed -nr '
            #extract img src
        '
    done
}

third_function(){
    while read lot_url; read img_url; do
        echo "<a href="$lot_url"><img src="$img_url" /></a>"
    done
}

first_function "$1" | second_function | third_function
    
por neurino 22.02.2012 / 00:06

2 respostas

1

Os dois lados de um tubo estão em processos diferentes. Você não pode compartilhar variáveis entre esses processos. Se você quiser compartilhar dados, terá que passar pelo canal ou usar canais de comunicação alternativos. Se você precisa de canais de comunicação alternativos, você está acima dos recursos do shell, mude para uma linguagem de programação real.

Aqui, passar lot_url ao lado de img_url no segundo canal parece ser uma boa solução para mim. Eu passaria na mesma linha. Supondo que seus URLs tenham escapado corretamente, você não precisa de nenhuma citação específica, você pode passá-los na mesma linha. Isso teria a vantagem de permitir um número variável de img_url s em cada lot_url .

second_function(){
    while read lot_url; do
        echo "$lot_url"
        curl -s "$lot_url" | sed -nr -e '
            #extract img src
        ' -e "s>^>$lot_url >"
    done
}

third_function(){
    while read lot_url img_url; do
        echo "<a href="$lot_url"><img src="$img_url" /></a>"
    done
}
    
por 22.02.2012 / 01:43
0

Um único loop while faria aqui, eu acho. Eu acho que não faria diferença, na verdade, já que você está chamando executáveis a cada iteração de qualquer maneira. Desta forma você pode compartilhar a variável global que você esperava. Como:

source_cmd |
    while read var
    do  fn1 "$var" |
        fn2 "$var"
    done

Mas acho melhor ainda mudar um pouco o fluxo de trabalho - a função nada mais é do que um conjunto de comandos shell baseados em um array. Agora você não está usando o array para nenhum deles, então deve realmente servir para apontar um propósito comum para um conjunto de comandos - e o mais comum que eu vejo parece ser curl ... | sed ... . Então sugiro que você faça uma função que aceite parâmetros. Então, o resultado pode ser assim:

curl_sed() { url=$1 && shift
    curl -s "$url" | sed -nr "$*"
}
fn() { URL=$1 && shift
    set -- '#extract sub url sed script' \
           '#extract img src sed script'
    curl_sed "$URL" "$1" | 
        while read lot_url
        do  IFS='
';          printf '<a href="'"$lot_url"'"><img src="%s" /></a>\n' \
            $(curl_sed "$lot_url" "$2")
        done
}

Você já aceitou a resposta de Gilles a essa pergunta - aparentemente anos atrás, que eu não sabia - mas aqui está outra que demonstra uma metodologia semelhante à minha, e que eu acho que seria mais adequada para esse propósito.

    
por 11.07.2014 / 17:13