posix sh kompatibilitás

 ( chx | 2016. július 14., csütörtök - 14:23 )

Hello Hupperek,

Racionalizálás okán a jövőben szeretnék olyan shell scripteket fejleszteni amik minden un*x-on működnek, ha jól tudom áldoznom kell a kompatibilitás oltárán, azaz POSIX kompatibilisnek (posix-sh) maradni. Mit használhatok amiben ha megírok valamit, és majd egyszer pl. egy Solarison, vagy Cygwin-en fogja futtatni valaki, tuti jól működjön majd? Perl és Python nincs mindenhol, ebbe az irányba nem tudok elmenni.

Lehetőségek Linuxon:
dash - "...virtually compatible with the POSIX standard's specification of the Unix shell"
ksh - "KornShell complies with POSIX.2"
bash - "Bash is a POSIX shell, but with a number of extensions."
zsh - ???
csh - ???

Így elsőre dash vagy ksh. Ok hogy a ksh93 más, de pl. AIX-os kollégák azt mondják hogy a Linux-os ksh és az AIX-os ksh sem ugyanaz. Esetleg ajánlhatnátok valamit, kb. vagy ksh vagy dash.

Köszönöm szépen.

Hozzászólás megjelenítési lehetőségek

A választott hozzászólás megjelenítési mód a „Beállítás” gombbal rögzíthető.

A legfapadosabb, legkevésbé komfortos shell, amit próbáltam, a dash. Pl:

trap '' HUP    # ezt megeszi
trap '' SIGHUP # ezt nem

printf '\033'  # ezt megeszi
printf '\x1b'  # ezt nem

f () {          # ezt megeszi
function f () { # ezt nem

Csak az utolsóhoz annyit, hogy

function f {
...
}

formában meg kell ennie. Azaz vagy (), vagy function, de nem mind a kettő. (Az utóbbi tipikus bashizm.)

Nem nyert;)

$ function f {
dash: 1: function: not found

Mondtam, hogy nem komfortos...

Aha, akkor az a dash valszeg inkább UNIX v7-es shell, mint POSIX. "select" nevű utasítás, vagy $( parancs ) forma van a `parancs` mellett? Vagy esetleg $(( kif )) ? Ezek még ilyen nagyon új (POSIX) funkciók

Ez pl. megy:

$ echo $(date)
Fri Jul 15 13:23:31 CEST 2016

'select' nem mond neki semmit (nekem sem, úgyhogy ez nem panasz;)

A select az pont egy ksh-ban kitalált és POSIX-ba beemelt, gyakorlatilag bugyuta, menüépítésre kitalált ciklusszervező utasítás.

select i in alma narancs szilva ; do
case "$i" in
alma) # ide jön az alma kiválasztása esetén végrehajtandó utasítássorozat
;;
narancs) # ide a narancs
;;
szilva) # ide meg a szilva
;;
esac
done

Lefuttatásakor kapsz egy

1) alma
2) narancs
3) szilva
#?

kinézetű menüt, 1 kiválasztásával eléred "alma"-t, 2-vel ....
És amikor lefutott, akkor újra menükiiratás és adatbevitel. A PS3 változóval a #? - mint prompt módosítható valami értelmesebbre, pl:

PS3="Válassz a fenti számok közül az egyes funkciók eléréséhez "

+1

Solarison ~15 éve van by default bash (talán a 7-esben jött be, ha jól emlékszem). A Cygwin GNU utilitykből áll, tehát ott eleve kéne legyen bash. AIX/HPUX vonalon nem tudok nyilatkozni, de nagyon meg lennék lepve, ha egy mai verziójukban ne lenne bash.

A csh nem is Bourne-kompatibilis, már egy if szintaxisa is tök más.

A szomorú helyzet amúgy az, hogy ha feature-ökre is szükséged van, és a bash alá adod, akkor gyorsan eljuthatsz arra a szintre, hogy az igényt nem fedi le a legnagyobb közös osztó, és elkezded telirakni a scriptet OS-függő hackolásokkal. Akkor meg már inkább a perl...

Off: nemrég a Perl-ben íródott yasql-t telepítettem, örömmel láttam, hogy az újabb Perl már nem futatja, egy-két 'do' kulcsszót ki kellett szedni a programból; ami eddig opcionális volt, az most már tilos.

