Gibt es eine funktionsähnliche Unix-Shell?


18

Ich bin (wirklich) Neuling in der funktionalen Programmierung (tatsächlich hatte ich nur mit Python Kontakt), aber es scheint ein guter Ansatz für einige listenintensive Aufgaben in einer Shell-Umgebung zu sein.

Ich würde gerne so etwas machen:

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

Gibt es eine Unix-Shell mit solchen Funktionen? Oder vielleicht eine Funktion, die einen einfachen Shell-Zugriff (Befehle, env / vars, readline usw.) aus Python heraus ermöglicht (die Idee ist, den interaktiven Interpreter von Python als Ersatz für bash zu verwenden).

BEARBEITEN:

Vielleicht würde ein Vergleichsbeispiel klarstellen. Nehmen wir an, ich habe eine Liste bestehend aus dir / file :

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

Und ich möchte eine wirklich einfache Aufgabe erledigen: Kopieren Sie alle Dateien nach dist / UND installieren Sie sie im System (es ist Teil eines Build-Prozesses):

Bash benutzen:

$ cp $ {files [*]} dist /
$ cd dist && rpm -Uvh $ (für f in $ {files [*]}; mache den Basisnamen $ f; fertig)

Verwenden eines "Pythonic Shell" -Ansatzes (Vorsicht: Dies ist imaginärer Code):

$ cp [os.path.join ('dist', os.path.basename (file)) für file in FILES] 'dist'

Kannst du den Unterschied sehen? DAS ist es, wovon ich rede. Wie kann man eine Shell mit solchen eingebauten Sachen noch nicht verlassen? Es ist ein echtes Problem, mit Listen in der Shell umzugehen, auch wenn es eine so häufige Aufgabe ist: Liste der Dateien, Liste der PIDs, Liste von allem.

Und ein wirklich, wirklich wichtiger Punkt: Verwenden von Syntax / Tools / Features, die jeder bereits kennt: sh und Python.

IPython scheint auf einem guten Weg zu sein, aber es ist aufgebläht: Wenn der Variablenname mit '$' beginnt, tut es dies, wenn '$$', tut es das. Die Syntax ist nicht "natürlich", so viele Regeln und "Problemumgehungen" ( [ ln.upper() for ln in !ls ] -> Syntaxfehler)


Etwas im Zusammenhang: github.com/amoffat/pbs
Josh Lee


4
Die funktionale Programmierung bietet mehr als nur Listenverständnis. Wenn Ihr Hauptaugenmerk auf dem Schreiben von funktionalem Code liegt, würde ich Python nicht als Beispiel nehmen.
pqnet

Antworten:


10

Es gibt eine Schema-Shell , die wahrscheinlich sehr nah an dem ist, wonach Sie suchen. Ich habe es selbst nicht benutzt.

UPDATE:

Ich habe es gerade selbst installiert und ausprobiert. Es scheint, dass scsh eher ein interaktiver Scheme-Interpreter und eine Skriptsprache ist als eine wirklich nützliche interaktive Shell. Sie können nicht einfach tippen

echo hello

Die Syntax scheint zu sein

(run (echo hello))

und es dauerte einige Minuten von Googeln, nur um das zu finden. Das erste Beispiel ist hier :

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

was übersetzt zu:

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

Aber das sagt Ihnen nicht, wie man einen einfachen Shell-Befehl ausführt.

Dieser FAQ-Eintrag lautet:

4.6 Kann ich scsh als interaktive Shell verwenden?

Nun, technisch gesehen können Sie: Führen Sie einfach den Befehl "scsh" aus und Sie werden eine Sitzung nach Schema 48 mit allen verfügbaren scsh-Funktionen starten. Dies ist jedoch definitiv nicht für interaktives Arbeiten geeignet: Es gibt keine Befehlszeilenbearbeitung, kein Befehlszeilenprotokoll, keine Vervollständigung von Datei- / Funktionsnamen, keine knappe Syntax usw.

Um diese Probleme zu lösen, haben Martin Gasbichler und Eric Knauel Commander S geschrieben, das auf scsh läuft und eine komfortable interaktive Umgebung bietet. Eine der neuen Funktionen besteht darin, dass die Ausgabe vieler Unix-Befehle verstanden wird und der Benutzer sie auf nützliche Weise durchsuchen und bearbeiten kann. Weitere Informationen zu Commander S finden Sie in dem entsprechenden Dokument: http://www.deinprogramm.de/scheme-2005/05-knauel/05-knauel.pdf Anweisungen zum Beziehen und Installieren von Commander S erhalten Sie von der scsh-Website: http://www.scsh.net/resources/commander-s.html

Vielleicht ist das die richtige Antwort.


7

In der Kategorie der direkten Beantwortung der Frage gibt es die ES-Shell, die als funktionaler Ersatz für Bash und Zsh usw. gedacht ist.

Zweitens sollten Sie in der Kategorie Hilfe beim Schreiben einer funktionaleren Standard-Shell das Erlernen der Pipemill-Technik in Betracht ziehen:

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

Die erste while-Schleife ist eine Funktion keep(nur die Nicht-Null-Werte weitergeben, die aus der Schleife kommen) und die zweite ist eine each(Karte nur für Nebenwirkungen).

Dies ist ein enormer Schub für Fp in Shells.

Es ist möglich, viele Dinge in einer Shell in einem fp-Stil auszudrücken, es ist einfach nicht so einfach, wie es sein mag. Es scheint, dass es nicht viel Interesse gibt, bessere Muscheln herzustellen, obwohl wir sie alle so oft verwenden.


6

