Shell Scripting Eingabeumleitung Seltsamkeiten

stimmen
16

Kann jemand dieses Verhalten erklären? Laufen:

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

Ergebnisse in nichts sein ouput, während:

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

erzeugt die erwartete Ausgabe:

hello
world

Sollte nicht das Rohr in einem Schritt tun, was die Umleitung auf test.file im zweiten Beispiel tat? Ich habe versucht, den gleichen Code sowohl mit dem Bindestrich und Bash-Shells und bekam das gleiche Verhalten von beiden.

Veröffentlicht am 05/08/2008 um 20:26
quelle vom benutzer
In anderen Sprachen...                            


9 antworten

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

kein Ausgangssignal erzeugt , weil Rohrleitungen jeder ihrer Komponenten innerhalb eines Subshell auszuführen. Subshells erben Kopien der Variablen der Eltern - Shell, anstatt sie zu teilen. Versuche dies:

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

Die Klammern definieren eine Region-Code, der in einer Subshell ausgeführt wird, und $ foo behält seinen ursprünglichen Wert nach in ihnen modifiziert.

Jetzt versuchen Sie dies:

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

Die Streben sind rein für die Gruppierung wird keine Sub-Shell erstellt, und die $ foo in den geschweiften Klammern modifiziert ist die gleiche $ foo außerhalb sie geändert.

Jetzt versuchen Sie dies:

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

Innerhalb der geschweiften Klammern, erzeugt die Lese gebautet var2 richtig $ var1 und $ und Sie können sehen , dass sie Echo erhalten. Außerhalb der Zahnspange, gibt es sie nicht mehr. Der gesamte Code innerhalb der geschweiften Klammern wurde in einer Subshell ausgeführt werden, weil es ein Bestandteil einer Pipeline ist .

Sie können beliebige Mengen von Code zwischen Klammern gesetzt, so können Sie diese kochend in-a-Block-Konstruktion verwenden, wenn Sie einen Block von Shell-Skript ausführen müssen, die sonst die Ausgabe von etwas parst.

Beantwortet am 19/09/2008 um 03:20
quelle vom benutzer

stimmen
9

Dies wird bereits richtig beantwortet worden, aber die Lösung ist noch nicht festgestellt worden. Verwenden Sie KSH, nicht einschlagen. Vergleichen:

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

Zu:

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

KSH ist ein überlegenes Programmierung Shell wegen der kleinen Nettigkeiten wie diese. (Bash ist die bessere interaktive Shell, meiner Meinung nach.)

Beantwortet am 15/08/2008 um 16:52
quelle vom benutzer

stimmen
8

Eine kürzliche Neben bashist die lastpipeOption, die den letzten Befehl in einer Pipeline in der aktuell Shell ist, nicht eine Subshell, wenn Auftragssteuerung deaktiviert laufen zu lassen.

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

wird in der Tat Ausgang

hello
world
Beantwortet am 26/07/2012 um 13:10
quelle vom benutzer

stimmen
8
read var1 var2 < <(echo "hello world")
Beantwortet am 17/09/2008 um 01:17
quelle vom benutzer

stimmen
5

Allright, ich es herausgefunden!

Dies ist eine harte Fehler zu fangen, sondern ergibt sich aus der Art, wie Rohre werden von der Shell gehandhabt. Jedes Element einer Pipeline verläuft in einem separaten Prozess. Wenn die Lesebefehlssätze var1 und var2, ist sie es seinen eigenen Sub-Shell setzt, nicht den Schal Elternteil. Also, wenn die Sub-Shell beendet wird, werden die Werte von var1 und var2 verloren. Sie können jedoch versuchen zu tun

var1=$(echo "Hello")
echo var1

das gibt die erwartete Antwort. Leider funktioniert dies nur für einzelne Variablen, können Sie nicht zu einer Zeit, viele setzen. Um mehrere Variablen zu einem Zeitpunkt einzustellen, müssen Sie entweder in eine Variable lesen und zerhacken in mehrere Variablen oder so etwas wie folgt verwenden:

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

Während ich es nicht so elegant wie mit einem Rohr zugeben, es funktioniert. Natürlich sollte man bedenken, dass von Dateien in Variablen lesen gemeint war zu lesen, so macht es von der Standardeingabe lesen ein wenig härter sein sollte.

Beantwortet am 05/08/2008 um 21:09
quelle vom benutzer

stimmen
4

Meine Meinung zu diesem Thema (mit Bash):

read var1 var2 <<< "hello world"
echo $var1 $var2
Beantwortet am 04/03/2009 um 10:52
quelle vom benutzer

stimmen
4

Der Beitrag wird bereits richtig beantwortet, aber ich möchte einen alternativen Einzeiler bieten, die vielleicht von Nutzen sein könnten.

Für die Zuordnung Leerzeichen getrennt Werte von Echo (oder was das betrifft stdout) Variablen zu schälen, können Sie mit Hilfe von Shell-Arrays berücksichtigen:

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

In diesem Beispiel ist ein Array, var, und der Inhalt unter Verwendung des Konstrukts $ werden kann var {[index]} zugegriffen wird, wobei der Index der Arrayindex (beginnt mit 0).

Auf diese Weise können Sie beliebig viele Parameter haben, wie Sie auf den entsprechenden Array-Index zugewiesen werden sollen.

Beantwortet am 14/09/2008 um 18:00
quelle vom benutzer

stimmen
4

Es ist, weil die Rohr Version ist ein Sub-Shell zu schaffen, die die Variable in seinen lokalen Raum liest, die dann, wenn die Subshell Ausgänge zerstört wird.

Führen Sie diesen Befehl

$ echo $$;cat | read a
10637

und verwenden pstree -p auf die laufenden Prozesse zu betrachten, sehen Sie eine zusätzliche Hülle aus Ihrer Hauptschale hängen.

    |                       |-bash(10637)-+-bash(10786)
    |                       |             `-cat(10785)
Beantwortet am 05/08/2008 um 21:00
quelle vom benutzer

stimmen
3

Versuchen:

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

Das Problem, wie mehrere Leute gesagt haben, ist, dass var1 und var2 in einer Sub-Shell-Umgebung geschaffen, die, wenn die betreffenden Subshell Ausfahrten zerstört wird. Die oben vermeidet die Subshell, bis das Ergebnis zu zerstören hat echo'd worden. Eine andere Lösung ist:

result=`echo "hello world"`
read var1 var2 <<EOF
$result
EOF
echo $var1
echo $var2
Beantwortet am 17/09/2008 um 03:15
quelle vom benutzer

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