Take the 2-minute tour ×
Super User is a question and answer site for computer enthusiasts and power users. It's 100% free, no registration required.

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).


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)

share|improve this question

migrated from stackoverflow.com Apr 18 '12 at 19:34

This question came from our site for professional and enthusiast programmers.

Somewhat related: github.com/amoffat/pbs –  Josh Lee Apr 18 '12 at 18:47
There is a bit more than list comprehension to functional programming. If your main focus is writing functional code I wouldn't take python as an example. –  pqnet Aug 19 '14 at 5:00

7 Answers 7

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}
share|improve this answer
sure, and I do use it a lot. but what about other stuff, like lambda functions? –  Caruccio Apr 18 '12 at 18:57
git clone $host/{repo1,repo2,repo3} doesn't do the same thing as the for loop; it invokes git clone once with three arguments. The fact that does essentially the same thing is an artifact of how git clone works; it doesn't necessarily apply to other commands. (Compare echo foo bar baz to echo foo; echo bar; echo baz, for example.) –  Keith Thompson Apr 18 '12 at 20:41
@caruccio you can use FUN=eval 'git clone '"$host"'$0 to define a lambda to use as for repo in repo{1,2,3} ; do $FUN $repo ; done –  pqnet Aug 19 '14 at 5:21

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


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.

share|improve this answer

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.

share|improve this answer

First, you should be using "${files[@]}" everywhere you have ${files[*]}. Otherwise spaces will mess you up.

The shell is pretty functional already; if you think in terms of text output being lists of lines, then grep is filter, xargs is map, etc. Pipes are very functional.

The shell is admittedly not the friendliest programming environment, but it's much more suited to interactive use than Python. And it has the very nice feature that the API and the UI are identical - learn both at once.

I don't understand why you find cp [ os.path.join('dist', os.path.basename(file)) for file in FILES ] 'dist' preferable to cp "${FILES[@]}" dist. The latter is much less typing.

share|improve this answer

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 
  cat <<EOF | grep $username
done | while read username
  echo "you have an answer on superuser.com" | mail -s "well done" $username

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.

share|improve this answer

Don't know about it being "functional", but there is also rc, which the scsh paper mentions. It's a predecesor to es.

On Linux Mint (and probably Debian, Ubuntu...) you can try it with

sudo apt-get install rc
man rc
share|improve this answer

Shells are necessarily extremely expressive, meaning you achieve lots with fewer lines, tokens, etc.

We usually make languages expressive by designing them for a special purpose, like shells or DSLs like R, maple, etc. And you find relatively little expressiveness in most general purpose languages like C, C++, Java, etc.

Python, Perl, Ruby, etc. are general purpose languages that're more expressive in ways similar to shells, ala duck typing. So DSLs get welded onto them, ala Sage for math. Ain't so great for actual shell commands though.

Scheme is not imho that expressive, even once you build a DLS, due to all the parentheses.

There are however functional languages like Haskell with enormous expressiveness and a great capacity for building DSLs. Interesting effort to build a shell on Haskell are turtle and shelly.

In practice, there is a learning curve with efforts tools due to Haskell powerful but restrictive type system, but they show considerable promise.

share|improve this answer

Your Answer


By posting your answer, you agree to the privacy policy and terms of service.