Dash, mint alapértelmezett shell a Fedora-ban?

A bash Shellshock sebezhetőségének fényében egyesekben felmerült, hogy lenne-e értelme annak, hogy a Fedora-ban - hasonlóan ahhoz, ahogy a Debian-ban és Ubuntu-ban van - alapértelmezetté tegyék mint nem-interaktív shell-t a dash-t, azaz a Debian Almquist Shell-t.

A felvetés nyomán egy hosszabb thread indult. A szálban többek közt a Red Hat alkalmazásában álló Lennart Poettering is kifejtette véleményét.

Hozzászólások

tl;dr, de gondolom Poettering ír egy PASH-t a systemdbe?

Az összes haterkedéssel együtt azért azt is illik észrevenni, hogy egész más az, hogy Lennart az upstream-nek/package maintainereknek csinál plusz munkát, vagy hogy ezzel a döntéssel az adminoknak csinálnak plusz munkát...

BlackY
--
"en is amikor bejovok dolgozni, nem egy pc-t [..] kapcsolok be, hanem a mainframe-et..." (sj)

Csak hogy jól értem-e: Poettering csinál egy új init rendszert, ahol a portolási munkát upstream/package maintenerek elvégzik és ezért rohaggyon meg, mert új dolgot kell megismerni. Poettering felveti, hogy nem kéne megtörni a házilag tákolt scripteket (amiket egy ilyen változtatás után auditálni kellene, mert ez egy API törés) és ezért rohaggyon meg, mert aki nem változtat, amiatt megáll a fejlődés...

Azért ezt a listát https://wiki.ubuntu.com/DashAsBinSh elnézve lehet megtörne egy-két script világszinten...

BlackY
--
"en is amikor bejovok dolgozni, nem egy pc-t [..] kapcsolok be, hanem a mainframe-et..." (sj)

Én csak azt nem értem, hogy ha valaki bash-specifikus dolgot használ, akkor miért nem a bash interpreterre hivatkozik. Én tudom magamról, hogy kihasználom a bash ámokfutásait, ennek megfelelően #!/bin/bash az, amit a script elejére írok. Szerintem akkor írjon valaki sh-t, ha csak a minimumot használja, ami talán POSIX, de ehhez nem értek, gondolom, le van valahol írva, mi a kötelező minimum.

tr '[:lower:]' '[:upper:]' <<<locsemege
LOCSEMEGE

Ez egy teljesen jogos érvrendszer. A gond ott van, hogy
1) nem mindenki írja ki a bash-t, talán lustaságból, talán mert meg vagy győzödve arról, hogy hordozható scriptet írt (aztán meg mégsem)
2) ha mégis kiírja, az sem segít, ha valami másik script pl. simán "."-al behúzza - ekkor ugye a shebangtől függetlenül abban a shellben fog futni, amiből hívták
...

BlackY
--
"en is amikor bejovok dolgozni, nem egy pc-t [..] kapcsolok be, hanem a mainframe-et..." (sj)

Azért, mert valaki korábban lusta volt, most ne lehessen shellt váltani? Ráadásul, ahol probléma az áttérés, egyszerűen bash interpretert kell megadni, illetve az adott csomag függőségeként meg kell adni a bash-t.

Egyébként van ilyen, a legutolsó changelogot nézzétek:

http://koji.fedoraproject.org/koji/buildinfo?buildID=581515

