Esiste una shell unix funzionale?


18

Sono (davvero) un principiante della programmazione funzionale (in effetti ho avuto contatti solo con python) ma sembra essere un buon approccio per alcune attività ad alta intensità di elenco in un ambiente shell.

Mi piacerebbe fare qualcosa del genere:

$ [ git clone $host/$repo for repo in repo1 repo2 repo3 ]

Esiste una shell Unix con questo tipo di funzionalità? O forse alcune funzionalità per consentire un facile accesso alla shell (comandi, env / vars, readline, ecc ...) dall'interno di Python (l'idea è di usare l'interprete interattivo di Python in sostituzione di bash).

MODIFICARE:

Forse un esempio comparativo chiarirebbe. Diciamo che ho un elenco composto da dir / file :

$ FILES=( build/project.rpm build/project.src.rpm )

E voglio fare un compito davvero semplice: copiare tutti i file in dist / E installarlo nel sistema (fa parte di un processo di compilazione):

Usando bash:

$ cp $ {files [*]} dist /
$ cd dist && rpm -Uvh $ (per f in $ {files [*]}; fai basename $ f; fatto))

Usando un approccio "shell pitonica" (attenzione: questo è un codice immaginario):

$ cp [os.path.join ('dist', os.path.basename (file)) per il file in FILES] 'dist'

Riesci a vedere la differenza? È quello di cui sto parlando. Come non uscire ancora da una shell con questo tipo di roba integrata? Gestire gli elenchi in shell è una vera seccatura, anche se è un compito così comune: elenco di file, elenco di PID, elenco di tutto.

E un punto davvero molto importante: usare la sintassi / strumenti / funzionalità che tutti già conoscono: sh e python.

IPython sembra avere una buona direzione, ma è gonfio: se var name inizia con '$', lo fa, se '$$' lo fa. La sua sintassi non è "naturale", quindi molte regole e "soluzioni alternative" ( [ ln.upper() for ln in !ls ] -> errore di sintassi)


In qualche modo correlato: github.com/amoffat/pbs
Josh Lee,


4
C'è un po 'più di comprensione dell'elenco nella programmazione funzionale. Se il tuo obiettivo principale è la scrittura di codice funzionale, non prenderei Python come esempio.
pqnet,

Risposte:


10

C'è uno schema Shell probabilmente molto vicino a quello che stai cercando. Non l'ho usato da solo.

AGGIORNARE :

Ho appena installato e provato da solo. Sembra che scsh sia più un interprete di Schema interattivo e un linguaggio di scripting che una shell interattiva davvero utile. Non puoi semplicemente digitare

echo hello

la sintassi sembra essere

(run (echo hello))

e ci sono voluti diversi minuti per cercare su Google. Il primo esempio qui è:

gunzip < paper.tex.gz | detex | spell | lpr -Ppulp &

che si traduce in:

(& (| (gunzip) (detex) (spell) (lpr -Ppulp)) (< paper.tex.gz))

ma questo non ti dice come eseguire un semplice comando di shell.

Questa voce FAQ dice:

4.6 Posso usare scsh come shell interattiva?

Bene, tecnicamente puoi: basta eseguire il comando "scsh" e si entrerà in una sessione di Scheme 48 con tutte le funzioni scsh disponibili. Tuttavia, questo non è sicuramente adatto per il lavoro interattivo: non c'è modifica della riga di comando, nessuna cronologia della riga di comando, nessun completamento del nome di file / funzione, nessuna sintassi concisa, ecc.

Per alleviare questi problemi, Martin Gasbichler ed Eric Knauel hanno scritto il comandante S, che gira su scsh e fornisce un ambiente interattivo confortevole. Una delle sue nuove funzionalità è che può comprendere l'output di molti comandi Unix e consente all'utente di sfogliarlo e manipolarlo in modi utili. Ulteriori informazioni su Commander S sono disponibili nel documento che lo descrive: http://www.deinprogramm.de/scheme-2005/05-knauel/05-knauel.pdf Le istruzioni su come ottenere e installare Commander S sono disponibili dal Sito Web scsh: http://www.scsh.net/resources/commander-s.html

Quindi forse questa è la vera risposta.


7

Nella categoria di risposta diretta alla domanda, c'è la shell ES che è intesa come una sostituzione funzionale per Bash e Zsh ecc.

In secondo luogo, nella categoria per aiutarti a scrivere shell standard più funzionali, considera l'apprendimento della tecnica pipemill:

who | while read username 
do
  cat <<EOF | grep $username
nic
mark
norman
keith
EOF
done | while read username
do
  echo "you have an answer on superuser.com" | mail -s "well done" $username
done

Il primo ciclo while è funzionale keep(passa solo i valori non nulli che escono dal ciclo) e il secondo è una each(mappa solo per gli effetti collaterali).

Questa è un'enorme spinta a FP nelle shell.

