top of page
Search

Shell scripting with marcel

  • Writer: Jack Orenstein
    Jack Orenstein
  • Nov 13, 2025
  • 2 min read


You can write shell scripts using marcel. I created a source file,

hello.m containing these commands:

#!/usr/bin/env marcel
('Hello world')

I then made the file executable and executed it:

jao@loon:/tmp$ ./hello.m
Hello world

Here is a script, recent.m, to find files recursively inside the

current directory, that have changed in the last 10 days.

#!/usr/bin/env marcel
ls -fr | select (f: now() - f.mtime < days(10))

What about modifying this so that it works in a directory given on the command line? This is one way:

#!/usr/bin/env marcel
(parse_args(dir=anon()))
ls -fr (dir[0]) | select (f: now() - f.mtime < days(10))

The parse_args function parses the scripts command-line arguments. anon() yields a list of the command line arguments and puts them into the variable dir. You could also do this:

#!/usr/bin/env marcel
(parse_args(dir=anon()))
ls -fr (ARGV[1]) | select (f: now() - f.mtime < days(10))

since parse_args puts all of the command line arguments, including the name of the script itself, into the variable ARGV. What if you wanted to pass in the number of days to check for, instead of hard-wiring 10? This works:

#!/usr/bin/env marcel
(parse_args(_=anon()))
ls -fr (ARGV[1]) | select (f: now() - f.mtime < days(int(ARGV[2])))

But this has a few problems:


  • A user of the script needs to know the order of the arguments.

  • The code is hard to read because the arguments are not assigned to separate variables.

  • The cast of the second argument to int has to be explicit.


Another way is to rely on parse_args to provide command-line flags,

e.g.

#!/usr/bin/env marcel
(parse_args(dir=flag('-d'), \
            n=int_flag('-n')))
ls -fr (dir) | select (f: now() - f.mtime < days(n))

Now, the recent.m script command has flags: -d to specify the directory, and -n to specify the number of days. The script can now be invoked like this:

jao@loon:/tmp$ ./recent.m -d ~/git/marcel -n 1

You can also provide for longer flags, e.g.

#!/usr/bin/env marcel
(parse_args(dir=flag('-d', '--dir'), \
            n=int_flag('-n')))
ls -fr (dir) | select (f: now() - f.mtime < days(n))

And you can specify default values:

#!/usr/bin/env marcel
(parse_args(dir=flag('-d', '--dir', default='.'), \
            n=int_flag('-n', default=1)))
ls -fr (dir) | select (f: now() - f.mtime < days(n))

If you don't have a suitable default value, and the command-line must specify the flag's value, you can make the flag required:

#!/usr/bin/env marcel
(parse_args(dir=flag('-d', '--dir', default='.'), \
            n=int_flag('-n', required=True)))
ls -fr (dir) | select (f: now() - f.mtime < days(n))

 
 
 

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

 
 
 

Comments


  • github
  • email
bottom of page