Még szerencse, hogy a konkurrencia (PHP, Python) sem idegenkedik az inkompatibilis változtatásoktól...

Hát izé, nem sok olyannal találkoztam, amit a bash tud, de a Korn-shell nem (és a programozhatóság szempontjából kihasznált eszköz lenne). HP-UX alatt sokáig nem volt bash, aztán egy darabig igen, de ha jól emlékszem mostanság megint nem része az alaprendszernek. Van helyette Korn-shell (ksh88), meg dtksh néven az újabb verzió (ksh93 alapon), és persze HP-UX-on eléggé régóta eleve a ksh88-ra épülő Posix-shell az alapértelmezett. (Mintha kb ugyanez lenne a helyzet AIX-szel is, de majd kijavít aki pontosan tudja.)
Sokkal nagyobb baj a bashizmek használata - akkor is, ha azt a funkciót le lehet írni másként is (pl. olyan formában, amit évszázadok óta tud a Korn-shell). Sokszor utaltam már rá:
source a . helyett
function x() - a function x illetve az x() forma helyett

Illetve szintén nagy probléma a linuxizmek; tipikusan szkriptekben pl: for i in `seq 1 100` - amivel csak az a baj, hogy seq nem sok nem-Linux rendszerben van. (Konkrétan talán Solarisban, de a többiben amik még egyáltalán léteznek, egyikben sem.)

A seq helyett mit kellene? Ahogy nézem, a jot pedig linuxon nem alapértelmezett.

A válasz, hogy nem for ciklussal kéne az ilyet megírni, hanem while-lal/until-lal :-) És igen, én magamnak az asztali gépemen a jot-tal (meg némi shell varázslással) implementáltam a seq-et.

Az asztali gépeden nem FreeBSD van?

De, és ez miért ellentmondás? Azért implementáltam a seq-et, hogy random linuxos oldalról "vakon" kopipésztelt huncutságokat ne kelljen még ezen a szinten is kijavítanom :-)

Nem ellentmondás, csak akkor egy kicsit feleslegesnek érzem a jot-tal létrehozott seq-wrappered:

$ which seq
/usr/bin/seq

Azaz a seq az alaptelepítés része.

No megnéztem a man-t:
"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."
Most hogy írod, már kezd derengeni, hogy valamikor olvastam erről, de azért az ilyen felesleges dolgokat azért nem mind szoktam megjegyezni. Mindenesetre kösz, most egy-két hétig megint fogom tudni.

Hát, aki régi motoros, biztos sok olyan verziót használt, ahol még nem volt seq :)

set i = 1
while ($i <= 100)
...
@ i = $i + 1
end

vagy valami ekvivalens Bourne-ilag.

OFF: Hogy utálom, hogy a C-shellben ezt leírhatod:

set a=2
set a = 2

de az már szintaktikai hiba, hogy

set a= 2
set a =2

Amúgy pedig Bourne-shellben ezt így kellene:

a=1
while [ "$i" -le 100 ] ; do
...
i=`expr "$i" + 1`
done

Korn- illetve POSIX-shellben már van rá egy halom gyorsabb és kicsit olvashatóbb módszer is, pl:

i=1
while (( i <= 100 )) ; do
...
(( i = i + 1 ))
done

Azzal persze egyet tudok érteni, hogy a for i in `seq 1 100` rövidebb - de cserébe nem hordozható.

Jav. a while ciklus feltétele.

Az még a kisebbik baj, de rászoktatja a népeket a `backtick` ilyen használatára... aztán ne csodálkozzunk, hogy honnan szedik a kezdők az ilyeneket:
for i in `ls`; do ... done

