Existe algum shell unix funcional?


18

Sou (realmente) novato em programação funcional (na verdade, só tive contato com ele usando python), mas parece ser uma boa abordagem para algumas tarefas que exigem muita lista em um ambiente shell.

Eu adoraria fazer algo assim:

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

Existe algum shell Unix com esse tipo de recurso? Ou talvez algum recurso para permitir acesso fácil ao shell (comandos, env / vars, readline, etc ...) de dentro do python (a idéia é usar o interpretador interativo do python como um substituto para o bash).

EDITAR:

Talvez um exemplo comparativo esclareça. Digamos que eu tenho uma lista composta de dir / file :

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

E eu quero fazer uma tarefa muito simples: copiar todos os arquivos para dist / AND instalá-lo no sistema (faz parte de um processo de compilação):

Usando o bash:

$ cp $ {files [*]} dist /
$ cd dist && rpm -Uvh $ (para f em $ {files [*]}; faça o nome da base $ f; done))

Usando uma abordagem de "casca pitônica" (cuidado: este é um código imaginário):

$ cp [os.path.join ('dist', os.path.basename (file)) para o arquivo em FILES] 'dist'

Você consegue ver a diferença? É disso que estou falando. Como ainda não é possível sair de um shell com esse tipo de material? É uma verdadeira dor lidar com listas no shell, mesmo sendo uma tarefa tão comum: lista de arquivos, lista de PIDs, lista de tudo.

E um ponto muito, muito importante: usando sintaxe / ferramentas / recursos que todo mundo já conhece: sh e python.

O IPython parece estar em uma boa direção, mas está inchado: se o nome do var começar com '$', ele fará isso, se '$$' fizer isso. Sua sintaxe não é "natural", existem muitas regras e "soluções alternativas" ( [ ln.upper() for ln in !ls ] -> erro de sintaxe)


Algo relacionado: github.com/amoffat/pbs
Josh Lee


4
Há um pouco mais do que compreensão de lista na programação funcional. Se o seu foco principal é escrever código funcional, eu não usaria o python como exemplo.
pqnet 19/08/14

Respostas:


10

Há um Shell de esquema que provavelmente está muito próximo do que você está procurando. Eu não usei eu mesmo.

ATUALIZAÇÃO:

Acabei de instalar e tentei eu mesmo. Parece que o scsh é mais um interpretador de esquema interativo e uma linguagem de script do que um shell interativo realmente útil. Você não pode simplesmente digitar

echo hello

a sintaxe parece ser

(run (echo hello))

e levou vários minutos pesquisando no Google apenas para descobrir isso. O primeiro exemplo aqui é:

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

que se traduz em:

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

mas isso não mostra como executar um simples comando shell.

Esta entrada da FAQ diz:

4.6 Posso usar o scsh como um shell interativo?

Bem, tecnicamente você pode: basta executar o comando "scsh" e você entrará em uma sessão do Scheme 48 com todas as funções disponíveis. No entanto, isso definitivamente não é adequado para trabalhos interativos: não há edição de linha de comando, histórico de linha de comando, conclusão de nome de arquivo / função, sintaxe concisa, etc.

Para aliviar esses problemas, Martin Gasbichler e Eric Knauel escreveram o Commander S, que roda em cima do scsh e fornece um ambiente interativo confortável. Um de seus novos recursos é que ele pode entender a saída de muitos comandos do Unix e permite ao usuário navegar e manipulá-lo de maneiras úteis. Mais informações sobre o Commander S podem ser encontradas no documento que o descreve: http://www.deinprogramm.de/scheme-2005/05-knauel/05-knauel.pdf Instruções sobre como obter e instalar o Commander S estão disponíveis no site Site scsh: http://www.scsh.net/resources/commander-s.html

Então talvez essa seja a resposta real.


7

Na categoria de responder diretamente à pergunta, existe o shell ES, que se destina a substituir funcional o Bash e o Zsh, etc.

Em segundo lugar, na categoria de ajudá-lo a escrever shell padrão mais funcional, considere aprender a 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

O primeiro loop while é funcional keep(transmite apenas os valores não nulos que saem do loop) e o segundo é um each(mapa apenas para efeitos colaterais).

Este é um tremendo impulso ao FP nas conchas.

É possível expressar muitas coisas em um estilo mais fp em um shell, simplesmente não é tão fácil quanto pode ser. Parece que não há muito interesse em fazer conchas melhores, embora todos nós as usemos tanto.


6

