For Development HEAD DRAFTSearch (procedure/syntax/module):

12.78 text.sh - Shell text utilities

Module: text.sh

This module provides several utilities useful when you’re writing shell-like scripts.

Function: shell-escape-string str :optional flavor

{text.sh} If str contains characters that affects shell’s command-line argument parsing, escape str to avoid shell’s interpretation. Otherwise, returns str itself.

The optional flavor argument takes a symbol to specify the platform; currently windows and posix can be specified. The way shell handles the escape and quotation differ a lot between these platforms; the windows flavor uses MSVC runtime argument parsing behavior, while the posix flavor assumes IEEE Std 1003.1. When omitted, the default value is chosen according to the running platform. (Note: Cygwin is regarded as posix.)

Use this procedure when you need to build a command-line string by yourself. (If you pass a command-line argument list, instead of a single command-line string, you don’t need to escape them since we bypass the shell.)

(NB: Use this with caution on Windows; if you run a batch file (*.bat or *.cmd), its command-line arguments are parsed differently, and it is known that there’s no safe escaping way that works for all the cases. It’s up to you to ensure all arugments are safe when you run those files. See also sys-exec (see Process management)).

Function: shell-tokenize-string str :optional flavor

{text.sh} Split a string str into arguments as the shell does.

(shell-tokenize-string "grep -n -e \"foo bar\" log")
 ⇒ ("grep" "-n" "-e" "foo bar" "log")

The optional flavor arguments can be a symbol either windows or posix to specify the syntax. If it’s windows, we follow MSVC runtime command-line argument parser behavior. If it’s posix, we follow IEEE Std 1003.1 Shell Command Language. When omitted, the default value is chosen according to the running platform. (Note: Cygwin is regarded as posix.)

This procedure does not handle fancier shell features such as variable substitution. If it encounters a metacharacter that requires such interpretation, an error is signaled. In other words, metacharacters must be properly quoted in str.

(shell-tokenize-string "echo $foo" 'posix)
  ⇒ signals error

(shell-tokenize-string "echo \"$foo\"" 'posix)
  ⇒ still signals error

(shell-tokenize-string "echo '$foo'" 'posix)
  ⇒ ("echo" "$foo")

(shell-tokenize-string "echo \\$foo" 'posix)
  ⇒ ("echo" "$foo")
Macro: shell-case expr clause …

{text.sh} This macro implements shell’s case built-in command. Each clause must be one fo the following forms:

  • (pattern body …)
  • ((pattern …) body …)
  • (else body …)

The else form must appear as the last clause, if there’s any.

First, expr is evaluated. It must produce a string. Then, each clause is examined, and the value of expr matches one of the patterns, then body … of the clause is evaluated, and the last result is returned.

When none of clause has matching pattern, if else clause is provided its body … is evaluated, otherwise an undefined value is returned.

The matching is done as glob (see Directories) does. That is, if a pattern is "abc*", then the value "abc", "abcd", "abccc", etc. match, and if a pattern is "a[bcd]", then the value "ab", "ac" and "ad" match.

For example, the following shell case command:

case $arg in
  foo*)        process_foo $arg;;
  ba[rz]|quux) process_bar $arg;;
   *)          process_other $arg;;
esac

can be translated as follows:

(shell-case arg
  ["foo*" (process-foo arg)]
  [("ba[rz]" "quux")  (process-bar arg)]
  [else (process-other arg)])

The same thing can be achieved with rxmatch-case, for example, but manually translating shell glob pattern to regexp can be tedious and error-prone. This is particulary useful when you’re rewriting existing shell scripts in Gauche.

Function: shell-match pattern str

{text.sh} This extract the matching function of shell-case to be used independently. The pattern argument must be a glob pattern string, or a list of glob pattern strings. The str argument must be a string.

If the value of str matches pattern (or one of patterns in the second form), it returns #t. Otherwise, it returns #f.



For Development HEAD DRAFTSearch (procedure/syntax/module):
DRAFT