redirection d'entrée de script shell bizarreries

voix
16

Quelqu'un peut-il expliquer ce comportement? Fonctionnement:

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

résultats en rien être ouput, alors que:

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

produit le résultat attendu:

hello
world

Ne doit pas faire le tuyau en une seule étape ce que la redirection vers test.file a fait dans le deuxième exemple? J'ai essayé le même code avec les deux tableau de bord et de coquillages bash et a obtenu le même comportement de deux d'entre eux.

Créé 05/08/2008 à 20:26
source utilisateur
Dans d'autres langues...                            


9 réponses

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

produit pas de sortie , car les pipelines fonctionnent chacun de leurs composants à l' intérieur d' un sous - shell. Sous - couches héritent des copies des variables du shell parent, plutôt que de les partager. Essaye ça:

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

Les parenthèses définissent une région de code qui est exécuté dans un sous-shell, et $ foo conserve sa valeur d'origine après avoir été modifié à l'intérieur.

Maintenant, essayez ceci:

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

Les accolades sont purement pour le regroupement, aucune sous-shell est créé, et le $ foo modifié à l'intérieur des accolades est le même foo $ modifié en dehors d'eux.

Maintenant, essayez ceci:

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

A l' intérieur des accolades, la lecture builtin crée var1 $ et $ var2 correctement et vous pouvez voir qu'ils se résonnaient. En dehors des accolades, ils n'existent pas plus. Tout le code dans les accolades a été exécuté dans un sous - shell , car il est un composant d'un pipeline .

Vous pouvez mettre des quantités arbitraires de code entre accolades, de sorte que vous pouvez utiliser cette construction tuyauterie en-un bloc chaque fois que vous devez exécuter un bloc de script shell qui analyse la sortie d'autre chose.

Créé 19/09/2008 à 03:20
source utilisateur

voix
9

Cela a déjà été répondu correctement, mais la solution n'a pas été dit encore. Utilisez ksh, bash pas. Comparer:

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

À:

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

ksh est une coquille de programmation supérieure en raison de petites subtilités comme celui-ci. (Bash est le shell interactif mieux, à mon avis.)

Créé 15/08/2008 à 16:52
source utilisateur

voix
8

Un ajout récent bashest l' lastpipeoption, qui permet la dernière commande dans un pipeline pour exécuter dans le shell en cours, pas un sous - shell, lorsque le contrôle de l' emploi est désactivé.

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

sera en effet sortie

hello
world
Créé 26/07/2012 à 13:10
source utilisateur

voix
8
read var1 var2 < <(echo "hello world")
Créé 17/09/2008 à 01:17
source utilisateur

voix
5

Allright, j'ai tout compris!

Ceci est un dur bug à attraper, mais les résultats des tuyaux de manière sont traités par le shell. Chaque élément d'un pipeline court dans un processus séparé. Lorsque les jeux de commandes de lecture var1 et var2, est les définit elle son propre sous-shell, pas le shell parent. Ainsi, lorsque les sorties de sous-shell, les valeurs de var1 et var2 sont perdus. Vous pouvez cependant essayer de faire

var1=$(echo "Hello")
echo var1

qui renvoie la réponse attendue. Malheureusement, cela ne fonctionne que pour les variables simples, vous ne pouvez pas mettre beaucoup à la fois. Pour définir plusieurs variables à la fois, vous devez soit lu en une seule variable et hacher en plusieurs variables ou utiliser quelque chose comme ceci:

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

Bien que je l'avoue est pas aussi élégant que l'aide d'un tuyau, il fonctionne. Bien sûr, vous devez garder à l'esprit que lire était censé lire des fichiers dans les variables, donc ce qui en fait lire l'entrée standard devrait être un peu plus difficile.

Créé 05/08/2008 à 21:09
source utilisateur

voix
4

Mon point de vue sur cette question (en utilisant Bash):

read var1 var2 <<< "hello world"
echo $var1 $var2
Créé 04/03/2009 à 10:52
source utilisateur

voix
4

Le message a été correctement répondu, mais je voudrais offrir une alternative d'une doublure qui pourrait peut-être d'une certaine utilité.

Pour l'attribution de l'espace des valeurs séparées de l'écho (ou stdout pour cette matière) à bombarder les variables, vous pouvez envisager d'utiliser des tableaux de shell:

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

Dans cet exemple var est un tableau et le contenu est accessible via la construction $ {var [index]}, où l'indice est l'indice du tableau (commence par 0).

De cette façon, vous pouvez avoir autant de paramètres que vous voulez affecter à l'index du tableau concerné.

Créé 14/09/2008 à 18:00
source utilisateur

voix
4

Il est parce que la version de conduite est de créer un sous-shell, qui lit la variable dans son espace local qui est détruit puis lors de la sortie de sous-shell.

Exécutez cette commande

$ echo $$;cat | read a
10637

et utiliser pstree -p pour examiner les processus en cours d'exécution, vous verrez une coquille supplémentaire accroché de votre coquille principale.

    |                       |-bash(10637)-+-bash(10786)
    |                       |             `-cat(10785)
Créé 05/08/2008 à 21:00
source utilisateur

voix
3

Essayer:

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

Le problème, comme plusieurs personnes ont déclaré, est que var1 et var2 sont créés dans un sous-shell qui est détruit lorsque que les sorties de sous-shell. Les évite ci-dessus jusqu'à ce que la destruction de la sous-couche le résultat a été echo'd. Une autre solution est:

result=`echo "hello world"`
read var1 var2 <<EOF
$result
EOF
echo $var1
echo $var2
Créé 17/09/2008 à 03:15
source utilisateur

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