Existe-t-il un shell Unix fonctionnel?

18

Je suis (vraiment) novice en programmation fonctionnelle (en fait, je n'ai eu de contact qu'avec elle en utilisant python), mais semble être une bonne approche pour certaines tâches gourmandes en listes dans un environnement shell.

J'adorerais faire quelque chose comme ça:

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

Existe-t-il un shell Unix avec ce genre de fonctionnalité? Ou peut-être une fonctionnalité permettant un accès facile au shell (commandes, env / vars, readline, etc ...) depuis python (l'idée est d'utiliser l'interpréteur interactif de python en remplacement de bash).

ÉDITER:

Peut-être qu'un exemple comparatif clarifierait. Disons que j'ai une liste composée de dir / fichier :

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

Et je veux faire une tâche vraiment simple: copier tous les fichiers dans dist / ET l'installer dans le système (cela fait partie d'un processus de construction):

Utilisation de bash:

$ cp $ {files [*]} dist /
$ cd dist && rpm -Uvh $ (pour f dans $ {files [*]}; do basename $ f; done))

Utilisation d'une approche "shell pythonique" (attention: c'est du code imaginaire):

$ cp [os.path.join ('dist', os.path.basename (file)) pour le fichier dans FILES] 'dist'

Pouvez-vous voir la différence ? C’est de cela que je parle. Comment ne peut-on pas encore sortir d'un shell avec ce genre de trucs intégrés? C'est une vraie douleur de gérer des listes en shell, même si c'est une tâche si courante: liste de fichiers, liste de PID, liste de tout.

Et un point vraiment, vraiment important: utiliser la syntaxe / outils / fonctionnalités que tout le monde connaît déjà: sh et python.

IPython semble être dans la bonne direction, mais il est gonflé: si le nom var commence par '$', il fait ceci, si '$$' il fait cela. Sa syntaxe n'est pas "naturelle", donc de nombreuses règles et "contournements" ( [ ln.upper() for ln in !ls ] -> erreur de syntaxe)

caruccio
la source
Assez lié: github.com/amoffat/pbs
Josh Lee
4
La programmation fonctionnelle ne se limite pas à la compréhension de listes. Si votre objectif principal est d'écrire du code fonctionnel, je ne prendrais pas python comme exemple.
pqnet

Réponses:

10

Il existe un Scheme Shell qui est probablement très proche de ce que vous recherchez. Je ne l'ai pas utilisé moi-même.

MISE À JOUR :

Je viens de l'installer et de l'essayer moi-même. Il semble que scsh soit plus un interpréteur de schéma interactif et un langage de script qu'un shell interactif vraiment utile. Vous ne pouvez pas simplement taper

echo hello

la syntaxe semble être

(run (echo hello))

et il a fallu plusieurs minutes de recherche sur Google juste pour trouver cela. Le premier exemple ici est:

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

ce qui se traduit par:

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

mais cela ne vous dit pas comment exécuter une simple commande shell.

Cette entrée de la FAQ dit:

4.6 Puis-je utiliser scsh comme un shell interactif?

Eh bien, techniquement, vous pouvez: exécutez simplement la commande "scsh" et vous entrerez dans une session Scheme 48 avec toutes les fonctions scsh disponibles. Cependant, cela ne convient certainement pas au travail interactif: il n'y a pas d'édition en ligne de commande, pas d'historique de ligne de commande, pas de complétion de nom de fichier / fonction, pas de syntaxe laconique, etc.

Pour atténuer ces problèmes, Martin Gasbichler et Eric Knauel ont écrit Commander S, qui fonctionne au-dessus de scsh et fournit un environnement interactif confortable. L'une de ses nouvelles fonctionnalités est qu'il peut comprendre la sortie de nombreuses commandes Unix et permet à l'utilisateur de la parcourir et de la manipuler de manière utile. Vous trouverez plus d'informations sur Commander S dans le document le décrivant: http://www.deinprogramm.de/scheme-2005/05-knauel/05-knauel.pdf Les instructions pour obtenir et installer Commander S sont disponibles sur le Site Web de scsh: http://www.scsh.net/resources/commander-s.html

C'est peut-être la vraie réponse.

Keith Thompson
la source
7

Dans la catégorie des réponses directes à la question, il y a le shell ES qui se veut un remplacement fonctionnel pour Bash et Zsh etc.

Deuxièmement, dans la catégorie de vous aider à écrire un shell standard plus fonctionnel, envisagez d'apprendre la technique du pipetier:

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

La première boucle while est une fonction keep(ne transmettez que les valeurs non nulles qui sortent de la boucle) et la seconde est une each(mappage des effets secondaires uniquement).

Il s'agit d'un formidable coup de pouce au fp dans les coquilles.

Il est possible d'exprimer beaucoup de choses dans un style plus fp dans un shell, ce n'est tout simplement pas aussi facile qu'il pourrait l'être. Il semble qu'il n'y ait pas beaucoup d'intérêt à fabriquer de meilleures coquilles, même si nous les utilisons tous beaucoup.

nic ferrier
la source
6