(Na persze az átirányítással is van gond: az hogy a ciklusmag is át van irányítva:

seq 1 10 | while read n; do echo $n; read m; done
1
3
5
7
9

Hol nincs Perl? A Python-t el tudom kepzelni, hogy regi rendszereken esetleg nincs es nem lehet letolteni, de Perl? Az 25 eve kirobbanthatatlan a Unixbol.

Pl. a FreeBSD alaptelepítésnek nem része, ports-ból vagy package-ből kell felrakni, ha valakinek kell. Természetesen rajta van a telepítő DVD-n a csomag, de *alapból* nem települ.

Oke, de mennyire realis, hogy egy olyan rendszeren kell a szkripteket futtatni, amin csak az alaptelepites van fent (amugy mit lehet egy ilyen rendszerrel csinalni?)? Vagy kifejezett ceges policy, hogy Perl le van tiltva az installbol? Mennyire realis ez a kovetelmeny?

Csak azert kerdezem, mert sokszoros a fejlesztes sebessegkulonbsege Perl vs shell szkript. Egyszeruen nem eri meg a szivast, a legtrivialisabb aprosagokat leszamitva. Foleg, ha a szivasba beleertendo, hogy altalanosan mindenhol fusson.

Nálunk a rendszerek jó 10%-án nincs Perl, és nem is lehet kérni, vagy lehet kérni csak akkora macera hogy lemondasz róla. Vagy pl. MVS unix subsys-en se látott Perl-t a kolléga, lehet nem is létezik, de ha létezik is nem volt ott, innentől pont az előző eset.

____________________
echo crash > /dev/kmem

Ismertem nem kis céget, ahol céges policy az volt, h a HP-UX szerverekre pl. nem fordíthattak maguknak szoftvert (így pl. perl-t sem), de ha mondjuk a HP adott egy gyári CD/DVD-t, amin volt perl, akkor az felmehetett.
A fejlesztés sebességkülönbsége meg szerintem leginkább azon múlik, hogy a fejlesztő shell-t vagy perl-t szokott-e gyakrabbn feladatmnegoldásra használni. Még 1x: szerintem.

Sajnos az sh csak az egyik probléma, a második kör az az által meghívott gnu vagy nem gnu tool-ok és azok verziónként és rendszerenkét változható paraméterezései.

+1, az én megoldásom erre nyelvtől függetlenül a futtató rendszer futásidejű felismerése, majd ahhoz megfelelő függvény választása.
------------------------
{0} ok boto
boto ?

Hát, ja. Pl AIX-on hogy találod ki a holnapi dátumot, ha nincs GNU-dateutils: nehezen vagy sehogy

Úgy '93-tól (telefonos szolgáltatás) számlázásra előkészítő rendszereket írtunk pont AIX-re. Méghozzá shellben, tarifálást, feldolgozást könyveléshez, göngyölítést, forgalmi kimutatást, részletezőt az előző N napra - max 18 hónap, stb. A script az ügyfélszolgálati munkahelyeket is kiszolgált. Akár egyszerre többet is. Azóta is meg tudok oldani mindent, még szökőévben is. ;)
A dateutils-t meg sohasem használtam.
Tudod, a topic a hordozható scriptről szól!

Ez csak kis bosszú volt a nyílért. :)

A lényeg lemaradt: mindez megy linuxon is.

Ne egyszerű kérdés!
Úgy 20 év AIX tapasztalat után ksh lenne a szavazat. Sajnos többször hordozni kellett a programot linuxra. Nagyon régi a tapasztalat, de ott a ksh nem igazán bizonyult működőképesnek, ezért maradt a bash.
A bash viszont csak 15 év alatt érte utol a ksh-t, ami végülis nem rossz, mert jelenleg elég hasonlóak.

Szerintem az ökölszabály az, hogy minden rendszeren a default shell-t érdemes használni. Ha tartózkodsz az adott shell specifikus megoldásainak használtától, akkor majdnem hordozható lesz a kód, de nem teljesen. Ráadásul - mint írták - az egyéb toolok használata is eltérhet az egyes rendszereken. Számomra az AIX - OpenSuse - Debian átjárhatóság esetenkén maximum 1 napos munkába került. Természetesen a C shellre ez nem igaz.

További gyakorlati jótanács: Az egyes linux disztrók esetén első dolgod legyen az elmebeteg environment és lokalizáció eltávolítása! Bármilyen hordozhatóság alapfeltétele a LANG=C (POSIX) esetleg en_US.

... mert jelenleg elég hasonlóak.

Tényleg? Mert én ezernyi TAB-ot nyomtam már ebben a ksh-ban, de még nem történt semmi... Hogy a fel/le nyilat már ne is említsem...

Rakd fel má' azt a nem hordozható scriptet, amiben a nyilakat nyomkodtad! :))
Bár annyi igazad vagyon, hogy eleinte a line editing funkcióról szóló könyvecske lényegesen vastagabb volt, mint az összes többi. Akik meg vi helyett joe-t használnak egyáltalán nem megbízhatóak! ;)

