Lupo LeBoucher <ix@io.com> wrote:
+---------------
| Um, yeah; in an ideal world, someone would take CPAN and shoe-horn it into
| CMU-CL (or even just shoe-horn the basic functionality of Perl itself
| into Lisp, like Graham is trying to do with Arc), and that could make a
| Lisp which is far more handy for "glue" code than Perl is, but nobody has
| done that, so we're stuck with shitty scripting languages for day to day
| work, or reimplementing language A in language B.
+---------------
Well, just because CL isn't *perfect* for scripting doesn't mean it's
not awfully darned useful!! I use CMUCL for scripting lots of stuff.
Some recent examples:
"date-nist" -- fetches the current time from (one or more of)
the NIST time server(s). The heart of it is this function:
(defun fetch-time/rfc868 (host)
(let* ((fd (connect-to-inet-socket host 37))
(stream (system:make-fd-stream
fd
:element-type '(unsigned-byte 8)
:buffering :none)))
(with-open-stream (s stream)
(loop repeat 4 ; [Thanks, Erik!]
for time = (read-byte s)
then (+ (read-byte s) (* time 256))
finally (return time)))))
"csv_to_html" -- Convert a CSV (Comma-Separated Variables) file into
an HTML table. The heart of it is this function:
;;; PARSE-CSV-LINE -- Parse one CSV line into a list of fields,
;;; stripping quotes and field-internal escape characters.
;;; Lexical states: NORMAL QUOTED ESCAPED QUOTED+ESCAPED
;;;
(defun parse-csv-line (line)
(when (or (string= line "") ; special-case blank lines
(char= #\# (char line 0))) ; or those starting with "#"
(return-from parse-csv-line '()))
(loop for c across line
with state = 'normal
and results = '()
and chars = '() do
(ecase state
((normal)
(case c
((#\") (setq state 'quoted))
((#\\) (setq state 'escaped))
((#\,)
(push (coerce (nreverse chars) 'string) results)
(setq chars '()))
(t (push c chars))))
((quoted)
(case c
((#\") (setq state 'normal))
((#\\) (setq state 'quoted+escaped))
(t (push c chars))))
((escaped) (push c chars) (setq state 'normal))
((quoted+escaped) (push c chars) (setq state 'quoted)))
finally
(progn
;; close still-open field
(push (coerce (nreverse chars) 'string) results)
(return (nreverse results)))))
"keto" -- Given a number of grams of protein, carbohydrate, and fat,
show the total number of calories and the "ketogenic ratio" [useful
to those on low-carb diets]:
% cat ~/bin/keto
#!/usr/local/bin/cmucl -script
(cond
((= 3 (length *script-args*))
(destructuring-bind (p c f)
(mapcar #'read-from-string *script-args*)
(format t "grams: protein ~a carb ~a fat ~a~%" p c f)
(format t "ketogenic ratio: ~a~%"
(/ (+ (* 0.9 f) (* 0.46 p))
(+ (* 1.0 c) (* 0.1 f) (* 0.58 p))))
(format t "total calories: ~a~%"
(+ (* 4 p) (* 4 c) (* 9 f)))))
(t
(format t "usage: ~a <protein> <carb> <fat>~%" *script-name*)
(format t "(enter all amounts in grams)~%")
(quit 1)))
% keto.cl 8 6 17
grams: protein 8 carb 6 fat 17
ketogenic ratio: 1.5380875
total calories: 209
%
"sum-time-user-sys" -- Do some trivial processing on the output of the
"time" builtin command in "csh". [Shown in a previous post today.]
"random" -- Generate random strings which are legal as URLs, filenames,
and passwords on most systems, thus shell and URL metacharacters
must be excluded. Takes the time of day plus a number of bytes from
"/dev/urandom" and uses it to seed the CMUCL MT19937 random number
generator, then crank that some number of times and encode the output
into acceptable text [6 bits per character] of the desired length
[default 16]:
% random
WhiTrVcHUQw8XavI
% random 64
BbnmXL4Jk_j_2kFF@8R4nYbiqtH@esAY0z2FbDugx3yRKRp_aetqNzbh6EtoUG2w
% repeat 3 random
z0P0xuFm6rKBosee
W0d_BWBiVZIkQvg2
LJUHkFRrhfictQRv
% repeat 5 random 8
kPIbakFj
6T0KvOB4
2GINrD3S
D39TQIV3
1vjJ8KzQ
%
"wild" -- Construct more complex wild-card command than are natively
convenient in Unix shell, e.g., the sort of thing TOPS-10 used to
let you do, stuff like "ren *.foo *.bar" [which does *not* do the
same thing at all in Unix!!]. It's just a loop around CL's DIRECTORY
and TRANSLATE-PATHNAME and a FORMAT to print it all. It doesn't do
the commands itself, it just outputs them, but if you like what you
see then, you can repeat it and pipe the output to "/bin/sh -x" to
execute them (the "-x" lets you see what's going on). Example:
% ls -l foo1*
-rwxr-xr-x 1 rpw3 rpw3 2099 Feb 6 03:52 foo1
-rw-r--r-- 1 rpw3 rpw3 223 Feb 6 03:48 foo1.lisp
-rw-r--r-- 1 rpw3 rpw3 882 Feb 6 03:52 foo1.x86f
% wild
usage: wild command pattern [ repl-patterns... ]
% wild mv foo1\* bar2\*
mv foo1 bar2
mv foo1.lisp bar2.lisp
mv foo1.x86f bar2.x86f
% !! | sh -x
wild mv foo1\* bar2\* | sh -x
+ mv foo1 bar2
+ mv foo1.lisp bar2.lisp
+ mv foo1.x86f bar2.x86f
% ls -l bar2*
-rwxr-xr-x 1 rpw3 rpw3 2099 Feb 6 03:52 bar2
-rw-r--r-- 1 rpw3 rpw3 223 Feb 6 03:48 bar2.lisp
-rw-r--r-- 1 rpw3 rpw3 882 Feb 6 03:52 bar2.x86f
%
Lest I bore people [if I haven't already!], I'll stop there. But suffice
it to say that the more I use CL and become familiar with various nuances,
the more I use it *instead* of scripts in "sh" or Perl (as well as in
conjunction with them).
-Rob
-----
Rob Warnock <rpw3@rpw3.org>
627 26th Avenue <URL:http://rpw3.org/>
San Mateo, CA 94403 (650)572-2607