Shell ingresso scripting curiosità reindirizzamento

voti
16

Qualcuno può spiegare questo comportamento? In esecuzione:

#!/bin/sh
echo hello world | read var1 var2
echo $var1
echo $var2

risultati a niente essere ouput, mentre:

#!/bin/sh
echo hello world > test.file
read var1 var2 < test.file
echo $var1
echo $var2

produce i risultati attesi:

hello
world

il tubo non deve fare un passo ciò che il reindirizzamento a test.file ha fatto nel secondo esempio? Ho provato lo stesso codice con entrambe le conchiglie trattino e bash ed ho ottenuto lo stesso comportamento da parte di entrambi.

È pubblicato 05/08/2008 alle 20:26
fonte dall'utente
In altre lingue...                            


9 risposte

voti
11
#!/bin/sh
echo "hello world" | read var1 var2
echo $var1
echo $var2

produce nessuna uscita perché condutture corrono ciascuno dei loro componenti all'interno di una subshell. Subshell ereditano le copie delle variabili della shell genitore, piuttosto che la loro condivisione. Prova questo:

#!/bin/sh
foo="contents of shell variable foo"
echo $foo
(
    echo $foo
    foo="foo contents modified"
    echo $foo
)
echo $foo

Le parentesi definiscono una regione di codice che viene eseguito in una subshell, e $ pippo mantiene il suo valore originale dopo essere stato modificato al loro interno.

Ora provate questo:

#!/bin/sh
foo="contents of shell variable foo"
echo $foo
{
    echo $foo
    foo="foo contents modified"
    echo $foo
}
echo $foo

Le parentesi sono puramente per il raggruppamento, non si crea alcun subshell, e $ pippo modificato all'interno delle parentesi è lo stesso $ foo modificato fuori di essi.

Ora provate questo:

#!/bin/sh
echo "hello world" | {
    read var1 var2
    echo $var1
    echo $var2
}
echo $var1
echo $var2

Dentro le parentesi, il incorporato read crea $ var1 e $ var2 correttamente e si può vedere che ottengono eco. Al di fuori delle parentesi graffe, non esistono più. Tutto il codice all'interno delle parentesi è stato eseguito in una subshell perché è una componente di un oleodotto .

Si può mettere quantità arbitrarie di codice tra parentesi graffe, in modo da poter utilizzare questa costruzione di tubazioni-in-a-blocco ogni volta che è necessario eseguire un blocco di script di shell che analizza l'uscita di qualcosa d'altro.

Risposto il 19/09/2008 a 03:20
fonte dall'utente

voti
9

Questo è già stato risposto in modo corretto, ma la soluzione non è stato ancora dichiarato. Utilizzare ksh, non bash. Confrontare:

$ echo 'echo "hello world" | read var1 var2
echo $var1
echo $var2' | bash -s

A:

$ echo 'echo "hello world" | read var1 var2
echo $var1
echo $var2' | ksh -s
hello
world

ksh è un guscio programmazione superiore a causa di piccole sottigliezze come questo. (Bash è la shell interattiva migliore, a mio parere.)

Risposto il 15/08/2008 a 16:52
fonte dall'utente

voti
8

Un'aggiunta recente bashè l' lastpipeopzione, che permette l'ultimo comando in una pipeline per eseguire nella shell corrente, non una subshell, quando il controllo processo viene disattivato.

#!/bin/bash
set +m      # Deactiveate job control
shopt -s lastpipe
echo "hello world" | read var1 var2
echo $var1
echo $var2

infatti, saranno uscita

hello
world
Risposto il 26/07/2012 a 13:10
fonte dall'utente

voti
8
read var1 var2 < <(echo "hello world")
Risposto il 17/09/2008 a 01:17
fonte dall'utente

voti
5

Allright, ho capito!

Questo è un bug difficile da catturare, ma deriva dal modo in cui i tubi sono gestiti dalla shell. Ogni elemento di una condotta viene eseguito in un processo separato. Quando il set di comandi di lettura Var1 e var2, è imposta loro che il proprio subshell, non la shell genitore. Così, quando le uscite subshell, si perdono i valori di var1 e var2. È possibile, tuttavia, prova a fare

var1=$(echo "Hello")
echo var1

che restituisce la risposta attesa. Purtroppo questo funziona solo per singole variabili, non è possibile impostare molti alla volta. Al fine di impostare più variabili alla volta dovete o leggere in una variabile e tritarlo fino in più variabili o usare qualcosa come questo:

set -- $(echo "Hello World")
var1="$1" var2="$2"
echo $var1
echo $var2

Anche se ammetto che non è elegante come utilizzando un tubo, funziona. Ovviamente si deve tenere a mente che legge aveva lo scopo di lettura da file in variabili, in modo che lo rende letta dallo standard input dovrebbe essere un po 'più difficile.

Risposto il 05/08/2008 a 21:09
fonte dall'utente

voti
4

Il mio prendere su questo tema (utilizzando Bash):

read var1 var2 <<< "hello world"
echo $var1 $var2
Risposto il 04/03/2009 a 10:52
fonte dall'utente

voti
4

Il post è stato risposto correttamente, ma vorrei offrire uno di linea alternativa che forse potrebbe essere di qualche utilità.

Per l'assegnazione spaziali valori separati da echo (o stdout per questo) shell variabili, si potrebbe considerare l'utilizzo di matrici shell:

$ var=( $( echo 'hello world' ) )
$ echo ${var[0]}
hello
$ echo ${var[1]}
world

In questo esempio var è un array e il contenuto può essere raggiunto usando il costrutto $ {var [index]}, dove l'indice è l'indice di matrice (inizia con 0).

In questo modo si può avere come molti parametri come si desidera assegnare al l'indice dell'array in questione.

Risposto il 14/09/2008 a 18:00
fonte dall'utente

voti
4

È perché la versione tubo crea una subshell, che legge la variabile nel corrispondente spazio locale che poi viene distrutto quando le uscite subshell.

Eseguire questo comando

$ echo $$;cat | read a
10637

e utilizzare pstree -p di guardare ai processi in esecuzione, si vedrà un guscio in più appesa fuori dal guscio principale.

    |                       |-bash(10637)-+-bash(10786)
    |                       |             `-cat(10785)
Risposto il 05/08/2008 a 21:00
fonte dall'utente

voti
3

Provare:

echo "hello world" | (read var1 var2 ; echo $var1 ; echo $var2 )

Il problema, come più persone hanno dichiarato, è che var1 e var2 vengono creati in un ambiente di subshell che viene distrutta quando che esce subshell. I evita sopra distruggendo la sottoshell fino a quando il risultato è stato echo'd. Un'altra soluzione è:

result=`echo "hello world"`
read var1 var2 <<EOF
$result
EOF
echo $var1
echo $var2
Risposto il 17/09/2008 a 03:15
fonte dall'utente

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more