Archive for the 'Linux' Category

Using SBCL for Common Lisp shell scripting

Sunday, October 5th, 2008

I have previously developed some Commom Lisp shell scripts with Emacs/Slime/SBCL and used Clisp for running the scripts. But after running into a compatibility problem between SBCL and Clisp while developing a script for maintaing an automatic mirror of my music collection where flac files are converted to much smaller ogg files, I decided I might as well do what has to be done for using SBCL directly for running the script.

Prepping SBCL

As was mentioned in a comment in my previous post about using Common Lisp for shell scripting, the SBCL manual outlines a piece of code that must be added to an initialization file (I have added it to my $HOME/.sbclrc file).

After adding that to .sbclrc, the next step is to add a shebang line to my script


#!/usr/bin/sbcl --noinform

Adapting for development

The problem now is that the code that is needed for running the script will also be executed while compiling the file inside Slime. I found that this can be fixed by inspecting the *posix-argv* variable. This is a list, that inside Slime has one entry (“/usr/bin/sbcl”), and when the script is executed from the command line has two entries (path to the SBCL interpreter and path to your script in addition to possible command line arguments to the scripts). So if *posix-argv* is longer than 1, we can execute the script. One caveat here, if you are inside a package, *posix-argv* is not directly available. We must use sb-ext:*posix-argv* instead. This leads us to the following file structure:


#!/usr/bin/sbcl --noinform

;; Lisp code (defuns, defclasses, whatever)

;; If run from command line, the following if-test will succeed
(if (> (length sb-ext:*posix-argv*) 1)
;; Code that is executed from the command line only goes here
)

Now, the script can be developed as usual in Slime and be executed from the command line without changing anything. This also means that the command line arguments to the script is found from the third position and onwards in ext:*posix-argv*.

Script details

The complete script.

This loops through my music directory and creates a parallell directory structure where flac files are converted to ogg files and other file types are just hard linked to the original file. Soft links does not work, because when you try to copy the files to your portable music player, you get a soft link/permission error instead of getting your actual music file.

The flac to ogg conversion is done with sox, so you need to install sox in addition to sbcl and cl-asdf to run this script.

Script usage

General:
./converter.lisp basedir targetdir quality
Example:
./converter.lisp /media/sda4/musikk/ /media/sda4/ogg-musikk/ 5
Note: You need the ending / in the directory paths, it does not work otherwise.

Portability hints for Clisp

The main problem I ran into with Clisp is different behaviour in the directory function. This can probably be fixed by using the complete pathname library from PCL chapter 15. The shebang line must be changed to f.ex.
#!/usr/bin/env clisp
and command line arguments are available in ext:*args*

More hints for porting shell scripts to other CL implementations are available in the Common Lisp Cookbook.

Learning Common Lisp by using it for shell scripting

Sunday, May 13th, 2007

For quite a while now, Lisp, or more specifically, Common Lisp has been on my list of languages to learn.
Lack of time and suitable projects for learning has put it off for a quite a while. And, while Lisp can be a neat
language for almost everything, a significant effort is required for getting up to sufficient speed for programming a typical web application.

Getting the idea

A post I found on comp.lang.lisp
raised the subject of
using Common Lisp for shell scripting
. So, I thought that shell scripting would be perfect for learning Common Lisp. Small programs that are done quickly and are usable are a lot more motivating
than dabbling with a small part of a normal application and not getting anywhere near a finished project.

So far, it’s been pretty rewarding. I have written a small backup utility (script source) that copies a file and adds a timestamp to the filename and a script for reminding me every time one of my domain names
closes in on its expiration date (script source). Variable binding with let and multiple-value-bind, the
format directive and date handling are the most important lessons I have learned from these scripts.

Shell scripting quirks

