Shell Command Support

The :std/cli/shell library provides facilities for working with Unix shell code

usage

(import :std/cli/shell)

An earlier version of this library used to be available as :clan/shell in gerbil-utils.

Interface

easy-shell-character?

(easy-shell-character? character) => bool

Returns true if the character if a string may contain the character in any position without that this fact requiring the string to be quoted in any shell. This include alphanumeric characters and those in "@%-_=+:,./" (not including the double quotes).

All other ASCII characters may require the string to be quoted. For good measure we also quote strings containing non-ASCII characters.

Examples:

> (string-for-each (lambda (c) (or (easy-shell-character? c) (error "foo")))
    "abcdefghijklmnopqrstuvwxzABCDEFGHIJKLMNOPQRSTUVWXZ012345678@%-_=+:,./") ;; no error
> (string-for-each (lambda (c) (or (not (easy-shell-character? c)) (error "foo")))
    "!`~#$^&*()[{]}\\|;'\"<>? \r\n\t\v") ;; no error either

needs-shell-escape?

(needs-shell-escape? string) => bool

Returns true if the string is known not to require quoting in a Unix shell.

The current implementation only trusts strings where every character satisfies easy-shell-character? to not require quoting.

Examples:

> (map needs-shell-escape ["foo?" "~user" "$1" "*.*" "!1" "ab\\cd" "{}" "a;b" "&amp;" "|" "a b  c"])
(#t #t #t #t #t #t #t #t #t #t #t)
> (map needs-shell-escape ["foo" "%-_=+:,./" "1" "..." "abcd" "x=y:z,t.z/u+v_w"])
(#f #f #f #f #f #f)

escape-shell-token

(escape-shell-token string) => shell-escaped-string

Given a string, returns a shell-escaped-string that, when included in a Unix shell command, will expand into the input string.

Examples:

> (map escape-shell-token ["foo?" "~user" "$1" "*.*" "!1" "ab\\cd" "{}" "a;b" "&amp;" "|" "a b  c"])
("\"foo?\"" "\"~user\"" "\"\\$1\"" "\"*.*\"" "\"!1\"" "\"ab\\\\cd\"" "\"{}\"" "\"a;b\"" "\"&amp;\"" "\"|\"" "\"a b  c\"")
> (let (l ["foo" "%-_=+:,./" "1" "..." "abcd" "x=y:z,t.z/u+v_w"])
    (equal? l (map escape-shell-token l)))
#t

->envvar

(->envvar . str) => environment-variable-name

Given a list of arguments str, return a string to be used as a shell environment variable name following the convention of having only upper-case ASCII letters and digits and underscores.

The arguments are passed to as-string then uppercased, and any non-empty sequence of characters other than letters and digits are replaced by a single underscore.

Examples:

> (->envvar "foo")
"FOO"
> (->envvar "bar baz")
"BAR_BAZ"
> (->envvar '("bar " "+!@#$") #(#\@ #\! "#") "baz")
"BAR_BAZ"