È possibile esprimere molte cose in uno stile più fp in una shell, non è così facile come potrebbe essere. Sembra che non ci sia molto interesse nel creare shell migliori, anche se le usiamo tutti così tanto.


6

Le shell standard in stile Bourne ( sh, bash, ksh, etc.) già consentono di fare:

for repo in repo1 repo2 repo3 ; do git clone $host/$repo ; done

(Nota la necessità di punti doe virgola prima e done). Inoltre, in bashe altre shell, se $repoappare solo una volta nel comando, puoi scrivere:

git clone $host/{repo1,repo2,repo3}

certo, e lo uso molto. ma che dire di altre cose, come le funzioni lambda?

8
git clone $host/{repo1,repo2,repo3}non fa la stessa cosa del forloop; invoca git cloneuna volta con tre argomenti. Il fatto che essenzialmente fa la stessa cosa è un artefatto di come git clonefunziona; non si applica necessariamente ad altri comandi. (Confronta echo foo bar bazper echo foo; echo bar; echo baz, per esempio.)
Keith Thompson

@caruccio puoi usare FUN=eval 'git clone '"$host"'$0 per definire un lambda da usare comefor repo in repo{1,2,3} ; do $FUN $repo ; done
pqnet il

Il problema maggiore è che gli strumenti unix hanno spesso effetti collaterali (come scrivere su file), quindi spesso non puoi comporli come vorresti fare in un linguaggio funzionale.
weberc2,

2

Scheme Shell, scsh, è davvero buono.

Come osserva Keith Thompson, non è utile come shell interattiva (anche se il comandante S sembra un esperimento interessante). Al contrario, è un eccellente linguaggio di programmazione per contesti in cui è utile disporre di tutti i collegamenti POSIX, inclusi i casi in cui si desidera chiamare altre applicazioni unix. Uno script di shell di più di una dozzina di righe sembrerà sempre un trucco, non importa quanto bene scrivi sh; al contrario non c'è nulla che ti impedisca di scrivere programmi significativi usando scsh.

scsh non è molto compatto (la brevità è sia la forza che la debolezza delle lingue sh-family), ma è potente.

Poiché è utile e pratico per compiti piccoli e grandi, per inciso scsh è un buon modo per fare i conti con uno Schema (anche se, se questo fosse il tuo obiettivo, potresti andare direttamente alla Racchetta, in questi giorni).

I vantaggi dei linguaggi funzionali non sono solo per le attività ad uso intensivo di elenchi (anche se a causa della loro cronologia, tendono a favorire gli elenchi come una struttura di dati) - è un modo davvero robusto per ottenere programmi scritti, una volta bevuto il giusto kool- aiuto.

Non vi è alcun senso significativo in cui le shell sh-style siano funzionali e Python funziona solo nel senso marginale che ha una funzione lambda.


2

Le conchiglie sono necessariamente estremamente espressive, il che significa che ottieni molti con meno linee, token, ecc.

Solitamente rendiamo le lingue espressive progettandole per uno scopo speciale, come shell o DSL come R, acero, ecc. E trovi espressività relativamente scarsa nella maggior parte dei linguaggi di uso generale come C, C ++, Java, ecc.

Python, Perl, Ruby, ecc. Sono linguaggi di uso generale che sono più espressivi in ​​modi simili alle conchiglie, alla tipizzazione ala duck. Quindi i DSL vengono saldati su di loro, ala Sage per la matematica. Tuttavia, non è eccezionale per i comandi della shell .

Lo schema non è così espressivo, anche dopo aver creato un DLS, a causa di tutte le parentesi.

Esistono tuttavia linguaggi funzionali come Haskell con un'enorme espressività e una grande capacità di creare DSL. Sforzo per costruire una shell su Haskell interessanti sono tartarughe e Shelly .

In pratica, esiste una curva di apprendimento con strumenti di impegno dovuti al sistema di tipi potente ma restrittivo di Haskell, ma mostrano notevoli promesse.


1

Innanzitutto, dovresti usare "${files[@]}"ovunque tu abbia ${files[*]}. Altrimenti gli spazi ti incasineranno.

La shell è già abbastanza funzionale; se pensi che l'output del testo sia un elenco di righe, allora grepè filter, xargsè map, ecc. I tubi sono molto funzionali.

La shell non è certamente l'ambiente di programmazione più amichevole, ma è molto più adatto all'uso interattivo di Python. E ha la caratteristica molto bella che l'API e l'interfaccia utente sono identiche: imparali entrambi in una volta.

Non capisco perché lo trovi cp [ os.path.join('dist', os.path.basename(file)) for file in FILES ] 'dist'preferibile cp "${FILES[@]}" dist. Quest'ultimo è molto meno digitante.


0

Non so che sia "funzionale", ma c'è anche rc , che cita la carta scsh . È un predecessore di es.

Su Linux Mint (e probabilmente Debian, Ubuntu ...) puoi provarlo

sudo apt-get install rc
man rc
rc
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.