Ciao a tutti,
approfitto del silenzio per fare un po' di pubblicità ad un mio nuovo
software,
ovviamente per Linux e Open Source.
Si tratta di schemesh
https://github.com/cosmos72/schemesh
ed è una shell Unix interattiva, intesa anche come shell di login.
Ha tutte le funzionalità classiche delle shell tradizionali:
* line editing, compreso l'editing multi-linea e l'highlight delle
parentesi e delle virgolette
* redirezione di input, output e file descriptors arbitrari di un
comando con la sintassi classica < <> > >> <& >&
* esecuzione di comandi aggregati con la sintassi classica && || { }
* pipelines tra più comandi, con la sintassi classica | |&
* esecuzione di più comandi in foreground con ; o in background con &
* esecuzione di sub-shell, la sintassi è [ ] anziché ( )
* cattura dell'output di un comando, la sintassi è la classica ` `
oppure $[ ] anziché $( )
* controllo dei job con CTRL+C CTRL+Z 'fg N' 'bg N'
Con la differenza che è scriptabile in Lisp,
e anzi è un ambiente interattivo basato su Chez Scheme (un compilatore
Lisp nativo che genera codice ottimizzato)
ed è *completo*, cioè offre tutte le funzionalità dei REPL Lisp,
inclusa la possibilità di eseguire codice, usare variabili, funzioni,
macro, librerie e definirne di nuove.
Si possono anche usare librerie di terze parti direttamente dal prompt,
ad esempio quelle distribuite da
https://akkuscm.org/
La funzionalità più interessante è che si può passare da sintassi shell
a quella Lisp e viceversa praticamente dappertutto:
* All'interno di un comando shell si possono inserire espressioni Lisp,
racchiudendole in ()
Esempio:
> ls -l (lisp-expression-returning-some-string arg1 arg2) --sort=size
Le espressioni Lisp devono restituire una stringa, o una lista di
stringhe,
o una funzione che a sua volta restituisce una stringa o una lista
di stringhe.
* All'interno di un'espressione Lisp si possono inserire comandi shell,
racchiudendoli in { }
Il comando shell è un oggetto Lisp "first-class": può essere salvato
in una variabile, passato a funzioni, restituito, ecc.
E chiaramente può essere eseguito.
Esempio:
> (set! job {sleep 5 && ls -l > ls.out || echo "ls failed"})
> (sh-start job)
; job 1 (running 1) {ls "--color=auto" -l
1>ls.out || echo "ls failed"}
(running 1)
> fg 1
I passaggi da una sintassi all'altra si possono nidificare, ad esempio:
> (set! job2 {find (sh-run/string {echo $HOME}) -type f | grep ^lib})
> (sh-run/i job2)
Chiaramente si può usare anche come REPL Lisp:
> (* 1/3 7/3 9)
7
> (string-split "a b c" #\space)
("a" "b" "c")
> (set! l (directory-list "/"))
> (values l)
("dev" "srv" "boot" "run" "etc" "root" ...)
> (define (fibonacci n)
(if (> n 2)
(+ (fibonacci (- n 1)) (fibonacci (- n 2)))
1))
> (fibonacci 20)
6765
Da quasi un mese la sto usando come shell di login, ed è comodissima :)
Ciao,
Max
--
----------------------------------------------------
Massimiliano Ghilardi
email:
mghi...@mbigroup.it
M.B.I. Group
Via Francesco Squartini 7
56121 Pisa
website:
www.mbigroup.it
----------------------------------------------------