viernes, 10 de febrero de 2017

(The motivation for this post is my recent discovery of oilshell, a very promising new shell. The author has been posting regularly for some time, and he has quite insightful ideas. Some of them I had them too and I didn't know they conformed to some defined concepts (I discovered Bernstein chaining two weeks ago). Whatever.... here it goes, as a way to open more discussion topics)

There's a small zsh trick that is unmatched by any other shell. It's maybe just syntax sugar, but it enables some pretty neat tricks.

The feature is global aliases (or "alias -g").

They are alias substituted
anywhere on a line. Global aliases can be used to abbreviate
frequently-typed usernames, hostnames, etc.

I think of them as some kind of reader macro, that applies substitutions to strings at read time, so there's no need to substitute a full command by another full command.

alias -g

The simplest case is to make an alias for a bunch of flags for a command you use many times (Also look at zsh globbing to see other examples of 'simple' alias -g).

Given this ("git last week"), we can use it in different contexts. In this example, the only useful ones that come to my mind are "git log" and "gitk", but to get the feeling of what it does internally, you can 'echo GLWEEK' and you'll get the flags printed. It allows for a lot of composability, and Bernstein chaining because everything concatenates and tries to apply.

Piping through

Another way to see it is as a way to Forthify your shell a bit more with pipes. This is how I use the feature the most:

If you make aliases expand to pipes (left, right or both), you can make many unix commands compose in a seamless way. Under the hood, you know that the connexion happens through stdin/stdout, but visually it eliminates most of the clutter.

With some training, it's very easy to see that this will copy the last file that matches 'foo' but doesn't match 'bar', or it will open the selected pdf file.

XARGS

There are some commands that do not accept arguments from stdin, but they require them to be as command line arguments. in those cases, one starts doing things like:

mplayer $(ls *(mpg|mp4|avi) DM )

Which works, but it breaks the pipe flow. For that, we can use xargs (as we saw a few posts ago), and we can use, again, another global alias:

alias -g XA='| xargs '

now we can do "ls *(mpg|mp4|avi) DM XA mplayer" .

FUNCTIONS

Here's an example of a uniq function on steroids. it accepts a field number to uniquify, and the rows do not have to be sorted to work.

function uc () {
awk -F" " "!_[\$$1]++"
}

alias -g UC=' | uc '
alias -g P1='| awk "{print \$1}"'

Let's see how to use this one: For the sake of the example, let's pretend we want to know the users that have some process running in my machine.

ps -axuf GV USER UC 1 P1

Of course, this is the same as typing the vanilla commands yourself, but IMO, it makes quite a lot of difference on the experimentation easiness.

There are some more fancy tricks, but we'll leave them for some future post.

The whole point of this is that some features allow for greater composability, and let you build your ad-hoc tools in a much easier way than others. Oilshell has plans to have '{', '}' and '[', ']' as operators, so you can have block like syntax (maybe the semantics of tcl's quoting would be enough?). Anyway, it's great that the shell space is active and there are interesting things happening. I'll keep oil in my radar :)

The article is an adaptation of Val Schorre's META-II paper to common lisp, leveraging reader macros to create parsers in very few lines of code.

Reading a bit more, I found this other very enjoyable article: Metacircular Semantics for Common Lisp Special Forms . This one takes the approach of metacircular interpreters to explain the behaviour of some common lisp special forms in terms of other common lisp expressions. I love the bottom up approach, and reminds me of "git from the bottom up", or CTMCP's explanations of the extensions to the Oz language.