viernes, 10 de febrero de 2017

Zsh global aliases for command chaining

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

alias -g GLWEEK=' --since=1.week.ago --author=kidd'

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.

Let's see some examples:

alias -g T='| tail'
alias -g T1='T -1'
alias -g X='| xclip '
alias -g G='| grep '
alias -g GV='| grep -v '
alias -g DM='| dmenu '

Let's see a few ways we can compose this:

ls -ltr G foo GV bar T1 X
evince $(ls *pdf DM)

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




miércoles, 8 de febrero de 2017

Henry G Baker's papers

I was rereading "Out of the tarpit" paper, and by the end of it I noticed they reference a paper from Henry Baker: "Equal rights for functional objects or, the more things change, the more they are the same.". The author's name rang a bell, and I decided to explore a bit more.

So, He's the author of a paper I loved to read 3 months ago or so: Pragmatic Parsing in Common Lisp.

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.

He wrote lots of articles related to Lisp to different degrees, but most of them (the ones I skimmed) are written in a very clear language (no pun intended), and quite fun and enlightening reads.

domingo, 22 de enero de 2017

Autocomplete erc nicks with @ sign (for slack)

 This is a very quick hack for something I've wanted for some time.  I'm using slack through their IRC gateway. That allows me to use erc, yasnippets, bug-reference-mode,  and whatnot.

The few things that annoy me of that interface is that to ping users, in slack you are expected to prepend the nick with an at sign. That makes autocompletion kinda useless because, as this redditor explains , it's a pain in the ass to type the nick, autocomplete, go back, add the @ sign, and move forward.

I haven't found a way to solve this in an elegant way, but as a hack, I could add tihs advice functions that will understand @nick as well as 'nick' when autocompleting.  I'd love to be able to just type the name and the autocompletion framework fill the '@'  sign itself, but I couldn't find it, so I'll try this approach I got so far and see if it works well enough for me.

I hope it's useful for some of you, dear emacslackers :)

sábado, 21 de enero de 2017

using xargs to parallelize command line

Did you know that xargs can spawn multiple processes to execute the commands it gets? It's the poor man's gnu parallel (very poor).

Well, I've been dabbling quite a bit with shell scripts lately and I've come to this balance of using shellscripts for simple (or not so simple) tasks. It's a mix of suckless and Taco Bell programming....

Well, the problem at point was to create many connections to some api endpoints. The endpoints would be serving data in a streamming fashion (think twitter hose).   My idea would be to spawn several curls to a "circular" list of urls.

I thought about wrk (because lua), vegeta or siege, but I'm not sure how they would cope with 'persistent' connections, so I tried my luck with plain curl and bash.

It's funny how you can solve some issues in bash with so few lines of code.  I don't have stats, or anything, but the only thing I wanted, that was to generate traffic can be done in plain simple shellscripting.

Things I learned:

- ${variable:-"default-value"}   is great
- doing arithmetic in bash is next to impossible.
- xargs can spawn multiple processes, and you can control the number, so you can use the number as an upper limit.
- while true + timeout are a very nice combo when you want to generate any kind of 'ticking' or 'movement' on the loop.

Here's the script:

jueves, 19 de enero de 2017

git contribution spans (emacs case study)

 Let's play a little, just for the fun of it, and to gather some metainformation about a codebase.

I sometimes would like to find out the commit spans of the different authors. I may not care about the number of commits, but only first and last. This info may be useful to know if a repo has most long time commiters or the majority of contributors are one-off, or one-feature-and-forget.

First we'll sharpen a bit our unix chainsaw:

Here's a little helper that has proven to be very useful. It's similar to uniq, but you don't need to sort first, and also it accepts a parameter meaning the column you want to be unique. (Unique by Column)

function uc () {

    awk -F" " "!_[\$$1]++"

}


And then, you only have to look at man git-log to find out you can reverse the order of the logs, so you can track the first and the last appearence of each commiter.


