スクリプトライブラリ

ML is a superb tool for scripting. In order to demonstrant this, SML# provides a sample scripting library consisting of (mostly imperative) functions for

  • interfacing with opetating system shell
  • basic IO, and
  • text formating

that allow you to write scripting code in an interactive session of SML#.

The features of SML#, including higher-order functions, pattern matching, and record polymorphism, makes it a particularly cool scripting language.

To use this library, simply open the library in the interactive session as:

# open Script;

and write an SML# code using the functions desribed in this API.

Scripting examples

The first is a one-liner that strips HTML tags off from a text read from the standard input.

app (print o (global_subst "<[^>]*>" "")) (readlines stdIn (SOME "\n"));

The next substitutes environment reference.

app
   (print
    o (global_replace "\\${?([a-zA-Z_]+)}?" (fn [_, name] => env name)))
   (readlines stdIn NONE)

Using this library, Unix commands can be implemented as follows.

grep command

val pattern = hd argv;
app
  (fn line => (if line =~ pattern then print line else ()))
  (readlines stdIn (SOME "\n"));

wc command.

val (ls, ws, cs) =
   foldl
       (fn (line, (ls, ws, cs)) =>
           (
             ls + 1,
             ws + length (tokens "[ \t]" line),
             cs + (size line)
           ))
       (0, 0, 0)
       (readlines stdIn (SOME "\n"));
print (itoa ls ^ " " ^ itoa ws ^ " " ^ itoa cs ^ "\n");

id command.

val user = case argv of [] => env "USER" | name :: _ => name;
case
  List.filter
      (fn entry => hd entry = user)
      (map (fields ":") (readlines (fopen "/etc/passwd" "r") (SOME "\n")))
 of [] => print ("not found: " ^ user)
  | [_ :: _ :: id :: gid :: _] => print ("uid=" ^ id ^ " gid=" ^ gid);

split command.

val (src, dest) = case argv of src :: dest :: _ => (src, dest);
val lines = 9; (* split into 10-line pieces. (not 9) *)
val count = ref 0;
fun destName () = dest ^ "." ^ itoa (!count) before count := !count + 1;
val (_, file) =
   foldl
   (fn (line, (ls, file)) =>
       (
         fputs file line;
         if 0 = ls
         then (fclose file; (lines, fopen (destName()) "w"))
         else (ls - 1, file)
       ))
   (lines, fopen (destName()) "w")
   (readlines (fopen src "r") (SOME "\n"));
fclose file;

which command.

structure P = OS.Path;
structure F = OS.FileSys;
exception Found of string
val cmd = case argv of name :: _ => name;
(
  app
      (fn dir =>
          let val path = P.concat (dir, cmd)
          in
            if F.access (path, [F.A_EXEC])
            then raise Found path
            else ()
          end handle SysErr _ => ())
      (fields ":" (env "PATH"));
  print "not found\n"
)
handle Found name => print name;
Last modified:2006/03/06 06:24:14
Keyword(s):
References:[ライブラリ]