A 4 nyíl nekem is nagy szívfájdalom volt, AIX-on .profile -ba:

set -o emacs
alias __A=$(print -n "\020")
alias __B=$(print -n "\016")
alias __C=$(print -n "\006")
alias __D=$(print -n "\002")

Mondjuk scriptben tuti mellőzném :)

____________________
echo crash > /dev/kmem

(Az 'exec bash' egy kicsit egyszerűbb;)

Egyszerűbb, ha van fent bash :-)

____________________
echo crash > /dev/kmem

És mekkora szopás a fent emlegetett bash-t hiányoló rendszereken ;-)
Egyébként fenti aliasok az egyedül üdvözítő megoldás, bár én még raknék oda még pár másik aliast, egyrészt mert vannak olyan elvetemült terminálok/terminálemulátorok/beállítások, amelyek nem [ ABCD szekvenciát küldenek, hanem van olyan, ahol a [ helyett O van, meg olyan is, amelyikben úgy ahogy van ez a második karakter hiányzik ( lásd pl: http://www8.cs.umu.se/~isak/snippets/vt100.txt ). A nagyobbik baj, hogy fenti aliasok beállítása után maga az aliasok lekérdezése elég sok helyen problémát fog okozni, ugyanis a kurzor-le gombhoz rendelt karakter (amúgy Ctrl-N) bizonyos terminálok/emulátorok esetén alternatív karakterkészletre váltja a kijelzést, ami után átlagjúzer (de átlag rendszergizda sem) nem nagyon tudja elolvasni a képernyőn a dolgokat (ugyanis átvált a keretrajzoló karaktereket tartalmazó készletre). Ezért én legalább még egy alias-t be szoktam rakni, aminek a neve a lista végére kerül (ezért tipikusan alias __Z), értéke pedig a karakterkészlet visszaállítására alkalmas érték, azaz a 'tput sgr0' parancs kimenete. Gyengébbek kedvéért: Ctrl-O .)

(off: Egyszer elkezdtem összeírni a terminálok hisztijeit, de nem sok lett belőle. Ez a rész talán ideillik)

(azannya, az axelerohu domén még létezik? Amúgy ezt a doksidat már jópárszor olvastam :-) Ja, és pont a Ctrl-N / Ctrl-O -val kezdődik, amit itt előbb emlegettem.)

Sajnos hiányos: van még egy szekvencia, ami VT52-kompatibilisre bombázza vissza a nyílbillentyűk szekvenciáit... DECANM -- ESC [ ? 2 h

FAKK! Lenyelte ez a dög fórummotor a [ elől az egybeírt < ESC > sztringet. Grrr.
Szóval a kurzormozgatók: pl. a fel: ESC [ A - vagy ESC O A vagy épp ESC A. (Ezt írják le a trükkös aliasok.)

(Fentieket *ne* a .profile-ba tedd, hanem abba a fájlba, amire a $ENV hivatkozik - tipikusan $HOME/.kshrc -, és akkor minden létező terminálsession-ben és al-al-al-Korn-shellben menni fog a 4 kurzormozgató. És ha még azt is köré teszed, hogy:

case "$-" in
*i*) # interaktív shell
set -o emacs
alias ...
;;
*) # nem-interaktív shell
...
;;
esac

akkor pl. a futtatott shell-scriptek nem kapják meg az aliasaidat :-) A .profile-ba meg mehet az EDITOR=vi ; export EDITOR )

+1

Ok, köszi a tippet.

____________________
echo crash > /dev/kmem

Köszi mindenkinek, elindulok ksh irányba, feltérképezem mik lehetnek az eltérések. Nem szorosan de idevág: echo vs printf, és még bele se ástam magam :)
Ha nagyon nyűgösnek néz ki (számomra) akkor meg Perl.

____________________
echo crash > /dev/kmem

Rendes ksh-ban van egy kb alias echo=print szintű beállítás, azaz noha a ksh saját parancsát print-nek híjják, használhatsz echo-t is benne. Ha viszont az egyes echok közti különbséget el akarod felejteni (Hogy kell soremelés nélküli kiírást kérni? 'echo -n valami' vagy pedig 'echo valami\\c'), akkor valóban el kell indulni a printf irányba, az kb mindenütt van - igaz, többségében nem shell belső parancsként, de legalább közel azonos szintaxissal.

Androidon is ez a default

http://www.all-things-android.com/content/mirbsd-korn-shell-android-shell

----
"Kb. egy hónapja elkezdtem írni egy Coelho-emulátort, ami kattintásra generál random Coelho-kompatibilis tartalmat."
Instant Coelho

> elindulok ksh irányba

Miután megegyeztünk, hogy a dash a "legszigorúbb", "leg-POSIX-osabb". Értem.

Hát a function, és a select hiánya miatt nem annyira POSIX. Lehet még tesztelni a (( aritmetikai-kifejezés )) parancsot, a $(( aritmetikai kifejezés )) helyettesítő mechanizmust (*), van-e $( parancshelyettesítés ) - vagy csak a `parancs` forma, ellenőrizhető a tömbváltozók kezelésése (és az, hogy

set -A tomb 1. 2. 3.
vagy épp
tomb=( 1. 2. 3. )

formában tud egyszerre inicializálni több elemet is, mert a POSIX csak a

tomb[0]=1.
tomb[1]=2.
tomb[2]=3.

formát írja elő). Ellenőrizhető, hogy van-e a változóknak tipusa (pl. integer/float - tudtommal az utóbbi ksh93 egyedül), readonly, létezik-e ugye az a mechanizmus, hogy "aritmetikai környezetben" pl. nem kell $i-t írni, elég csak simán i; és í. t. Szóval azért nem biztos, hogy a dash annyira POSIX, egyelőre két negatívumot már mondtál :-)

