Shell scripting přesměrování vstupu a zvláštnosti

hlasů
16

Může mi někdo vysvětlit tento problém vyřešit? Běh:

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

Výsledky v ničem, že výstup signálu, zatímco:

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

vytváří očekávaný výstup:

hello
world

By neměla trubka dělat v jednom kroku, co přesměrování na test.file dělal v druhém příkladu? Snažil jsem stejný kód s oběma pomlčka a bash a dostali stejné chování z obou z nich.

Položena 05/08/2008 v 20:26
zdroj uživatelem
V jiných jazycích...                            


9 odpovědí

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

produkuje žádný výstup, protože ropovody každém ze svých složek uvnitř subshell. Subshells zdědí kopie proměnných mateřské společnosti Shell, spíše než jejich sdílení. Zkuste to:

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

Závorky definují oblast kódu, který se běží v subshellu a $ foo si zachovává svou původní hodnotu poté, co byl modifikován uvnitř nich.

Teď zkuste toto:

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

Závorky jsou pouze seskupení, je vytvořena žádná subshell a $ foo upravený uvnitř závorek je stejný $ foo upraven mimo ně.

Teď zkuste toto:

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

Uvnitř složených závorek, čtecí vestavěný vytváří $ var1 a var2 $ správně a můžete vidět, že si zopakoval. Mimo závorky, nemají nic víc neexistuje. Veškerý kód uvnitř závorek byl spuštěn v subshellu , protože je to jedna součást potrubí .

Si můžete dát libovolné množství kódu mezi rovnátka, takže můžete použít toto potrubí-do-a-blok konstrukci kdykoli budete potřebovat spustit blok shell skript, který analyzuje výstup něco jiného.

Odpovězeno 19/09/2008 v 03:20
zdroj uživatelem

hlasů
9

To již byla zodpovězena správně, ale řešení zatím nebyla uvedena. Použijte ksh, ne bash. porovnávat:

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

Na:

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

ksh je vynikající programování shell kvůli malé jemnosti, jako je tento. (Bash je lepší interaktivní shell, podle mého názoru).

Odpovězeno 15/08/2008 v 16:52
zdroj uživatelem

hlasů
8

Nedávný dodatek k bashje lastpipevarianta, která umožňuje poslední příkaz v potrubí spustit v aktuálním shellu, nikoli subshell, kdy je řízení úlohy deaktivována.

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

bude skutečně výstup

hello
world
Odpovězeno 26/07/2012 v 13:10
zdroj uživatelem

hlasů
8
read var1 var2 < <(echo "hello world")
Odpovězeno 17/09/2008 v 01:17
zdroj uživatelem

hlasů
5

V pořádku, jsem na to přišel!

To je těžká chyba chytit, ale výsledky z toho, jak trubky jsou zpracovány plášti. Každý prvek potrubí běží v samostatném procesu. Když příkaz čtení sady VAR1 a var2, je nastaví se jim to vlastní subshell, ne nadřazené shell. Takže když subshellu východy, dojde ke ztrátě hodnoty var1 a var2. Můžete však zkusit dělat

var1=$(echo "Hello")
echo var1

která vrací očekávanou odpověď. Bohužel toto funguje pouze pro jednotlivé proměnné, nelze nastavit mnoho najednou. Chcete-li nastavit více proměnných najednou, musíte buď načíst do jedné proměnné a prohánějí ji do více proměnných nebo použít něco jako toto:

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

I když jsem se přiznat, že to není tak elegantní jako použití potrubí, funguje to. Samozřejmě byste měli mít na paměti, že čtení měla číst ze souborů do proměnné, takže dělat to číst ze standardního vstupu by měla být o něco těžší.

Odpovězeno 05/08/2008 v 21:09
zdroj uživatelem

hlasů
4

My se k této problematice (pomocí Bash):

read var1 var2 <<< "hello world"
echo $var1 $var2
Odpovězeno 04/03/2009 v 10:52
zdroj uživatelem

hlasů
4

Příspěvek byl správně odpověděl, ale já bych chtěl nabídnout alternativní jednu vložku, že snad mohl být k užitku.

Pro přidělování prostor oddělené hodnoty z echo (nebo stdout na to přijde), aby shell proměnné, mohli byste zvážit použití shell polí:

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

V tomto příkladu var je pole a obsah lze přistupovat pomocí konstruktu $ {var [index]}, kde index je index pole (od 0 ° C).

Tímto způsobem můžete mít tolik parametrů, kolik chcete přiřadit k příslušnému indexu pole.

Odpovězeno 14/09/2008 v 18:00
zdroj uživatelem

hlasů
4

Je to proto, že verze trubka vytváří subshell, která čte proměnnou do svého lokálního prostoru, který pak je zničen, když subshellu východy.

Tohoto příkazu

$ echo $$;cat | read a
10637

a používat pstree -p se podívat na běžících procesů, uvidíte navíc shell visící z vašeho hlavního pláště.

    |                       |-bash(10637)-+-bash(10786)
    |                       |             `-cat(10785)
Odpovězeno 05/08/2008 v 21:00
zdroj uživatelem

hlasů
3

Snaž se:

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

Problém, jak více lidí uvedly, že var1 a var2 jsou vytvořeny v subshellu prostředí, které je zničeno, kdy to subshellu východy. Výše uvedené vyhýbá ničí subshell až do výsledku bylo echo'd. Dalším řešením je:

result=`echo "hello world"`
read var1 var2 <<EOF
$result
EOF
echo $var1
echo $var2
Odpovězeno 17/09/2008 v 03:15
zdroj uživatelem

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