( Zahy | 2024. 08. 06., k – 21:26 )

Nincs itt semmi látnivaló, fent kb. minden lényegeset leírtak már (vannak marhaságok - "a read nem olvas a stdin-ről" - szerencsére kiigazítva; meg nem annyira marhaságok is).

Shell és a zárójelek:

{ } - a kapcsos zárójel NEM generál önmaga subshell-t (így a shell saját változói látszódnak), a közé zárt parancsok csoportosítására szolgál, a nyitó zárójelet el kell választani a mögé írt parancstól (szóköz, tabulátor vagy akár újsor), a záró zárójel pedig "parancs pozícióban" kell álljon, azaz vagy ; vagy & vagy soremelés után, azaz:

{ parancs1;parancs2;}

( ) - a kerek zárójel önmagában generál egy subshell-t a benne levő parancsok számára (melyben amúgy az eredeti shell lokális változóinak saját másolatai is elérhetőek). Ugyanúgy csoportosít, mint a kapcsos, de mind a nyitó, mind a záró tag akár egybe is írható a mögötte (előtte) levő paranccsal, azaz írható így:

(parancs1;parancs2)

 

Mind a kettő hatása, hogy a be- és kimenetek közösek lesznek a közbezárt parancsoknak, és értelemszerűen a ki- és bemenet (meg az stderr) együtt irányítható át. Lásd: mást jelenít meg a

cat < f ; cat < f

mint a

{ cat ; cat ; } < file

és ugyanez az eredménye kimenet szempontjából a

( cat ; cat ) < file

verziónak. A zárójel nélküli forma 2x írja ki az f file tartalmát, a zárójelesek meg egyszer

 

A { } specialitása, hogy a parancsok az eredeti shellben hajtódnak végre, így azon parancsok hatása, amelyek shellen belül okoznak változást, azok a zárójelen kívül (értelemszerűen: utána) is láthatóak. Ilyenek

- A változókkal kapcsolatos dolgok (változó létrehozása, módosítása, törlése, jellegének megváltoztatása - pl.  A=5; unset A ; readonly A; export A  ; typeset / declare parancs).

- A shell belső beállításaival kapcsolatos beállítások - ezeket jellemzően a set paranccsal szokás beállítani, de ide tartozik pl. a bash-féle shopt

- Hasonlóan kapcsos zárójelen belüli könyvtárváltás a zárójelen kívül is látható, míg kerek zárójelen (azaz egy al-shellen) belüli cd hatása nem érzékelhető a zárójelen kívül. (de amelyik shellnek van pushd, popd - és hasonló - directory stack kezelője, azok is így működnek)

- Shell aliasok (alias, unalias parancs) és shell-függvények (function parancs, unset -f parancs) létrehozása és törlése

- umask beállítás

- átadott paraméterek eldobása a shift paranccsal (vagy épp újrainicializálása a set -- paranccsal)

 

Ami pedig a pipe és a read  ilyetén működését illeti, elég jól dokumentálják a különböző manualok. Pl. a pdksh manual legvégén, a BUGS szekcióban ez áll:

BTW, the most frequently reported bug is
               echo hi | read a; echo $a   # Does not print hi
I'm aware of this and there is no need to report it.
 

Mindez azért szerepel így, mert  már az eredeti ksh (ma ksh88-ként szoktunk rá hivatkozni) is, meg az új verziójú ksh (ksh93) is ettől eltérően működik - ahogy a kérdésfelvetésben is látszik (szerintem amúgy némi dup / dup2 rendszerhívás-mágia segítségével lehetne megoldani). De nagyjából semmi más nem optimalizálja ki ezt az egyetlen speciális helyzetet (sh, ash, dash, bash, yash egyike sem - sőt látható, a pdksh sem, és gyanítom az ezen alapuló mirsh sem).

 

Ui: Újszülötteknek azt szoktam javasolni, hogy szorgosan olvasgassák a dokumentációt, egészen meglepő dolgokat lehet benne találni. (Pl. van olyan shell manual, amely explicit leírja, hogy egyes régebbi Bourne-shell szintaxist használó shellekben a ^ karakter a | szinonímája - és milyen jól jött ez a tudás, amikor az egyik rendszer konzolján gyakorlatilag lehetetlen volt elérni a | jelet.) Megtalálhatóak olyan - mai napig használható - csemegék, mint hogy a különböző összetett parancsok (for, while, until parancsok) használatakor a do / done helyett nyugodtan lehet a klasszikus { } zárójelpárt használni. :-) Ha valaki szeretne rendesen megismerkedni a shelle(kke)l (ez kb. minden *X admin számára nélkülözhetetlen lenne), akkor minimum azt értse meg, hogy mi  a különbség a shell belső és külső parancsainak végrehajtása között, de bátrabbak elindulhatnak megkeresni, hogy mi a különbség a (normál) belső parancsok és az un. (POSIX-) speciális belső parancsok végrehajtása között; ad absurdum, azt hogy melyek melyek, és ha nem tudom ezt fejből, hogyan lehet ezt szabályos eszközzel megkérdezni (hint type és whence parancsok, és megint csak a pdksh manualja elég korrekten leírja ezeket. Külön öröm, hogy pl. a bash nem jelzi ezt a különbséget, és ugyan a man-ban hivatkozik a POSIX special builtins nevű izére, de ki már nem fejti, hogy mi a frász is ez, és melyek ezek a parancsok. Tudom, GNU világban nem man van, hanem info. További pontosítás: mivel a bash ezeket csak POSIX módban különbözteti meg, ezért ezeket az infókat is csak POSIX-módban jeleníti meg.).

 

Jav:

kicsit pontosítottam és részletesebbé tettem a zárójelekben másként működő dolgok listáját, megjelent a bash POSIX-módja, és lett egy utóirat.