ip[6]tables.init: change shebang from /bin/sh to /bin/bash (RHBZ#1147272)

tr '[:lower:]' '[:upper:]' <<<locsemege
LOCSEMEGE

Félre ne érts, nem azt mondom, hogy ne váltsanak (kb. nem érdekelne, ha eltörik valami script, átírom, "nagyon jó móka" shell scriptet debugolni. Ahol mondjuk a két plusz karakter beszúrásához több száz oldal papírmunka kell, azokat nem irigylem).
Ami nem tetszik, az a van rajta - nincs rajta sapka elv, amit Poetteringgel szemben tanúsítanak sokan: jogos biztonsági, kompatibilitási stb. érveket hoz fel, amire a válasz az, hogy "ezt pont ő mondja" és lesöpörjük őket az asztalról mondván, hogy max. módosítjuk a scripteket.

BlackY
--
"en is amikor bejovok dolgozni, nem egy pc-t [..] kapcsolok be, hanem a mainframe-et..." (sj)

+1

tokeletesen egyetertek veled.

egyebkent szerintem itt szepen leirjak az sh-t.

http://pubs.opengroup.org/onlinepubs/9699919799/utilities/sh.html
http://pubs.opengroup.org/onlinepubs/009604599/utilities/xcu_chap02.html
--
A legértékesebb idő a pillanat amelyben élsz.
https://sites.google.com/site/jupiter2005ster/

Az emberek több, mint 99%-a azt se tudja mi az, hogy bash. Aki pedig parancsfájlokat ír, azok jelentős része nincs tisztában azzal, hogy mi bash-specifikus (mint ahogy azzal sem, hogy mi az ami linuxizm). És míg az utóbbi nem akkora gáz, hisz Linuxra írja a vackait, addig az előbbi komoly probléma. De mit lehet kezdeni azon kívül, hogy folyton szajkózzuk, hogy mit hogyan kell írni?
OT: én anno szórakoztam azzal, hogy "mértem" hogy van-e időkülönbség a között, hogy mi módon növelem egy i változó értékét eggyel. És nem mondom hogy komoly, de mérhető, reprodukálható különbség volt adott shellen belül. De persze nem minden shell ugyanúgy volt lusta/gyors. (És akkor még nem vettem figyelembe, hogy van olyan, amit pl. a bash tud, de a FreeBSD saját - ash-n alapuló - shellje már nem.) Aki parancsfájlokat ír, elvben ilyesmit is figyelembe vehet(ne). Hányan fogják letesztelni, hogy hagyományos Bourne-shell, vagy ash, vagy dash, bash, zsh, 3-féle Korn-shell (eredeti, pdksh, mksh, - esetleg ksh88 vagy ksh93) használatakor melyik a legjobb.

Íme néhány példa:

1. i=`expr "$i" + 1` # ez a leghordozhatóbb, de totál olvashatatlan, és a plusz processz miatt a lehető leglassabb.
2. i=$(( $i + 1 )) # ez az egyetlen olyan, amit a legtöbb shell megért - kivéve originál Bourne-shell -, és mivel nincs alprocessz, emberi a tempója
3. (( i = i + 1 ))
4. (( i++ ))
5. let i=i+1
6. let i="$i + 1"

Ezt meg lehet fejelni azzal, hogy a 2. és 3. esetben a shell működése miatt az = jobb oldalán i is írható, meg $i is. (Hasonlóan a let parancs esetén, mint az 5. és 6. példában.) Az se mindegy, hogy rakok-e szóközt (ekkor kell az idézőjel), vagy nem. De a 3. és 4. formát az ash nem ismeri (a dash-ról nem tudom mi a helyzet). Bonyolító tényező, hogy az 5. és 6. a FreeBSD-s natív shellben nincs dokuentálva, de működik. Vicces módon végrehajtja ugyan a műveletet, de mellesleg kiírja az i új értékét (amitől mondjuk parancsfájlban nem biztos, hogy boldog lennék). És ezt ugye fejeljük meg azzal, hogy a Korn-shell dokumentációja valahogy úgy fogalmaz, hogy a let "i z é" és a (( i z é )) - pontosan ugyanaz.
Nos ha ezeket valakinek nem magyarázzák el, akkor odahány valamit, aztán vagy hordozható lesz, vagy nem. Ha meg elmagyarázzák, akkor itt megy el a kedve az egésztől. Pedig ez az egész dolog pont ugyanolyan, mint az hogy K&R C vagy ANSI C, és azon belül is melyik verzió (89, 99, stb); vagy hogy 1.4-es, 1.5-ös, stb. Java. Azt is sok év után tanulja meg átlag programozó, meg ezt is. Csak míg C, Java, stb nyelven általában némi tanulás után szoktak programozni, addig shell-scriptet ír minden óvodás.

És akkor ezt még nem is írtad:

7. ((i+=1))

Én a saját scriptjeimben nem törekszem a hordozhatóságra, mert felmerül bennem, hogy akkor mégis mi a fenének van az a rengeteg feature a bash-ben, ha a fegyelmezettség miatt úgysem használnám. Ha már ott van, használom, csak annyi, hogy nem sh-t írok interpreternek, hanem bash-t. Ha a Fedorában lecserélik a bash-t dash-re, akkor sem esek kétségbe. Vagy megírom a scriptjeimet a szűkösebb nyelvi készlet felhasználásával, vagy bash-t használok interpreternek, és mindent úgy csinálok, mint eddig.

tr '[:lower:]' '[:upper:]' <<<locsemege
LOCSEMEGE

Meg ezt sem:

8. let "i += 1"

Ha valaki /bin/bash -t ír, akkor nyugodtan használjon bash specifikus dologat. De ennek csak akkor van igazán értelme, ha az a valami másban nem elérhető - más, esetleg a bashban is meglevő formában sem. Mondjuk a saját, esetleg mások életét tudja megkönnyíteni azzal, ha azokat a dolgokat, amik más shellben is megvannak, abban a formában írja, ami a másik shellnek is megfelelő. Azaz sajnos az eddigi felsorolásból a 2. (meg nyilván az 1.) az, amit használva később nem kell módosítani semmit - ha például egy indító script-ről beszélünk, akkor egy bash - dash csere után sincs gond. Pár napja már leírtam itt valahol, én elsősorban olyasmire gondolok, mint

- "function x { ...; }" vagy "x() { ...; }" használata a bash-ban épp még elfogadott "function x() { ...; }" helyett

- "typeset -i i" írása a "declare -i i" helyett; csak arra kell gondolni, hogy írhatnám a sokkal olvashatóbb "integer i"-ként is, akkor meg a bash kapna tőle hülyét, pedig maga a lehetőség Korn-shellben ugye adott. Hasonló okokból én jobb szeretem az "export X"-et a "typeset -x X" (vagy akár "declare -x X" helyett).

- ". fnév" a "source fnév" helyett

- továbbmegyek, mivel a for i in {1..10} az egyéb általam használt rendszereken nem megy, én sosem írok így ciklust, noha nagyon kényelmes lenne; helyette leírom a sokkal hosszabb, de hordozható while ciklust. És mivel a seq is leginkább csak Linuxon létező parancs, ezért nem írom így se: for i in $(seq 1 10) .

(Most jól meglepődtem egyébként, mert ezt találtam a saját gépemen:

"The seq command first appeared in Plan 9 from Bell Labs. A seq command appeared in NetBSD 3.0, and ported to FreeBSD 9.0. This command was based on the command of the same name in Plan 9 from Bell Labs and the GNU core utilities. The GNU seq command first appeared in the 1.13 shell utilities release."

Szóval lassan akár FreeBSD-n is használhatnám, de nem teszem. Anno a BSD-specifikus jot parancsot felhasználva csináltam saját seq-et, ujjgyakorlatként.)

(Ja, szerintem alig akad olyasmi, amit POSIX-shellben nem lehet megcsinálni, bash-ban meg igen. A többsége a bashizmeknek szimplán szokás kérdés. (Mint fenti {1..10} , vagy pl a &>fnév formájú átirányítás.)

Azaz: kis odafigyléssel elég hamar meg lehet szokni, hogy úgy írja meg az ember, hogy később nem fut bele inkompatibilitási dolgokba. Ha meg valaki kényelmes most, később esetleg lesznek kényelmetlenségei. Egy kedves ismerős ezt úgy szokta a fejemhez vágni: a kompatibilitás látszólagossága okán én folyton hüvelykszorítóban dolgozom, ő meg kényelmesen él. Ma. Holnap meg esetleg mégse.

Pedig azért van néhány jó dolog bash-ben, az egyik az általad is említett brace expansion. Efféle ciklusokat én C-szerűen írok, de nem vagyok róla meggyőződve, hogy hordozható:

for ((i=1; i<=10; i++)); do ...; done

Amit szeretek, az a here string:

cut -d: -f5 <<<"`getent passwd locsemege`"

Vagy a process substitution. Jól tud jönni akkor, amikor a pipe miatt subshellben futna a ciklus, ezért a hívó shellből nem látszanának a változók:
while read; do
...
done < <(ls -1)

tr '[:lower:]' '[:upper:]' <<<locsemege
LOCSEMEGE

Ezt a fajta for ciklust sem az ash, sem a ksh88 (pdksh, mksh) nem ismeri, de a ksh93 már igen. Ugyanez igaz a process substitution-ra is és a here string-re. Tudtommal POSIX-ban sem szerepel ezek egyike sem. A <(..) az egyetlen, amit elég macerás kicserélni hordozható kódra (bár régebbi rendszereken "mknod /tmp/pipe.$$ p", újabbakon "mkfifo /tmp/pipe.$$" -ral helyettesíthető - de ugye ebben az esetben minimum egy takarítás még szükséges.)

Ezért mondtam, hogy eléggé bash-specifikus, de ha már van, használom. Mondjuk a cut-os példám elég béna, ebben a formában viszonylag értelmetlen, ugyanúgy két process fut, mint pipe esetében lenne. Viszont, ha változó tartalmával csinálom a here stringet, már jobban jövök ki, mint ha echo $változó tartalmát pipe-olnám a cut-nak.

Ha named pipe-ot csinálsz, akkor viszont az egyik - például a fifo-t író - folyamatot a háttérben kell indítani, ha jól gondolom, míg a másik az aktuális shellben szedi ki a fifo-ból a cuccot.

tr '[:lower:]' '[:upper:]' <<<locsemege
LOCSEMEGE

Jaja, háttérprocesszt akartam is írni, de valahogy elmaradt. Illetve lehet még játszani koproceszekkel, de azt rohadtul ksh-inkompatibilis módon rakták bele a bash-ba. (Ím koprocesszek:

ksh93> echo jaj |& while read a ; do echo "$a"; done <&p
bash> coproc echo jaj ; while read a ; do echo "$a" ; done <&${COPROC[0]}

Ami a bash-féle megoldásban külön gyönyörű, hogy ha interaktívan csinálok koprocesszt, és mire begépelem a feldolgozó parancsot addigra befejeződik, akkor nem lehet többé elérni a kimenetét. Ksh-ban várhatok 5-10 percet is, akkor is elérem a kimenetét. (Nyilván, ha a koprocessz stdin-re vár - tehát nem fejeződik be, akkor kb. ugyanúgy működnek.)

Nincs ertelme, ahogy mas distrokban sem volt.

Amit nem lehet megirni assemblyben, azt nem lehet megirni.

Ha kicsi shell kene ott van a busybox sh.

time busybox sh -c "echo hello"
hello

real 0m0.001s
user 0m0.000s
sys 0m0.000s

time bash -c "echo hello"
hello

real 0m0.002s
user 0m0.001s
sys 0m0.000s

time dash -c "echo hello"
hello

real 0m0.002s
user 0m0.000s
sys 0m0.001s

A startup time kulombseg kb. meresi hiba, de busybox gyorsabb mint a bash vagy dash.
Rendszerint busybox van az initramfs -ben.

Hasono dolog 1000 loopban:
busybox:
real 0m0.383s
user 0m0.043s
sys 0m0.107s

dash:
real 0m0.537s
user 0m0.048s
sys 0m0.107s

bash:
real 0m1.030s
user 0m0.151s
sys 0m0.259s

1000 script (nem paralell) inditasanal lathatsz 0.5 sec kulombseget.
A boothoz 100 as nagysagrandu scriptet szokas futatni es parhuzamosan.
Igazi gyursulast az jelentene, ha a shell scriptek szama csokene,
vagyis nem shell alapu init rendszer.

Ha dash scriptnek, valamiert tobb kulso parancsot kell hivnia (akkar egyel is), mint a bash-nek,
akkor rogton bebuktad az elonyt.

1000 python hello meg ettol is lassabb:
real 0m12.739s
user 0m9.468s
sys 0m2.841s

python -ban irt parancsokat hasznalani rendszerint lassu
a module import miatt ettol lenyegesen lassabb is lehet.

Amit nem lehet megirni assemblyben, azt nem lehet megirni.