Shell script insette herleiding oddities
-
08-06-2019 - |
Vra
Kan iemand verduidelik hierdie gedrag?Hardloop:
#!/bin/sh
echo "hello world" | read var1 var2
echo $var1
echo $var2
resultate in niks om output, terwyl:
#!/bin/sh
echo "hello world" > test.file
read var1 var2 < test.file
echo $var1
echo $var2
produseer die verwagte uitset:
hello
world
Moet nie die pyp nie in een stap wat die herleiding te toets.die lêer het in die tweede voorbeeld?Ek het probeer om die dieselfde kode met beide die dash en bash skulpe en het dieselfde gedrag van beide van hulle.
Oplossing
In 'n onlangse toevoeging tot bash
is die lastpipe
opsie, wat die laaste opdrag kan in 'n pypleiding te voer in die huidige dop, nie 'n subskil, wanneer werk beheer is gedeaktiveer.
#!/bin/bash
set +m # Deactiveate job control
shopt -s lastpipe
echo "hello world" | read var1 var2
echo $var1
echo $var2
sal inderdaad uitset
hello
world
Ander wenke
#!/bin/sh
echo "hello world" | read var1 var2
echo $var1
echo $var2
produseer geen uitset want pyplyne loop elk van hul komponente binne'n subshell.Subshells erf afskrifte van die ouer shell se veranderlikes, eerder as deel van hulle.Probeer om hierdie:
#!/bin/sh
foo="contents of shell variable foo"
echo $foo
(
echo $foo
foo="foo contents modified"
echo $foo
)
echo $foo
Die hakies definieer'n streek van die kode wat loop in'n subshell, en $foo behou sy oorspronklike waarde na verander binne-in hulle.
Nou probeer om hierdie:
#!/bin/sh
foo="contents of shell variable foo"
echo $foo
{
echo $foo
foo="foo contents modified"
echo $foo
}
echo $foo
Die draadjies is suiwer vir die groepering, geen subshell is geskep, en die $foo verander binne-in die draadjies is die dieselfde $foo verander buite hulle.
Nou probeer om hierdie:
#!/bin/sh
echo "hello world" | {
read var1 var2
echo $var1
echo $var2
}
echo $var1
echo $var2
Binne-in die draadjies, die lees ingeboude skep $var1 en $var2 behoorlik en jy kan sien dat hulle kry eggo.Buite die draadjies, het hulle nie bestaan nie meer nie.Al die kode in die draadjies is loop in'n subshell want dit is een komponent van'n pyplyn.
Jy kan sit arbitrêre bedrae van die kode tussen draadjies, sodat jy kan gebruik om hierdie pype-in-'n-blok konstruksie wanneer jy nodig het om'n blok van shell script wat ontleed die uitset van iets anders.
Dit is reeds korrek beantwoord word, maar die oplossing is nog nie verklaar. Gebruik KSH, nie bash. Vergelyk:
$ echo 'echo "hello world" | read var1 var2
echo $var1
echo $var2' | bash -s
Aan:
$ echo 'echo "hello world" | read var1 var2
echo $var1
echo $var2' | ksh -s
hello
world
KSH is 'n uitstekende program dop as gevolg van min niceties soos hierdie. (Bash is die beter interaktiewe dop, in my opinie.)
read var1 var2 < <(echo "hello world")
Die post behoorlik beantwoord nie, maar ek wil graag 'n alternatiewe een sak wat dalk van 'n paar gebruik kan bied.
Vir die toeken van die ruimte geskei waardes van eggo (of stdout vir die saak) om veranderlikes dop, kan jy oorweeg om dop skikkings:
$ var=( $( echo 'hello world' ) )
$ echo ${var[0]}
hello
$ echo ${var[1]}
world
In hierdie voorbeeld var is 'n skikking en die inhoud kan verkry word met behulp van die konstruk $ {var [indeks]}, waar indeks is die skikking indeks (begin met 0).
Die manier wat jy kan soveel parameters het as jy na die relevante reeks indeks wil opgedra.
My siening oor hierdie kwessie (met behulp van Bash):
read var1 var2 <<< "hello world"
echo $var1 $var2
Allright, gedink ek dit uit!
Dit is 'n harde fout om te vang, maar die gevolg van die manier pype word hanteer deur die dop. Elke element van 'n pypleiding loop in 'n afsonderlike proses. Wanneer die lees opdrag stelle VAR1 en VAR2, is stel hulle dit sy eie subskil, nie die ouer dop. So wanneer die subskil uitgange, die waardes van var1 en VAR2 verlore. Jy kan egter probeer doen
var1=$(echo "Hello")
echo var1
wat gee die verwagte antwoord. Ongelukkig is hierdie net werke vir enkele veranderlikes, jy kan nie baie op 'n slag te stel. Ten einde meerdere veranderlikes gestel op 'n slag moet jy óf lees in een veranderlike en kap dit in verskeie veranderlikes of so iets gebruik:
set -- $(echo "Hello World")
var1="$1" var2="$2"
echo $var1
echo $var2
Terwyl ek erken dit is nie so elegant soos die gebruik van 'n pyp, dit werk. Natuurlik moet jy in gedagte hou dat lees veronderstel was om te lees van lêers in veranderlikes hou, so maak dit lees van standaard insette moet 'n bietjie moeiliker wees.
Dit is omdat die pyp weergawe is die skep van 'n subskil, wat die veranderlike in sy plaaslike ruimte wat dan vernietig lui wanneer die subskil uitgange.
Voer die opdrag
$ echo $$;cat | read a
10637
en gebruik pstree p om te kyk na die verloop prosesse, sal jy sien 'n ekstra dop hang af van jou belangrikste dop.
| |-bash(10637)-+-bash(10786)
| | `-cat(10785)
Drie:
echo "hello world" | (read var1 var2 ; echo $var1 ; echo $var2 )
Die probleem, soos verskeie mense het gesê, is dat var1 en VAR2 geskep in 'n subskil omgewing wat vernietig wanneer dit subskil uitgange. Bogenoemde vermy die vernietiging van die subskil totdat die gevolg is echo'd. Nog 'n oplossing is:
result=`echo "hello world"`
read var1 var2 <<EOF
$result
EOF
echo $var1
echo $var2