cmd = "ezt hajtsd végre shellben";
cmd | getline változó;
close(cmd); # <- ez kell!
Igen, a close() argumentumában vissza kell idézni a teljes shell parancsot pontosan, onnan fogja azonosítani, melyik az a pipe, amelyet le kell zárnia.
- locsemege blogja
- A hozzászóláshoz be kell jelentkezni
- 216 megtekintés
Hozzászólások
Valami konkrét példát írnál, mert nálam nem úgy tűnik.
$ gawk "BEGIN { cmd=\"printf '%s\\n' a b c d\" ; while ( cmd | getline var ) { print var ; } ; } " /dev/null
a
b
c
d
$
- A hozzászóláshoz be kell jelentkezni
Nálam még ez is benne van a man-ban:
If using a pipe, coprocess, or
socket to getline, or from print or printf within a loop, you must use
close() to create new instances of the command or socket. AWK does not
automatically close pipes, sockets, or coprocesses when they return
EOF.
Szóval close nélkül EOF után a további getline hibát ad vissza, de ezt le kell kezelni; ha pedig close volt, akkor újra elindítja a programot.
- A hozzászóláshoz be kell jelentkezni
Addig nekem sem tűnt fel a close() hiánya, amíg egyetlen sort olvastam be, mert az sikerült. Feldolgozta majd kilépett az awk programom, így észre sem vettem. Viszont amikor a BEGIN {} szekcióban egy ciklusból hívtam azt a függvényemet, amelyikben volt egy cmd | getline var szerkezet, akkor a függvényem első hívása jól működött, az összes többi nem akadt el, visszatért ugyan, csak a var változóba már nem olvasta be, amit a cmd a pipe-ba tolt. Azt nem tudom, hogy a cmd egyáltalán lefutott-e, de talán. Nem futott le, emlékszem, nagyon gyorsan futott, a socat-nek viszont van egy time out-ja, szóval már a cmd-t sem futtatta.
Próbáld ciklusba írni, máris nem lesz olyan jó a helyzet close() nélkül!
Szerk.: külön tisztességtelen dolog az élettől, hogy egyszerű példaprogaramon nem jön ez elő. Legyen annyi elég, hogy van, amikor előjön, s az általam linkelt dokumentum szerint is kell a close().
tr '[:lower:]' '[:upper:]' <<<locsemegeLOCSEMEGE
- A hozzászóláshoz be kell jelentkezni
tr '[:lower:]' '[:upper:]' <<<locsemegeLOCSEMEGE
- A hozzászóláshoz be kell jelentkezni
No egy kicsit jobban megnézve - itt te mindig új parancsot akarsz futtatni és olvasni belőle - ekkor valóban kell a close.
- A hozzászóláshoz be kell jelentkezni
Amit linkeltem, abban is ez áll:
close(filename)or
close(command)The argument filename or command can be any expression. Its value must exactly equal the string that was used to open the file or start the command--for example, if you open a pipe with this:
"sort -r names" | getline foothen you must close it with this:
close("sort -r names")Once this function call is executed, the next
getlinefrom that file or command will reopen the file or rerun the command.
A két kiemelés tőlem.
tr '[:lower:]' '[:upper:]' <<<locsemegeLOCSEMEGE
- A hozzászóláshoz be kell jelentkezni
Amúgy tiszta hülye vagyok, elfelejtettem shellben programozni. Azt akarom, hogy legyen timestamp is. Ezt írtam:
cmd = "echo -ne '" s "' | socat -t 0.2 - 'file:" port;
cmd = cmd ",nonblock,rawer,b115200' | { date '+%s.%N'; od -An -v -tx1; }";
Aztán meg ezt:
cmd = "echo -ne '" s "' | socat -t 0.2 - 'file:" port;
cmd = cmd ",nonblock,rawer,b115200' | { date '+%s.%N' </dev/null; od -An -v -tx1; }";
De mintha az od nem kapná meg a névtelen függvénybe pipe-oltakat. Legfeljebb átveszem egy bash read-del.
tr '[:lower:]' '[:upper:]' <<<locsemegeLOCSEMEGE
- A hozzászóláshoz be kell jelentkezni
Ó, persze, a date beszúrt a végére egy newline-t. Így már jó:
cmd = "echo -ne '" s "' | socat -t 0.2 - 'file:" port;
cmd = cmd ",nonblock,rawer,b115200' | { echo -n `date '+%s.%N '`; od -An -v -tx1; }";
tr '[:lower:]' '[:upper:]' <<<locsemegeLOCSEMEGE
- A hozzászóláshoz be kell jelentkezni
No akkor ugorgyunk neki megint.
a) a példámat ha jobban megnézed, eleve ciklusban hívtam a cmd | getline formát
b) felnyitottam a bibliát(*), ez áll benne szó szerint:
It is also possible to pipe the output of another command directly into getline. Eg: the statement
while ( "who" | getline )
n++
executes the Unix program who (only once) and pipes its output into getline. The output of who is a list of users logged in. Each iteration of the while loop reads one more line from this list and increments the variable n ..."
c) ha minden getline használat uitán mondasz egy close(cmd) -t, akkor új és új processzeket fog kreálni. Ha ezzel szemben nincs close, akkor az eredeti processz fut és onnan olvas a getline. Amely egyébként EOF esetén 0-t ad vissza, később viszont -1 -et, ami viszont TRUE. Sőt. nemlétező fájlból átirányításkor vagy hibás parancs kimenete esetén is. Erről is ír a biblia, kb ezt:
"Ez a forma hibás:
while ( getline <"file" )
helyette ezt kell írni:
while ( getline < "file" > 0 )
- ugyanis az elsőnél nemlétező fájl esetén jó kis végtelen ciklust kapsz." Fenti példában az a szép, hogy a kisebb jel átirányítás, a nagyobb viszont a relációs operátor - azaz hogy csak addig fusson a while, amíg a getline el nem éri a fájl végét
Azaz tartom magam ahhoz, hogy PEBKAC, és nem gawk hiba. (Én egyébként ezért is tartok (most már) 4-féle awk-t a FreeBSD-men: the one true awk (nawk), gawk, mawk és most már goawk is. Nyilván akkor szívás van, ha építesz a gawk speciális tudására.)
(*) The AWK book by A & W & K
- A hozzászóláshoz be kell jelentkezni
Azt egy pillanatig sem állítottam, hogy ez awk bugos. Csak annyi történt, hogy nem ismertem a close() használatát awk-ban. Le kell zárjam, mert újabb socat-okat, od-okat és date-eket, no meg echo-kat akarok futtatni.
Egyébként van még egy hely, ahol megszívtam ezt. A printf() >file esetében. Kiírtam a stringemet, de a következő körben appendelte, mert nem zártam le a file-t. Most lezárom, így kénytelen legközelebb újranyitni, s felülírni a korábbit.
tr '[:lower:]' '[:upper:]' <<<locsemegeLOCSEMEGE
- A hozzászóláshoz be kell jelentkezni