Les coquilles standards de type Bourne ( sh, bash, ksh, etc.) vous permettent déjà faire:

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

(Notez la nécessité de points-virgules avant doet done.) De plus, dans bashet dans d' autres shells, si une $reposeule fois apparaît dans la commande, vous pouvez écrire:

git clone $host/{repo1,repo2,repo3}
jwodder
la source
bien sûr, et je l'utilise beaucoup. mais qu'en est-il d'autres choses, comme les fonctions lambda?
8
git clone $host/{repo1,repo2,repo3}ne fait pas la même chose que la forboucle; il invoque git cloneune fois avec trois arguments. Le fait que cela fasse essentiellement la même chose est un artefact de la façon dont git clonefonctionne; il ne s'applique pas nécessairement aux autres commandes. (Comparez echo foo bar bazà echo foo; echo bar; echo baz, par exemple.)
Keith Thompson
@caruccio vous pouvez utiliser FUN=eval 'git clone '"$host"'$0 pour définir un lambda à utiliser commefor repo in repo{1,2,3} ; do $FUN $repo ; done
pqnet
Le plus gros problème est que les outils Unix ont souvent des effets secondaires (comme l'écriture dans des fichiers), donc vous ne pouvez souvent pas les composer comme vous le feriez dans un langage fonctionnel.
weberc2
2

Scheme Shell, scsh, est vraiment bon.

Comme le note Keith Thompson, il n'est pas utile en tant que shell interactif (bien que le commandant S ressemble à une expérience intéressante). Au lieu de cela, c'est un excellent langage de programmation pour les contextes où toutes les liaisons POSIX sont utiles - cela inclut les cas où vous souhaitez appeler d'autres applications Unix. Un script shell de plus de quelques dizaines de lignes se sentira toujours comme un hack, quelle que soit la façon dont vous écrivez sh; en revanche, rien ne vous empêche d'écrire des programmes importants en utilisant scsh.

scsh n'est pas très compact (la brièveté est à la fois la force et la faiblesse des langages de la famille sh), mais il est puissant.

Parce qu'il est utile et pratique pour les petites et grandes tâches, scsh est d'ailleurs un bon moyen de se familiariser avec un schéma (bien que, si cela était votre objectif, vous feriez aussi bien d'aller directement à Racket, ces jours-ci).

Les avantages des langages fonctionnels ne sont pas seulement pour les tâches gourmandes en listes (bien qu'en raison de leur historique, ils ont tendance à privilégier les listes en tant que structure de données) - c'est un moyen très robuste pour écrire des programmes, une fois que vous buvez le bon kool- aide.

Il n'y a pas de sens significatif dans lequel les shells de style sh sont fonctionnels, et Python n'est fonctionnel que dans le sens marginal où il a une fonction lambda.

Norman Gray
la source
2

Les coquilles sont nécessairement extrêmement expressives, ce qui signifie que vous réalisez des lots avec moins de lignes, de jetons, etc.

Nous rendons généralement les langages expressifs en les concevant à des fins spéciales, comme les shells ou les DSL comme R, érable, etc. Et vous trouvez relativement peu d'expressivité dans la plupart des langages à usage général comme C, C ++, Java, etc.

Python, Perl, Ruby, etc. sont des langages à usage général qui sont plus expressifs de manière similaire aux shells, ala duck typing. Les DSL sont donc soudés dessus, ala Sage pour les mathématiques. Ce n'est pas si bon pour les commandes shell réelles .

Le schéma n'est pas à mon humble avis, même une fois que vous avez créé un DLS, à cause de toutes les parenthèses.

Il existe cependant des langages fonctionnels comme Haskell avec une expressivité énorme et une grande capacité de construction de DSL. Les efforts intéressants pour construire une coquille sur Haskell sont la tortue et la coquille .

Dans la pratique, il existe une courbe d'apprentissage avec des outils d'efforts en raison du système de type Haskell puissant mais restrictif, mais ils sont très prometteurs.

Jeff Burdges
la source
1

Tout d'abord, vous devez utiliser "${files[@]}"partout où vous avez ${files[*]}. Sinon, les espaces vous gâcheront.

Le shell est déjà assez fonctionnel; si vous pensez que la sortie de texte est une liste de lignes, alors grepest filter, xargsest map, etc. Les tuyaux sont très fonctionnels.

Le shell n'est certes pas l'environnement de programmation le plus convivial, mais il est beaucoup plus adapté à une utilisation interactive que Python. Et il a la très belle fonctionnalité que l'API et l'interface utilisateur sont identiques - apprenez les deux à la fois.

Je ne comprends pas pourquoi vous trouvez cp [ os.path.join('dist', os.path.basename(file)) for file in FILES ] 'dist'préférable cp "${FILES[@]}" dist. Ce dernier est beaucoup moins typant.

Mark Reed
la source
0

Je ne sais pas si c'est "fonctionnel", mais il y a aussi rc , que le papier scsh mentionne. C'est un prédécesseur d'es.

Sur Linux Mint (et probablement Debian, Ubuntu ...) vous pouvez l'essayer avec

sudo apt-get install rc
man rc
rc
spelufo
la source