Come rendere disponibile una variabile da una subshell nella shell padre


11

Ho scritto uno script veloce e sporco per cronometrare alcuni rapporti da un servizio 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

Devo racchiudere il timecomando in una subshell in modo da poter reindirizzare il suo output, ma ciò rende il valore di $responsenon disponibile alla shell genitore. Come aggirare questo problema?

Risposte:


11

Non è possibile portare il valore di una variabile da una subshell al suo genitore, non senza fare marshalling soggetto a errori e comunicazioni ingombranti.

Fortunatamente, non hai bisogno di una subshell qui. Il reindirizzamento richiede solo il raggruppamento dei comandi con { … }, non una subshell.

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

(Non dimenticare le doppie virgolette attorno alle sostituzioni variabili .)


è divertente che ogni linguaggio di programmazione possa farlo. ho già trascorso 1 ora a cercare su google senza alcuna soluzione in shell. Sono deluso.
A Kra il

1
@ToKra No. Nessun linguaggio di programmazione può farlo. (Quasi) qualsiasi linguaggio di programmazione può portare il valore di una variabile da una subroutine o un blocco di istruzioni al suo genitore, ed è esattamente quello che spiego nella mia risposta: utilizzare il raggruppamento dei comandi { … }anziché una subshell ( … ).
Gilles 'SO- smetti di essere malvagio' il

4

Compagni di U&L: prima di effettuare il downgrade della mia risposta per l'utilizzo di C-style con la main()funzione, visitare questo link: https://unix.stackexchange.com/a/313561/85039 L' utilizzo delle funzioni principali negli script è una pratica comune, utilizzata da molti professionisti nel campo.


Come ha sottolineato Gilles, i subshells non possono rendere disponibili le variabili al di fuori del loro ambiente. Ma affrontiamo questo problema da un'altra prospettiva: se scrivi lo script in funzioni, è possibile dichiarare la variabile come locale che può essere modificata.

Dal manuale di bash 4.3, localdescrizione:

... Quando local è usato all'interno di una funzione, fa sì che il nome della variabile abbia un ambito visibile limitato a quella funzione e ai suoi figli ...

Esempio:

#!/bin/bash

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

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

Come puoi vedere dopo 3 iterazioni della funzione di loop, la variabile viene modificata.


Hmm, comportamento non intuitivo per programmatori C. Normalmente mi aspetto outterdi fare riferimento a un'istanza globale di var.
Ruslan,

Questa risposta ha alcuni difetti. "$var"non è necessario nella chiamata outter. Non fa nulla. E inoltre local var=0non fa nulla; la chiamata ouf outtersovrascrive var, come hai affermato.
Golar Ramblar,

@GolarRamblar Ho rimosso "$var"come argomento posizionale outter; per essere onesti, questo è per abitudine. Riesci a elaborare come local var=0 parte?
Sergiy Kolodyazhnyy,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.