Compared to a normal Common Lisp program, there are two things to notice. First, the shebang line
that is required for use as a shell script (#!/usr/bin/env clisp). It causes a syntax error in Lisp so I
comment it out for development. Second, the whole script is fired with a main function that takes no
arguments. The main call is also commented out for development. I have basically followed the model
from Lars Rune Nøstdal’s example script from the mentioned CLL thread
and I think the idea behind this approach is that all functions can be developed and tested
independently. When going from development to executable shell script, all that is needed is to uncoment the shebang line and the call to the main function.

You can probably use any Common Lisp implementation for this. Clisp is quite small so it works well for shell scripting and is what I have used for my scripts.

Script usage

Usage of the backup script (after making the script executable with chmod +x clbackup.lisp):

harald@semmentjern:~/prog/lisp$ mkdir test
harald@semmentjern:~/prog/lisp$ touch test/somefile.txt
harald@semmentjern:~/prog/lisp$ ls test
somefile.txt
harald@semmentjern:~/prog/lisp$ ./clbackup.lisp test/somefile.txt 
Copying file test/somefile.txt to test/somefile.txt.20070513154857
harald@semmentjern:~/prog/lisp$ ls test
somefile.txt  somefile.txt.20070513154857

Usage of the domain alert script (with a 150 days limit):

harald@semmentjern:~/prog/lisp$ ./domainalert.lisp 150
goodwebhosting.info expires in 144 days
flaks.net expires in 150 days

Customizing keyboard shortcuts in Fluxbox

Tuesday, April 3rd, 2007

Out of the box, Fluxbox provides only the most basic keyboard shortucts for
flipping through your applications and workspaces. Fortunately, Fluxbox
includes a simple but efficient way of customizing your keyboard shortcuts
for managing your desktop and applications.

The fluxbox keys file

Inside your fluxbox directory (.fluxbox), there is a file with the name keys. By default, mine looked like this:

Mod1 Tab :NextWindow
Mod1 Shift Tab :PrevWindow
Mod1 F1 :Workspace 1
Mod1 F2 :Workspace 2
Mod1 F3 :Workspace 3
Mod1 F4 :Workspace 4
Mod1 F5 :Workspace 5
Mod1 F6 :Workspace 6
Mod1 F7 :Workspace 7
Mod1 F8 :Workspace 8
Mod1 F9 :Workspace 9
Mod1 F10 :Workspace 10
Mod1 F11 :Workspace 11
Mod1 F12 :Workspace 12

Now, Mod1 is your alt key, so this file says that you can flip
through your windows (backward and forward) with alt-tab and alt-shift-tab.
This is just like on any operating system. Alt-Fn (n from 1 to 12) takes you to
the workspace with the corresponding number. You probably have 4 workspaces by
default so the last 8 doesn’t do anything.

Your first customized keyboard shortcut

One common task is to minimize a window (or iconize as it’s also called).
To avoid clashes with application shortcuts, the ctrl-alt combination can be
used as a namespace for your shortcuts. Add the following line to your kes file (below the current content):

Mod1 Control i :Minimize

To make Fluxbox aware of this new keyboard shortcut, save your keys file and
reconfigure Fluxbox by right clicking on an empty area on your desktop and select Reconfigure from the menu. You can now press ctrl-alt-i to
minimize the current window.

A trick to ease your experiments

The whole point of this is to enable more efficient use of your keyboard and
less mouse usage. So to make your keyboard experiments 100% keyboard-driven
you should be able to reconfigure fluxbox with a keystroke. The command for
this is of course called Reconfigure and I have chosen to bind this to
ctrl-alt-r. The following line in my keys file enables that:

Mod1 Control r :Reconfigure

Now you can just save your keys file and press ctrl-alt-r to test your configuration. You can test this by binding Minimize to a different key.

Controlling the Audacious media player

With the ExecCommand directive, you can bind regular commands that you would
normally type in a shell to keyboard combinations of your choice. One
application that is controllable from the command line is Audacious, an
uncomplicated audio player forked from Beep Media Player which was forked
from XMMS a long time ago. So we should be able to control Audacious with some simple keystrokes.

Starting Audacious

Most keyboards have a so-called Windows key that can be quite useless if you
are using Linux. This also means that it won’t clash with application shortcuts
and I think it is a good choice for binding to your favorite applications.
This key is also called the super key, so to avoid the w-word, we’ll go for that name.

The super key is called Mod4 within Fluxbox, so the line in your keys file for
starting Audacious on pressing super-a is:

Mod4 a :ExecCommand audacious

Controlling Audacious

By typing man audacious in your shell you will find out that you
can control Audacoius from the command line with the following commands
(explanations):

audacious -r  (rewind/previous track)
audacious -p  (play)
audacious -u  (pause)
audacious -s  (stop)
audacious -f (forward/next track)

These are bound to the keys z, x, c, v and b inside Audacious so we will use
those instead. For controlling applications, I have chosen the prefix
ctrl-super. The key a is then used as a prefix for Audacious. So the
following is found in my keys file:

Mod4 Control a Mod4 Control z :ExecCommand audacious -r
Mod4 Control a Mod4 Control x :ExecCommand audacious -p
Mod4 Control a Mod4 Control c :ExecCommand audacious -u
Mod4 Control a Mod4 Control v :ExecCommand audacious -s
Mod4 Control a Mod4 Control b :ExecCommand audacious -f

Reconfigure Fluxbox, and you can start and control Audacious from your keyboard
without locating the Audacious windows on your desktop. Just type
super-a for starting Audacious, ctrl-super-a x for
playing your selected track (hold down ctrl and super, type a, then x before
releasing ctrl-super). Just type ctrl-super-a b to skip to the
next track in your playlist and so on…

This was done with a fully updated Sidux Linux, Fluxbox 0.9.14 and Audacious 1.2.2. I hope it works on your setup too. You can also see my current keys file (which may or may not be updated in the future) and check out the official documentation on the subject of key bindings.