top of page
Search

Marcel the Shell

  • Writer: Jack Orenstein
    Jack Orenstein
  • Jun 16, 2020
  • 2 min read

Welcome to marcel! Marcel is yet another shell that pipes objects between commands, instead of strings. What is different about marcel is it's reliance on Python. First, it is implemented in Python.


Second, marcel exposes Python. If you have an input stream of Files and you want to output a stream of (file name, file size) tuples, then you can use the map operator, which applies a function to input values to generate output values. The function used by the map operator is an ordinary Python function. So for example:

ls -fr | map (lambda file: (file.path, file.size))

ls -fr visits the current directly recursively (-r) and outputs files only (-f), not directories or symlinks. The function is in parentheses, (you could omit the lambda keyword if you'd like).


Third, marcel uses Python to take a different approach to scripting. Shell commands are augmented by control structures and rudimentary datatypes to provide a scripting language. These languages are usually pretty poorly designed, (e.g. bash). And of course, it's yet another language to learn. Furthermore, individual commands have extensive sub-languages, and to do anything sophisticated requires the reading of man pages documenting these sub-languages.


The marcel approach is to recognize that Python is a good programming language, but is bad at scripting because of the API to the host OS. You can't just run the ls command from Python, for example, you have to use something like subprocess.Popen. Piping requires chaining the stdin/stdout arguments together from successive Popen calls. Marcel offers an API module, marcel.api, which provides much cleaner integration. For example, the above example, done as Python code:

from marcel.api import *

for path, size in (ls(file=True, recursive=True) 
                   | map(lambda file: (file.path, file.size))):
    print(f'{file.path}: {file.size})

The ls -fr command, which was used in the shell, turns into ls(file=True, recursive=True) in the API. The pipe symbol again pipes the ls output to the map input. The command output is made available as a Python iterator, so that a for loop can iterate over the results.


 
 
 

Recent Posts

See All
Marcel runs on MacOS!

Yes, marcel now runs on MacOS. I've been working on this for months , and it's finally done. This was a major project because: Most...

 
 
 
Compiling Marcel to Python

Marcel is interpreted. A command like this: gen 100 | map (x: (x, x**0.5)) | write gives rise to objects of type marcel.op.Gen,...

 
 
 
  • github
  • email
bottom of page