¿Hay algún shell unix funcional?

18

Soy (realmente) novato en la programación funcional (de hecho, solo tuve contacto con él usando python) pero parece ser un buen enfoque para algunas tareas intensivas en listas en un entorno de shell.

Me encantaría hacer algo como esto:

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

¿Hay algún shell de Unix con este tipo de características? O tal vez alguna característica para permitir un fácil acceso de shell (comandos, env / vars, readline, etc.) desde Python (la idea es utilizar el intérprete interactivo de Python como reemplazo de bash).

EDITAR:

Quizás un ejemplo comparativo aclararía. Digamos que tengo una lista compuesta de dir / archivo :

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

Y quiero hacer una tarea realmente simple: copiar todos los archivos para dist / AND instalarlo en el sistema (es parte de un proceso de compilación):

Usando bash:

$ cp $ {archivos [*]} dist /
$ cd dist && rpm -Uvh $ (para f en $ {archivos [*]}; nombre base $ f; hecho))

Usando un enfoque de "capa pitónica" (precaución: este es un código imaginario):

$ cp [os.path.join ('dist', os.path.basename (file)) para el archivo en ARCHIVOS] 'dist'

Puedes ver la diferencia ? ESO es de lo que estoy hablando. ¿Cómo no se puede salir de un shell con este tipo de cosas incorporadas todavía? Es realmente difícil manejar listas en shell, incluso si es una tarea tan común: lista de archivos, lista de PID, lista de todo.

Y un punto muy, muy importante: usar la sintaxis / herramientas / características que todos ya conocen: sh y python.

IPython parece estar en una buena dirección, pero está hinchado: si el nombre var comienza con '$', lo hace, si '$$' lo hace. Su sintaxis no es "natural", hay muchas reglas y "soluciones" ( [ ln.upper() for ln in !ls ] -> error de sintaxis)

caruccio
fuente
Algo relacionado: github.com/amoffat/pbs
Josh Lee
44
Hay un poco más de comprensión de la lista para la programación funcional. Si su enfoque principal es escribir código funcional, no tomaría Python como ejemplo.
pqnet

Respuestas:

10

Hay un Shell de esquema que probablemente esté muy cerca de lo que estás buscando. No lo he usado yo mismo.

ACTUALIZACIÓN

Acabo de instalarlo y lo probé yo mismo. Parece que scsh es más un intérprete de esquemas interactivo y un lenguaje de script que un shell interactivo realmente útil. No puedes simplemente escribir

echo hello

la sintaxis parece ser

(run (echo hello))

y me tomó varios minutos buscar en Google solo para encontrar eso. El primer ejemplo aquí es:

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

que se traduce en:

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

pero eso no te dice cómo ejecutar un simple comando de shell.

Esta entrada de preguntas frecuentes dice:

4.6 ¿Puedo usar scsh como un shell interactivo?

Bueno, técnicamente puedes: simplemente ejecuta el comando "scsh" e ingresarás a una sesión del Esquema 48 con todas las funciones scsh disponibles. Sin embargo, esto definitivamente no es adecuado para el trabajo interactivo: no hay edición de línea de comandos, no hay historial de línea de comandos, no se completa el nombre de archivo / función, no hay sintaxis concisa, etc.

Para aliviar estos problemas, Martin Gasbichler y Eric Knauel han escrito Commander S, que se ejecuta sobre scsh y proporciona un entorno interactivo cómodo. Una de sus características novedosas es que puede comprender la salida de muchos comandos de Unix y permite al usuario navegar y manipularlo de formas útiles. Puede encontrar más información sobre Commander S en el documento que lo describe: http://www.deinprogramm.de/scheme-2005/05-knauel/05-knauel.pdf Las instrucciones sobre cómo obtener e instalar Commander S están disponibles en Sitio web de scsh: http://www.scsh.net/resources/commander-s.html

Entonces tal vez esa sea la respuesta real.

Keith Thompson
fuente
7

En la categoría de responder directamente a la pregunta, está el shell ES que está destinado a ser un reemplazo funcional para Bash y Zsh, etc.

En segundo lugar, en la categoría de ayudarlo a escribir un shell estándar más funcional, considere aprender la técnica de 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

El primer bucle while es funcional keep(transmite solo los valores no nulos que salen del bucle) y el segundo es un each(mapa solo para efectos secundarios).

Este es un tremendo impulso para fp en los depósitos.

Es posible expresar muchas cosas en un estilo más fp en un shell, simplemente no es tan fácil como podría ser. Parece que no hay mucho interés en hacer mejores conchas, a pesar de que todos las usamos mucho.

nic ferrier
fuente
6

Las conchas de estilo Bourne estándar ( sh, bash, ksh, etc.) ya le permiten hacer:

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