Die Standard - Bourne-style Schalen ( sh, bash, ksh, etc.) schon können Sie tun:

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

(Beachten Sie die Notwendigkeit von Semikolons vor dound done.) Außerdem können Sie in bashund in anderen Shells $reposchreiben , wenn sie nur einmal im Befehl enthalten sind:

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

sicher, und ich benutze es oft. aber was ist mit anderen Sachen, wie Lambda-Funktionen?

8
git clone $host/{repo1,repo2,repo3}macht nicht das Gleiche wie die forSchleife; es ruft git cloneeinmal mit drei Argumenten auf. Die Tatsache, dass sie im Wesentlichen dasselbe tut, ist ein Artefakt der Funktionsweise git clone. Dies gilt nicht unbedingt für andere Befehle. (Vergleiche echo foo bar bazzum echo foo; echo bar; echo bazBeispiel.)
Keith Thompson

@caruccio können Sie verwenden FUN=eval 'git clone '"$host"'$0 , um ein Lambda zu definieren, das alsfor repo in repo{1,2,3} ; do $FUN $repo ; done
pqnet

Das größte Problem ist, dass die Unix-Tools häufig Nebenwirkungen haben (wie das Schreiben in Dateien), sodass Sie sie häufig nicht so komponieren können, wie Sie es in einer funktionalen Sprache tun möchten.
weberc2

2

Schema Shell, scsh, ist wirklich gut.

Wie Keith Thompson bemerkt, ist es als interaktive Shell nicht nützlich (obwohl Commander S wie ein interessantes Experiment aussieht). Stattdessen ist es eine ausgezeichnete Programmiersprache für Kontexte, in denen alle POSIX-Bindungen nützlich sind - dies schließt Fälle ein, in denen Sie andere Unix-Anwendungen aufrufen möchten. Ein Shell-Skript mit mehr als ein paar Dutzend Zeilen fühlt sich immer wie ein Hack an, egal wie ordentlich Sie schreiben sh. im gegensatz dazu hindert nichts sie daran, wichtige programme mit scsh zu schreiben.

scsh ist nicht sehr kompakt (Kürze ist sowohl die Stärke als auch die Schwäche von Sprachen der sh-Familie), aber es ist mächtig.

Da scsh für kleine und große Aufgaben nützlich und praktisch ist, ist es im Übrigen eine gute Möglichkeit, ein Schema in den Griff zu bekommen (obwohl Sie heutzutage auch gleich zu Racket wechseln könnten, wenn dies Ihr Ziel wäre).

Die Vorteile von funktionalen Sprachen gelten nicht nur für listenintensive Aufgaben (obwohl sie aufgrund ihrer Vergangenheit Listen als Datenstruktur bevorzugen) - es ist eine sehr robuste Methode, um Programme zu schreiben, wenn Sie die richtige Lernsoftware trinken. Hilfe.

Es gibt keinen sinnvollen Sinn, in dem die Sh-Shells funktionieren, und Python ist nur in dem marginalen Sinn funktionsfähig, in dem es eine Lambda-Funktion hat.


2

Muscheln sind notwendigerweise extrem ausdrucksstark, was bedeutet, dass Sie viel mit weniger Linien, Token usw. erreichen.

Wir machen Sprachen in der Regel ausdrucksstark, indem wir sie für einen bestimmten Zweck entwerfen, z. B. für Muscheln oder DSLs wie R, Ahorn usw. In den meisten Mehrzwecksprachen wie C, C ++, Java usw. ist die Ausdruckskraft relativ gering.

Python, Perl, Ruby usw. sind Mehrzwecksprachen, die in ähnlicher Weise wie Muscheln ausdrucksstark sind. Also werden DSLs angeschweißt, ala Sage für Mathe. Ist aber nicht so toll für aktuelle Shell-Befehle .

Das Schema ist nicht so aussagekräftig, auch wenn Sie erst einmal ein DLS erstellt haben, da alle Klammern gesetzt sind.

Es gibt jedoch funktionale Sprachen wie Haskell mit enormer Ausdruckskraft und einer großen Kapazität zum Aufbau von DSLs. Interessante Bemühungen, eine Muschel auf Haskell zu bauen, sind Schildkröten und Muscheln .

In der Praxis gibt es aufgrund des leistungsfähigen, aber restriktiven Schriftsystems von Haskell eine Lernkurve mit Aufwandsinstrumenten, die jedoch beträchtliche Aussichten eröffnen.


1

Erstens sollten Sie "${files[@]}"überall verwenden, wo Sie haben ${files[*]}. Andernfalls werden Leerzeichen Sie durcheinander bringen.

Die Shell ist schon ziemlich funktionell; Wenn Sie denken, dass die Textausgabe Listen von Zeilen ist, dann grepist filter, xargsist mapusw. Pipes sind sehr funktional.

Die Shell ist zwar nicht die freundlichste Programmierumgebung, eignet sich jedoch viel besser für die interaktive Verwendung als Python. Und es hat die sehr nette Eigenschaft, dass die API und die Benutzeroberfläche identisch sind - lernen Sie beide auf einmal.

Ich verstehe nicht, warum Sie es cp [ os.path.join('dist', os.path.basename(file)) for file in FILES ] 'dist'vorziehen cp "${FILES[@]}" dist. Letzteres ist viel weniger tippen.


0

Ich weiß nicht, ob es "funktionstüchtig" ist, aber es gibt auch rc , was im scsh-Artikel erwähnt wird. Es ist ein Vorläufer von es.

Auf Linux Mint (und wahrscheinlich Debian, Ubuntu ...) können Sie es mit versuchen

sudo apt-get install rc
man rc
rc
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.