Marcel (<a href="https://marceltheshell.org" rel="nofollow">https://marceltheshell.org</a>) is a shell designed around the idea of piping objects instead of strings, in a way that should be more familiar to Linux users. It is designed to be bash-like. Instead of learning sublanguages (awk, find, etc.), customization is done by Python, and in fact, it is Python objects that are piped between commands.<p>To take an example from the article, here is the marcel code to read penguins.csv and get unique species values, sorted:<p><pre><code> read -c penguins.csv | map (species, *: species) | unique | sort
</code></pre>
Or to find species = 'gentoo':<p><pre><code> read -c penguins.csv | select (species, *: species == 'gentoo')
</code></pre>
"read -c penguins.csv" reads the file, but instead of returning strings, -c causes each line to be parsed into a Python tuple.<p>In both cases, parens delimit a Python lambda (you can omit or include "lambda"). "species, *" binds species to the first value of a field, and * to a tuple of the remaining fields. So "map (species, *: species)" maps the row to just the value of the species column. "select (species, *: species == 'gentoo')" uses a Python expression to select rows with species 'gentoo'.<p>You can also do grouping and aggregation in marcel. For example, this command locates files recursively, obtains the extension and size of each, groups by extension, and then sums sizes for each extension:<p><pre><code> ls -fr | map (file: (file.suffix, file.size)) | red . +
</code></pre>
"ls -fr" lists everything recursively (-r), yielding only files (-f). A stream of File objects is piped to map, which maps each File to an (extension, size) tuple. "red . +" does reduction (i.e., grouping and aggregation. The "." specifies that the first part of the input tuple, the extension, is used for grouping, and the second part, the file size, is aggregated using +.