(Tenga en cuenta la necesidad de punto doy coma antes y done.) Además, en bashy otros shells, si $reposolo aparece una vez en el comando, puede escribir:

git clone $host/{repo1,repo2,repo3}
jwodder
fuente
claro, y lo uso mucho. pero ¿qué pasa con otras cosas, como las funciones lambda?
8
git clone $host/{repo1,repo2,repo3}no hace lo mismo que el forbucle; Invoca git cloneuna vez con tres argumentos. El hecho de que esencialmente haga lo mismo es un artefacto de cómo git clonefunciona; no necesariamente se aplica a otros comandos. (Compárese echo foo bar bazcon echo foo; echo bar; echo baz, por ejemplo.)
Keith Thompson
@caruccio que puede usar FUN=eval 'git clone '"$host"'$0 para definir una lambda para usar comofor repo in repo{1,2,3} ; do $FUN $repo ; done
pqnet
El mayor problema es que las herramientas de Unix a menudo tienen efectos secundarios (como escribir en archivos), por lo que a menudo no puede componerlas como desearía hacer en un lenguaje funcional.
weberc2
2

Scheme Shell, scsh, es realmente bueno.

Como señala Keith Thompson, no es útil como un shell interactivo (aunque el Comandante S parece un experimento interesante). En cambio, es un excelente lenguaje de programación para contextos donde es útil tener todos los enlaces POSIX, lo que incluye casos en los que desea llamar a otras aplicaciones de Unix. Un script de shell de más de unas pocas docenas de líneas siempre se sentirá como un truco, sin importar cuán prolijamente escriba sh; en contraste, no hay nada que te detenga escribiendo importantes programas usando scsh.

scsh no es muy compacto (la brevedad es tanto la fortaleza como la debilidad de los lenguajes sh-family), pero es potente.

Debido a que es útil y práctico para tareas pequeñas y grandes, scsh es, por cierto, una buena manera de familiarizarse con un Esquema (aunque, si ese fuera su objetivo, también podría ir directamente a Racket, en estos días).

Las ventajas de los lenguajes funcionales no son solo para las tareas intensivas en listas (aunque debido a su historial, tienden a favorecer las listas como una estructura de datos), es una forma realmente sólida de escribir programas, una vez que bebe el kool- correcto ayuda.

No hay un sentido significativo en el que los shells de estilo sh sean funcionales, y Python solo es funcional en el sentido marginal de que tiene una función lambda.

Gris normando
fuente
2

Los proyectiles son necesariamente extremadamente expresivos, lo que significa que logra lotes con menos líneas, tokens, etc.

Por lo general, hacemos que los lenguajes sean expresivos al diseñarlos para un propósito especial, como shells o DSL como R, maple, etc. Y encuentra relativamente poca expresividad en la mayoría de los lenguajes de propósito general como C, C ++, Java, etc.

Python, Perl, Ruby, etc. son lenguajes de uso general que son más expresivos en formas similares a las conchas, la escritura del pato ala. Entonces, las DSL se sueldan sobre ellas, como Sage para las matemáticas. Sin embargo, no es tan bueno para los comandos de shell reales .

El esquema no es tan expresivo, incluso una vez que construyes un DLS, debido a todos los paréntesis.

Sin embargo, existen lenguajes funcionales como Haskell con una enorme expresividad y una gran capacidad para construir DSL. Esfuerzo interesante para construir un caparazón en Haskell son las tortugas y las conchas .

En la práctica, hay una curva de aprendizaje con herramientas de esfuerzo debido al sistema de tipo potente pero restrictivo de Haskell, pero muestran una promesa considerable.

Jeff Burdges
fuente
1

Primero, deberías usarlo en "${files[@]}"todas partes ${files[*]}. De lo contrario, los espacios te arruinarán.

El shell ya es bastante funcional; si piensa que en términos de salida de texto son listas de líneas, entonces grepis filter, xargsis map, etc. Las tuberías son muy funcionales.

El shell no es el entorno de programación más amigable, pero es mucho más adecuado para el uso interactivo que Python. Y tiene la característica muy buena de que la API y la interfaz de usuario son idénticas: aprenda ambas cosas a la vez.

No entiendo por qué te parece cp [ os.path.join('dist', os.path.basename(file)) for file in FILES ] 'dist'preferible cp "${FILES[@]}" dist. Este último es mucho menos tipeado.

Mark Reed
fuente
0

No sé si es "funcional", pero también hay rc , que el documento scsh menciona. Es un antecesor de es.

En Linux Mint (y probablemente Debian, Ubuntu ...) puedes probarlo con

sudo apt-get install rc
man rc
rc
spelufo
fuente