As conchas Bourne de estilo padrão ( sh, bash, ksh, etc.) já permitem que você faça:

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

(Observe a necessidade de ponto doe vírgula antes e done.) Além disso, em bashe outros shells, se $repoaparecer apenas uma vez no comando, você pode escrever:

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

claro, e eu uso muito isso. mas e outras coisas, como funções lambda?

8
git clone $host/{repo1,repo2,repo3}não faz a mesma coisa que o forloop; invoca git cloneuma vez com três argumentos. O fato de fazer essencialmente a mesma coisa é um artefato de como git clonefunciona; não se aplica necessariamente a outros comandos. (Compare echo foo bar baza echo foo; echo bar; echo baz, por exemplo.)
Keith Thompson

@caruccio você pode usar FUN=eval 'git clone '"$host"'$0 para definir um lambda para uso comofor repo in repo{1,2,3} ; do $FUN $repo ; done
pqnet

O maior problema é que as ferramentas unix costumam ter efeitos colaterais (como gravar em arquivos); portanto, você não pode compor como deseja em uma linguagem funcional.
weberc2

2

Esquema Shell, scsh, é realmente bom.

Como observa Keith Thompson, não é útil como um shell interativo (embora o Commander S pareça um experimento interessante). Em vez disso, é uma excelente linguagem de programação para contextos em que é útil ter todas as ligações POSIX - isso inclui casos em que você deseja chamar outros aplicativos unix. Um script de shell com mais de algumas dezenas de linhas sempre parecerá um hack, não importa o quão bem você escreva sh; em contraste, não há nada que o impeça de escrever programas significativos usando o scsh.

O scsh não é muito compacto (a brevidade é a força e a fraqueza das linguagens da família sh), mas é poderoso.

Por ser útil e prático para tarefas pequenas e grandes, o scsh é, aliás, uma boa maneira de se familiarizar com um esquema (embora, se esse fosse o seu objetivo, você também poderia ir direto para o Racket hoje em dia).

As vantagens das linguagens funcionais não são apenas para tarefas com muitas listas (embora, devido ao seu histórico, elas tendam a favorecer as listas como uma estrutura de dados) - é uma maneira realmente robusta de escrever programas, depois de beber o kool certo. ajuda.

Não há um sentido significativo no qual os shells do estilo sh sejam funcionais, e o Python é funcional apenas no sentido marginal de que ele possui uma função lambda.


2

Os reservatórios são necessariamente extremamente expressivos, o que significa que você obtém lotes com menos linhas, tokens etc.

Geralmente, tornamos as linguagens expressivas projetando-as para uma finalidade especial, como shells ou DSLs como R, maple, etc. E você encontra relativamente pouca expressividade na maioria das linguagens de uso geral, como C, C ++, Java, etc.

Python, Perl, Ruby etc. são linguagens de uso geral que são mais expressivas de maneira semelhante a shells, digitando ala duck. Então as DSLs são soldadas, ala Sage para matemática. Porém, não é tão bom para comandos reais de shell .

O esquema não é tão expressivo, mesmo depois de criar um DLS, devido a todos os parênteses.

No entanto, existem linguagens funcionais como Haskell com enorme expressividade e uma grande capacidade para criar DSLs. Esforço interessante para construir um escudo em Haskell são tartaruga e Shelly .

Na prática, há uma curva de aprendizado com ferramentas de esforços devido ao sistema de tipo Haskell poderoso, porém restritivo, mas elas mostram uma promessa considerável.


1

Primeiro, você deve usar em "${files[@]}"qualquer lugar que tenha ${files[*]}. Caso contrário, os espaços vão atrapalhar você.

O shell já é bastante funcional; se você pensa em termos de saída de texto como listas de linhas, então grepé filter, xargsé mapetc. Os tubos são muito funcionais.

É certo que o shell não é o ambiente de programação mais amigável, mas é muito mais adequado para uso interativo que o Python. E tem o recurso muito bom de que a API e a interface do usuário são idênticas - aprenda as duas ao mesmo tempo.

Não entendo por que você acha cp [ os.path.join('dist', os.path.basename(file)) for file in FILES ] 'dist'preferível cp "${FILES[@]}" dist. Este último é muito menos digitado.


0

Não sei se é "funcional", mas também há rc , que o artigo scsh menciona. É um predecessor para es.

No Linux Mint (e provavelmente Debian, Ubuntu ...), você pode experimentá-lo com

sudo apt-get install rc
man rc
rc
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.