I can has scripting?

Brainstorming a bit here...

So I saw this cool one-liner script. It displays a directory tree:

ls -R | grep ":$" | sed -e 's/:$//' -e 's/[^-][^\/]*\//--/g' -e 's/^/   /' -e 's/-/|/'

I have been hacking (on and off) on an Awk-like tool that uses Chicken for scripting. Its working title is s1, and so far it supports begin/main/end blocks like Awk, and $N-notation for quick access to fields.

The real problem is not, adding Awk-like functionality as Scheme functions, but rather, making the Scheme concise enough that it can be used for one-liners. For example, the following works, but is still too verbose:

ls -l | csi -ss s1.scm '(before (set! total 0)) (set! total (+ total (as-number $5))) (after (print total))'

(It shows the total size of files in the current directory, in case it wasn't obvious. :-)

It gets even worse when we try to emulate the ls/grep/sed script mentioned above. Writing this as a one-line just isn't feasible at this point; rather, I have to use a script:

;; tree.s1
;; Call with: ls -aR | csi -ss s1.scm -s tree.s1

(define (branch parts)
  (let* ((parts (reverse parts))
         (dirname (string-trim-right (first parts) #\:))
         (line (apply conc (map (lambda (s) "--") (cdr parts)))))
    (conc "|" line dirname)))

(when (string-suffix? ":" $0)
  (let* ((parts (string-split $0 "/")))
    (print "   " (branch parts))))

Much of the work goes into processing strings and lists, but even without that the code probably still would not fit on one line.

Granted, it's hard to beat the conciseness of regular expressions (as used by grep and sed), but if I want s1 to be useful, it needs to support (much) shorter code. (Maybe I should rewrite it in Arc? ;-)

Here are some thoughts about making this shorter:

1. I dearly miss slicing. In Python, I would have used s[:-1] to chop off the trailing colon. Adding a slice function to the toolbox would probably be useful.

2. I could leverage some of the Awk-like features. This Reddit comment does just that:

find "${1-.}" -type d | awk -F/ '{printf "  |%*s%s\n",(NF-1)*2,"",$NF}'

It takes advantage of the following features:

  • using "/" as a field separator (effectively splitting the path with no extra code)
  • using NF (indicating the number of fields in a line) to compute the indentation level
  • using $NF to display the last field (i.e. the directory name we want to see)

As it happens, s1 can do all these things as well, but it won't be quite as concise. This is something to work on. Maybe there could be a special variable (or symbol) that translates to (length *fields*). I would have to hack the current $-literal to accept any expression, not just a number literal.

The tricky part is to make things concise while still keeping the spirit of Scheme. :-/ s1 will never automagically coerce numbers to strings (or vice versa), for example. I can, however, make it easy to convert them explicitly. (This is also the Pythoneer in me speaking... explicit is better than implicit, and all that good stuff.)

Anyway, there was really no point to this post, except letting the world know that I am tinkering with a new toy. :-) If it ever actually becomes useful, I'll release it... Until then, I might talk more about it here.

3 Comments »

  1. John Cowan said,

    February 7, 2008 @ 8:37 am

    Implicit is clearly better than explicit in the domain of throwaway code, though. Anyhow, if Pythoneers really believed explicit was better than implicit, they'd all switch to Java.

  2. Hans Nowak said,

    February 7, 2008 @ 10:22 am

    """Implicit is clearly better than explicit in the domain of throwaway code, though."""

    Maybe you're right; I'll need to experiment with this some more. A lot more.

    """Anyhow, if Pythoneers really believed explicit was better than implicit, they'd all switch to Java."""

    Hm, I don't know about that. Java is verbose, but it does do a number of things implicitly that Python does not.

  3. creidiki said,

    February 7, 2008 @ 11:01 am

    Concisiveness(sp?) is one of the things lispy languages are simply not very good at.

    You just have to look at the (aborted) esh project - a system shell like bash, but with scheme syntax, or at the similar effort to make a system shell based on SBCL.

    Chicken's (grep) suffers from this, as well as its existing, and rather convoluted, scsh-derived 'awk' egg.

    I wish you good luck with it - i've been using chicken for all my "shell script" functionality for a bit, and I'd dearly love a concise replacement for awk or even just the inbuilt regex functions :)

RSS feed for comments on this post · TrackBack URI

Leave a Comment