Shell wejściowe skryptowy dziwactwa przekierowania

głosy
16

Może ktoś wyjaśnić to zachowanie? Bieganie:

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

Wyniki w niczym będąc Ouput, przy czym:

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

produkuje oczekiwany wynik:

hello
world

Nie powinno rura zrobić w jednym etapie, co przekierowanie do test.file zrobił w drugim przykładzie? Próbowałem tego samego kodu zarówno z myślnik i bash muszli i mam ten sam problem z obu z nich.

Utwórz 05/08/2008 o 20:26
źródło użytkownik
W innych językach...                            


9 odpowiedzi

głosy
11
#!/bin/sh
echo "hello world" | read var1 var2
echo $var1
echo $var2

nie tworzy żadnego wyjścia, ponieważ rurociągi uruchomienia każdego z ich elementów wewnątrz podpowłoce. Podpowłok dziedziczyć kopie zmiennych powłoce macierzystej, a nie dzielenie się nimi. Spróbuj tego:

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

Nawiasy zdefiniować obszar kodu, który zostanie uruchomiony w podpowłoce i $ foo zachowuje swoją pierwotną wartość po modyfikowany wewnątrz nich.

Teraz spróbuj tego:

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

Szelki są wyłącznie do grupowania, bez powłoki w tle jest tworzony i modyfikowany $ foo wewnątrz klamer jest taka sama $ foo zmodyfikowany poza nimi.

Teraz spróbuj tego:

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

Wewnątrz szelki, odczyt wbudowane tworzy $ i $ var2 zm1 prawidłowo i widać, że się echem. Poza szelkami, nie istnieje. Cały kod w nawiasach został uruchomiony w podpowłoce , ponieważ jest to jeden z elementów rurociągu .

można umieścić dowolne ilości kodu między szelkami, dzięki czemu można korzystać z tej budowy rurociągów-do-a-bloku, gdy trzeba uruchomić blok skryptu powłoki, który analizuje dane wyjściowe coś innego.

Odpowiedział 19/09/2008 o 03:20
źródło użytkownik

głosy
9

Zostało to już odpowiedział poprawnie, ale rozwiązanie nie zostało jeszcze określone. Użyj ksh, nie bash. Porównać:

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

Do:

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

ksh jest lepsza powłoka programowanie z powodu drobnych subtelności jak ten. (Bash jest interaktywny shell lepiej, moim zdaniem).

Odpowiedział 15/08/2008 o 16:52
źródło użytkownik

głosy
8

Niedawny uzupełnieniem bashjest lastpipeopcja, która pozwala ostatniego polecenia w rurociągu do uruchomienia w bieżącej powłoce, a nie podpowłoki, gdy kontrola zadaniem jest wyłączona.

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

rzeczywiście wyjście

hello
world
Odpowiedział 26/07/2012 o 13:10
źródło użytkownik

głosy
8
read var1 var2 < <(echo "hello world")
Odpowiedział 17/09/2008 o 01:17
źródło użytkownik

głosy
5

Allright, wyobraziłem go!

Jest to trudne bug złapać, lecz wynika ze sposobu rur są obsługiwane przez powłokę. Każdy element rurociągu biegnie w oddzielnym procesie. Kiedy zestawy poleceń odczytu zm1 i var2, to ustawia im, że własne powłoki w tle, a nie powłoki macierzystej. Więc kiedy wychodzi podpowłoki, wartości var1 i VAR2 zostaną utracone. Można jednak spróbować zrobić

var1=$(echo "Hello")
echo var1

która zwraca oczekiwaną odpowiedź. Niestety działa to tylko dla pojedynczych zmiennych, nie można ustawić wiele naraz. W celu ustawienia wielu zmiennych w czasie, należy albo przeczytać w jednej zmiennej i posiekać go na wiele zmiennych lub użyć czegoś takiego:

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

Choć muszę przyznać, że nie jest tak eleganckie, jak za pomocą rury, to działa. Oczywiście należy pamiętać, że czytać miała odczytać z plików do zmiennych, więc co czytać ze standardowego wejścia powinna być nieco trudniejsze.

Odpowiedział 05/08/2008 o 21:09
źródło użytkownik

głosy
4

Moje zdanie w tej kwestii (przy użyciu bash):

read var1 var2 <<< "hello world"
echo $var1 $var2
Odpowiedział 04/03/2009 o 10:52
źródło użytkownik

głosy
4

Post został prawidłowo odpowiedział, ale chciałbym zaoferować alternatywny jedną wkładkę, że być może się przydać.

Do przypisywania wartości oddzielone od przestrzeni echa (lub stdout dla tej sprawy) do zmiennych powłoki, można rozważyć użycie tablic powłoki:

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

W tym przykładzie var tablicy i zawartość można uzyskać za pomocą konstruktu $ {zmienna [indeks]}, gdzie wskaźnik jest wskaźnikiem tablicy (zaczyna się od 0).

W ten sposób można mieć tyle, ile chcesz parametry przypisane do odpowiedniego indeksu tablicy.

Odpowiedział 14/09/2008 o 18:00
źródło użytkownik

głosy
4

To dlatego, że wersja rura jest tworzenie podpowłoce, który odczytuje zmienną w swojej lokalnej przestrzeni, która następnie zostaje zniszczone, gdy wyjścia podpowłoki.

Wykonanie tego polecenia

$ echo $$;cat | read a
10637

i używać pstree -p patrzeć uruchomionych procesów, widać dodatkowa powłoka dyndał z głównego zbiornika.

    |                       |-bash(10637)-+-bash(10786)
    |                       |             `-cat(10785)
Odpowiedział 05/08/2008 o 21:00
źródło użytkownik

głosy
3

Próbować:

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

Problem, jak wiele ludzie stwierdzili, że zm1 i var2 tworzone są w środowisku podpowłoki, która jest niszczona kiedy wydostająca podpowłoki. Powyższe unika niszczenie powłoki w tle aż do wyniku został echo'd. Innym rozwiązaniem jest:

result=`echo "hello world"`
read var1 var2 <<EOF
$result
EOF
echo $var1
echo $var2
Odpowiedział 17/09/2008 o 03:15
źródło użytkownik

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