(*) Ehhez is van bashizm: $[ aritmetikai kifejezés ] formában (persze ismeri a ksh/POSIX-félét is, de a különböző leírások ezt a formát sulykolják - tök értelmetlenül amúgy)

De a kérdező a minimumot keresi, ami mindenhol megy. Tehát lehetnek tökjó Posix2016-os feature-ok, ha nem mennek pl. dash-ban, akkor nem lehet őket univerzálisnak szánt scriptben használni.

Akkor viszont marad kb a UNIX V7-es shell funkcionalitás - hisz simán lehet még olyan (múzeumi) rendszert találni, aminél az alap /bin/sh nem POSIX/BA(SH)/K(SH), hanem jó öreg Bourne-shell. (Ja már az alias parancs megléte is "modern" shell-re utal, mármint a Bourne-shell kompatibilisek esetében.)

Csak follow up, shell scripting jobban bejött mint Perl. Utóbbi tényleg jó cucc, de ha az ellátandó feladatok leginkább olyanok hogy futtass valami un*x utility kombót, és elemezd a kimenetét, a shell scripting kényelmesebb (nekem).
Pár útmutatót követek (http://mywiki.wooledge.org/Bashism pl.), eddig bash/ksh/dash vonalat sikerült tartani. Ha minden megy még zsh, csh, tcsh, mksh alatt is, akkor szerintem eléggé portable lesz a motyó. Ofkoz tesztelni, tesztelni, tesztelni.

Egyébként érdekes látni, hogy bár a Perl nyilván sokkal-sokkal több mindent tud, több mindenre jó, ha a shell scriptingbe belemerül az ember akkor azért az is mutat pár lehetőséget :)

Mostmár csak Perl5 jövőjére vagyok kíváncsi, ha lesz neki akkor azért azt se kellene hanyagolnom.

____________________
echo crash > /dev/kmem

Idézet:
Ha minden megy még zsh, csh, tcsh, mksh alatt is, akkor szerintem eléggé portable lesz a motyó.

A nagyon egyszerűeken kívül szerintem a szkriptjeid csh és tcsh alatt nemigen mennek. Eleve pl. a for-ciklus máshogy néz ki, meg persze arról nem is szólva, hogy függvények pl. nincsenek.

Pont most tartok itt. Úgy néz ki t/csh lekerül a listáról, viszont nem is találtam sehol ilyet nálunk. Belevettem a nagy kompatibilitási tesztbe, de kukázható. bash/ksh/dash is elég lesz. Köszi az észrevételt amúgy :)

____________________
echo crash > /dev/kmem

Nagyvállalati környezetben nemigen van Debian/variáns (afaik), én még sose láttam, így dash-t se. Az elején ezt kihagytam, jogos a komment, tx.
Hát akkor lesz még egy ksh vs dash kör is :-)

____________________
echo crash > /dev/kmem

sub