git log --format='%aE %ai'  | uc 1 | sort  >/tmp/last

git log --reverse --format='%aE %ai -> '  | uc 1 | sort >/tmp/first

paste /tmp/first /tmp/last > /tmp/spans.txt


Here is the output file. it has some spurious parsing errors, but I think it still shows how powerful insights we can get with just a bit of bash, man and pipelines.

Just by chance, the day after I tried this, I discovered git-quick-stats, which is a utility tool to get simple stats out of a git repo. It's great that I could add the same functionality there too via a Pull Request :).

Big thanks to every one of the commiters in emacs, being long or short span and amount of code contributed. Thanks to y'all 

gnu parallel as a queuing system

This post is about a gnu parallel, a tool I recently discovered, and I'm starting to use a bit more every day.

At its core, it's a command to multiple commands in parallel, but it has many many different options to customize how the paralelization is done, notifications, and other configs. Take a look at the official tutorial or the man page, which contain a wealth of info and examples.

Let's get SICP videos

The use case I have today is to use it as a simple queuing system. I just want processes to start when I have a new job for them.  The task at hand is to download all sicp lectures, at one download at a time (don't want to hog the network).

First of all, we notice the pattern of the links:

  1. http://www.archive.org/download/MIT_Structure_of_Computer_Programs_1986/lec1a.mp4
  2. http://www.archive.org/download/MIT_Structure_of_Computer_Programs_1986/lec1b.mp4
  3. http://www.archive.org/download/MIT_Structure_of_Computer_Programs_1986/lec2a.mp4 
  4. http://www.archive.org/download/MIT_Structure_of_Computer_Programs_1986/lec2b.mp4 

We notice the pattern, right? Let's craft some generator for the filenames.


 perl -e 'for(1..15){for $i (('a','b')){print "wget http://www.archive.org/download/MIT_Structure_of_Computer_Programs_1986/lec$_$i.mp4\n"}}' >sicp.list


After we generated the file, we're going to run the command in the following way:

cat sicp.lisp | parallel -j1 --tmux

this makes parallel run one after the other, and just putting the outputs of each job in a tmux tab.

B, b, but.... what's the point of all this?

Ok, we didn't use parallel for anything useful, we could have run the list as a shellscript, and be happy.   The idea is that we can use this simple mechanism to treat the file as a job queue, that waits for new incomming jobs and then processes them.  Beware, it has very little logging, and you can't do very sophisticated error recovery (see --resume-failed), so it's NOT a replacement for resque/sidekiq/etc...  In fact, I'd love to see something like a suckless queuing system based on parallel and bash.

So, here's the command to use this tool as a queuing system.

touch joblist; tail -f joblist | parallel --tmux 

Then, add lines to the joblist for them to be executed. It's a very easy plumbing task:

echo "sleep 10" >joblist

tail -f works as our event loop, waiting for new tasks to come, and it will pass the tasks to parallel, that will apply the job contention depending on the number of jobs you configure it to run in parallel.

I've just scratched the surface of what parallel is able to do. Do some searching around, and take a look at the man and tutorial to get a grasp of what this amazing gnu tool is able to do.  Taco Bell programming at its best!

References

Here I'm pasting some useful refs (appart from the ones already mentioned). 

martes, 20 de diciembre de 2016

How to replace procrastination by a list of parsing techniques

Here's a very nice Wadler's paper with quite simple ideas to get you through a way of parsing which I guess predates monads, and monadic parser combinators.

How to replace failure by a list of successes.

Seeing it after playing with SMUG (Common Lisp Monadic parser combinator lib), watching MJD's Higher Order Parsing techniques with perl, and re-reading his parsing chapter definitely helped a lot to make all that fuzzy knowledge settle a bit.

Unfortunatelly, I'm not using any parsing technique very often, but I like to read about all those crazy parsing techniques. (See META: Pragmatic parsing in Common Lisp for another one (inspired by Val Schorre's no-words-to-describe-how-enlightening-is-it META-II)).