Next: , Up: Programming in M4sh


9.1 Common Shell Constructs

M4sh provides portable alternatives for some common shell constructs that unfortunately are not portable in practice.

— Macro: AS_BOX (text, [char = ‘-])

Expand into shell code that will output text surrounded by a box with char in the top and bottom border. text should not contain a newline, but may contain shell expansions valid for unquoted here-documents. char defaults to ‘-’, but can be any character except ‘/’, ‘'’, ‘"’, ‘\’, ‘&’, or ‘`’. This is useful for outputting a comment box into log files to separate distinct phases of script operation.

— Macro: AS_CASE (word, [pattern1], [if-matched1], ..., [default])

Expand into a shell ‘case’ statement, where word is matched against one or more patterns. if-matched is run if the corresponding pattern matched word, else default is run. Avoids several portability issues (see Limitations of Shell Builtins).

— Macro: AS_DIRNAME (file-name)

Output the directory portion of file-name. For example, if $file is ‘/one/two/three’, the command dir=`AS_DIRNAME(["$file"])` sets dir to ‘/one/two’.

This interface may be improved in the future to avoid forks and losing trailing newlines.

— Macro: AS_ECHO (word)

Emits word to the standard output, followed by a newline. word must be a single shell word (typically a quoted string). The bytes of word are output as-is, even if it starts with "-" or contains "\". Redirections can be placed outside the macro invocation. This is much more portable than using echo (see Limitations of Shell Builtins).

— Macro: AS_ECHO_N (word)

Emits word to the standard output, without a following newline. word must be a single shell word (typically a quoted string) and, for portability, should not include more than one newline. The bytes of word are output as-is, even if it starts with "-" or contains "\". Redirections can be placed outside the macro invocation.

— Macro: AS_ESCAPE (string, [chars = ‘`\"$])

Expands to string, with any characters in chars escaped with a backslash (‘\’). chars should be at most four bytes long, and only contain characters from the set ‘`\"$’; however, characters may be safely listed more than once in chars for the sake of syntax highlighting editors. The current implementation expands string after adding escapes; if string contains macro calls that in turn expand to text needing shell quoting, you can use AS_ESCAPE(m4_dquote(m4_expand([string]))).

The default for chars (‘\"$`’) is the set of characters needing escapes when string will be used literally within double quotes. One common variant is the set of characters to protect when string will be used literally within back-ticks or an unquoted here-document (‘\$`’). Another common variant is ‘""’, which can be used to form a double-quoted string containing the same expansions that would have occurred if string were expanded in an unquoted here-document; however, when using this variant, care must be taken that string does not use double quotes within complex variable expansions (such as ‘${foo-`echo "hi"`}’) that would be broken with improper escapes.

This macro is often used with AS_ECHO. For an example, observe the output generated by the shell code generated from this snippet:

          foo=bar
          AS_ECHO(["AS_ESCAPE(["$foo" = ])AS_ESCAPE(["$foo"], [""])"])
          ⇒"$foo" = "bar"
          m4_define([macro], [a, [\b]])
          AS_ECHO(["AS_ESCAPE([[macro]])"])
          ⇒macro
          AS_ECHO(["AS_ESCAPE([macro])"])
          ⇒a, b
          AS_ECHO(["AS_ESCAPE(m4_dquote(m4_expand([macro])))"])
          ⇒a, \b

To escape a string that will be placed within single quotes, use:

          m4_bpatsubst([[string]], ['], ['\\''])
— Macro: AS_EXIT ([status = ‘$?])

Emit code to exit the shell with status, defaulting to ‘$?’. This macro works around shells that see the exit status of the command prior to exit inside a ‘trap 0’ handler (see Limitations of Shell Builtins).

— Macro: AS_IF (test1, [run-if-true1], ..., [run-if-false])

Run shell code test1. If test1 exits with a zero status then run shell code run-if-true1, else examine further tests. If no test exits with a zero status, run shell code run-if-false, with simplifications if either run-if-true1 or run-if-false is empty. For example,

          AS_IF([test "x$foo" = xyes], [HANDLE_FOO([yes])],
                [test "x$foo" != xno], [HANDLE_FOO([maybe])],
                [echo foo not specified])

ensures any required macros of HANDLE_FOO are expanded before the first test.

— Macro: AS_MKDIR_P (file-name)

Make the directory file-name, including intervening directories as necessary. This is equivalent to ‘mkdir -p -- file-name’, except that it is portable to older versions of mkdir that lack support for the -p option or for the -- delimiter (see Limitations of Usual Tools). Also, AS_MKDIR_P succeeds if file-name is a symbolic link to an existing directory, even though Posix is unclear whether ‘mkdir -p’ should succeed in that case. If creation of file-name fails, exit the script.

Also see the AC_PROG_MKDIR_P macro (see Particular Programs).

— Macro: AS_SET_STATUS (status)

Emit shell code to set the value of ‘$?’ to status, as efficiently as possible. However, this is not guaranteed to abort a shell running with set -e (see Limitations of Shell Builtins). This should also be used at the end of a complex shell function instead of ‘return’ (see Shell Functions) to avoid a DJGPP shell bug.

— Macro: AS_TR_CPP (expression)

Transform expression into a valid right-hand side for a C #define. For example:

          # This outputs "#define HAVE_CHAR_P 1".
          # Notice the m4 quoting around #, to prevent an m4 comment
          type="char *"
          echo "[#]define AS_TR_CPP([HAVE_$type]) 1"
— Macro: AS_TR_SH (expression)

Transform expression into shell code that generates a valid shell variable name. The result is literal when possible at m4 time, but must be used with eval if expression causes shell indirections. For example:

          # This outputs "Have it!".
          header="sys/some file.h"
          eval AS_TR_SH([HAVE_$header])=yes
          if test "x$HAVE_sys_some_file_h" = xyes; then echo "Have it!"; fi
— Macro: AS_SET_CATFILE (var, dir, file)

Set the polymorphic shell variable var to dir/file, but optimizing the common cases (dir or file is ‘.’, file is absolute, etc.).

— Macro: AS_UNSET (var)

Unsets the shell variable var, working around bugs in older shells (see Limitations of Shell Builtins). var can be a literal or indirect variable name.

— Macro: AS_VERSION_COMPARE (version-1, version-2, [action-if-less], [action-if-equal], [action-if-greater])

Compare two strings version-1 and version-2, possibly containing shell variables, as version strings, and expand action-if-less, action-if-equal, or action-if-greater depending upon the result. The algorithm to compare is similar to the one used by strverscmp in glibc (see String/Array Comparison).