Is there any functional-like unix shell?

I'm (really) newbie to functional programming (in fact only had contact with it using python) but seems to be a good approach for some list-intensive tasks in a shell environment.

I'd love to do something like this:

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

Is there any Unix shell with these kind of feature? Or maybe some feature to allow easy shell access (commands, env/vars, readline, etc...) from within python (the idea is to use python's interactive interpreter as a replacement to bash).

EDIT:

Maybe a comparative example would clarify. Let's say I have a list composed of dir/file:

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

And I want to do a really simple task: copy all files to dist/ AND install it in the system (it's part of a build process):

Using bash:

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

Using a "pythonic shell" approach (caution: this is imaginary code):

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

Can you see the difference ? THAT is what i'm talking about. How can not exits a shell with these kind of stuff build-in yet? It's a real pain to handle lists in shell, even its being a so common task: list of files, list of PIDs, list of everything.

And a really, really, important point: using syntax/tools/features everybody already knows: sh and python.

IPython seams to be on a good direction, but it's bloated: if var name starts with '$', it does this, if '$$' it does that. It's syntax is not "natural", so many rules and "workarounds" ([ ln.upper() for ln in !ls ] --> syntax error)


Solution 1:

There's a Scheme Shell that's probably very close to what you're looking for. I haven't used it myself.

UPDATE :

I just installed and tried it myself. It appears that scsh is more of an interactive Scheme interpreter and scripting language than a really useful interactive shell. You can't just type

echo hello

the syntax appears to be

(run (echo hello))

and it took several minutes of Googling just to find that. The first example here is:

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

which translates to:

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

but that doesn't tell you how to run a simple shell command.

This FAQ entry says:

4.6 Can I use scsh as an interactive shell?

Well, technically you can: just run the "scsh" command and you will enter a Scheme 48 session with all scsh functions available. However, this is definitely not suitable for interactive work: there is no command-line editing, no command-line history, no file/function name completion, no terse syntax, etc.

To alleviate these problems, Martin Gasbichler and Eric Knauel have written Commander S, which runs on top of scsh and provides a comfortable interactive environment. One of its novel features is that it can understand the output of many Unix commands, and allows the user to browse and manipulate it in useful ways. More information about Commander S can be found in the paper describing it: http://www.deinprogramm.de/scheme-2005/05-knauel/05-knauel.pdf Instructions about how to obtain and install Commander S are available from the scsh Web site: http://www.scsh.net/resources/commander-s.html

So maybe that's the real answer.

Solution 2:

In the category of directly answering the question, there is the ES shell which is intended as a functional replacement for Bash and Zsh etc.

Secondly, in the category of helping you write more functional standard shell, consider learning the pipemill technique:

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

The first while loop is a functional keep (pass on only the non-null values that come out of the loop) and the second is an each (map for side effects only).

This is a tremendous boost to fp in shells.

It is possible to express many things in a more fp style in a shell, it just isn't as easy as it might be. It seems that there is not much interest in making better shells, even though we all use them such a lot.

Solution 3:

The standard Bourne-style shells (sh, bash, ksh, etc.) already let you do:

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

(Note the need for semicolons before do and done.) Additionally, in bash and other shells, if $repo only appears once in the command, you can write:

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

Solution 4:

Scheme Shell, scsh, is really good.

As Keith Thompson notes, it's not useful as an interactive shell (though Commander S looks like an interesting experiment). Instead, it's an excellent programming language for contexts where having all the POSIX bindings is useful -- that includes cases where you want to call other unix applications. A shell script of more than a few dozen lines will always feel like a hack, no matter how neatly you write sh; in contrast there's nothing stopping you writing significant programs using scsh.

scsh isn't very compact (brevity is both the strength and the weakness of sh-family languages), but it's powerful.

Because it's useful and practical for small and large tasks, scsh is incidentally a good way of getting to grips with a Scheme (although, if that happened to be your goal, you might as well go straight to Racket, these days).

The advantages of functional languages aren't just for list-intensive tasks (though because of their history, they tend to favour lists as a data structure) -- it's a really robust way to get programs written, once you drink the right kool-aid.

There is no meaningful sense in which the sh-style shells are functional, and Python is only functional in the marginal sense that it has a lambda function.