[ < ] | [ > ] |  | [ << ] | [ Up ] | [ >> ] |  |  |  |  | [Top] | [Contents] | [Index] | [ ? ]

# 13. Macros for running shell commands

There are a few builtin macros in `m4` that allow you to run shell commands from within `m4`.

Note that the definition of a valid shell command is system dependent. On UNIX systems, this is the typical `/bin/sh`. But on other systems, such as native Windows, the shell has a different syntax of commands that it understands. Some examples in this chapter assume `/bin/sh`, and also demonstrate how to quit early with a known exit value if this is not the case.

[ < ] | [ > ] |  | [ << ] | [ Up ] | [ >> ] |  |  |  |  | [Top] | [Contents] | [Index] | [ ? ]

## 13.1 Determining the platform

Sometimes it is desirable for an input file to know which platform `m4` is running on. GNU `m4` provides several macros that are predefined to expand to the empty string; checking for their existence will confirm platform details.

Optional builtin: __gnu__
Optional builtin: __os2__
Optional builtin: os2
Optional builtin: __unix__
Optional builtin: unix
Optional builtin: __windows__
Optional builtin: windows

  Each of these macros is conditionally defined as needed to describe the environment of `m4`. If defined, each macro expands to the empty string.

When GNU extensions are in effect (that is, when you did not use the ``-G'` option, see section Invoking m4), GNU `m4` will define the macro `__gnu__` to expand to the empty string.

    __gnu__
    ⇒
    ifdef(`__gnu__', `Extensions are active')
    ⇒Extensions are active

On UNIX systems, GNU `m4` will define `__unix__` by default, or `unix` when the ``-G'` option is specified.

On native Windows systems, GNU `m4` will define `__windows__` by default, or `windows` when the ``-G'` option is specified.

On OS/2 systems, GNU `m4` will define `__os2__` by default, or `os2` when the ``-G'` option is specified.

If GNU `m4` does not provide a platform macro for your system, please report that as a bug.

    define(`provided', `0')
    ⇒
    ifdef(`__unix__', `define(`provided', incr(provided))')
    ⇒
    ifdef(`__windows__', `define(`provided', incr(provided))')
    ⇒
    ifdef(`__os2__', `define(`provided', incr(provided))')
    ⇒
    provided
    ⇒1

[ < ] | [ > ] |  | [ << ] | [ Up ] | [ >> ] |  |  |  |  | [Top] | [Contents] | [Index] | [ ? ]

## 13.2 Executing simple commands

Any shell command can be executed, using `syscmd`:

Builtin: syscmd (shell-command)

  Executes shell-command as a shell command.

  The expansion of `syscmd` is void, not the output from shell-command! Output or error messages from shell-command are not read by `m4`. See section Reading the output of commands, if you need to process the command output.

  Prior to executing the command, `m4` flushes its buffers. The default standard input, output and error of shell-command are the same as those of `m4`.

  The macro `syscmd` is recognized only with parameters.

    define(`foo', `FOO')
    ⇒
    syscmd(`echo foo')
    ⇒foo
    ⇒

Note how the expansion of `syscmd` keeps the trailing newline of the command, as well as using the newline that appeared after the macro.

As an example of shell-command using the same standard input as `m4`, the command line `echo "m4wrap(\`syscmd(\`cat')')" | m4` will tell `m4` to read all of its input before executing the wrapped text, then hand a valid (albeit emptied) pipe as standard input for the `cat` subcommand. Therefore, you should be careful when using standard input (either by specifying no files, or by passing ``-'` as a file name on the command line, see section Invoking m4), and also invoking subcommands via `syscmd` or `esyscmd` that consume data from standard input. When standard input is a seekable file, the subprocess will pick up with the next character not yet processed by `m4`; when it is a pipe or other non-seekable file, there is no guarantee how much data will already be buffered by `m4` and thus unavailable to the child.

[ < ] | [ > ] |  | [ << ] | [ Up ] | [ >> ] |  |  |  |  | [Top] | [Contents] | [Index] | [ ? ]

## 13.3 Reading the output of commands

If you want `m4` to read the output of a shell command, use `esyscmd`:

Builtin: esyscmd (shell-command)

  Expands to the standard output of the shell command shell-command.

  Prior to executing the command, `m4` flushes its buffers. The default standard input and standard error of shell-command are the same as those of `m4`. The error output of shell-command is not a part of the expansion: it will appear along with the error output of `m4`.

  The macro `esyscmd` is recognized only with parameters.

    define(`foo', `FOO')
    ⇒
    esyscmd(`echo foo')
    ⇒FOO
    ⇒

Note how the expansion of `esyscmd` keeps the trailing newline of the command, as well as using the newline that appeared after the macro.

Just as with `syscmd`, care must be exercised when sharing standard input between `m4` and the child process of `esyscmd`.

[ < ] | [ > ] |  | [ << ] | [ Up ] | [ >> ] |  |  |  |  | [Top] | [Contents] | [Index] | [ ? ]

## 13.4 Exit status

To see whether a shell command succeeded, use `sysval`:

Builtin: sysval

  Expands to the exit status of the last shell command run with `syscmd` or `esyscmd`. Expands to 0 if no command has been run yet.

    syscmd(`false')
    ⇒
    ifelse(sysval, `0', `zero', `non-zero')
    ⇒non-zero
    syscmd(`exit 2')
    ⇒
    sysval
    ⇒2
    syscmd(`true')
    ⇒
    sysval
    ⇒0
    esyscmd(`false')
    ⇒
    ifelse(sysval, `0', `zero', `non-zero')
    ⇒non-zero
    esyscmd(`exit 2')
    ⇒
    sysval
    ⇒2
    esyscmd(`true')
    ⇒
    sysval
    ⇒0

`sysval` results in 127 if there was a problem executing the command, for example, if the system-imposed argument length is exceeded, or if there were not enough resources to fork. It is not possible to distinguish between failed execution and successful execution that had an exit status of 127.

On UNIX platforms, where it is possible to detect when command execution is terminated by a signal, rather than a normal exit, the result is the signal number shifted left by eight bits.

    dnl This test assumes kill is a shell builtin, and that signals are
    dnl recognizable.
    ifdef(`__unix__', ,
          `errprint(` skipping: syscmd does not have unix semantics
    ')m4exit(`77')')dnl
    syscmd(`kill -13 $$')
    ⇒
    sysval
    ⇒3328
    esyscmd(`kill -9 $$')
    ⇒
    sysval
    ⇒2304

[ < ] | [ > ] |  | [ << ] | [ Up ] | [ >> ] |  |  |  |  | [Top] | [Contents] | [Index] | [ ? ]

## 13.5 Making temporary files

Commands specified to `syscmd` or `esyscmd` might need a temporary file, for output or for some other purpose. There is a builtin macro, `mkstemp`, for making a temporary file:

Builtin: mkstemp (template)
Builtin: maketemp (template)

  Expands to a name of a new, empty file, made from the string template, which should end with the string ``XXXXXX'`. The six ``X'` characters are then replaced with random characters matching the regular expression ``[a-zA-Z0-9._-]'`, in order to make the file name unique. If fewer than six ``X'` characters are found at the end of `template`, the result will be longer than the template. The created file will have access permissions as if by `chmod =rw,go=`, meaning that the current umask of the `m4` process is taken into account, and at most only the current user can read and write the file.

  The traditional behavior, standardized by POSIX, is that `maketemp` merely replaces the trailing ``X'` with the process id, without creating a file, and without ensuring that the resulting string is a unique file name. In part, this means that using the same template twice in the same input file will result in the same expansion. This behavior is a security hole, as it is very easy for another process to guess the name that will be generated, and thus interfere with a subsequent use of `syscmd` trying to manipulate that file name. Hence, POSIX has recommended that all new implementations of `m4` provide the secure `mkstemp` builtin, and that users of `m4` check for its existence.

  The macros `mkstemp` and `maketemp` are recognized only with parameters.

If you try this next example, you will most likely get different output for the two file names, since the replacement characters are randomly chosen:

    maketemp(`/tmp/fooXXXXXX')
    ⇒/tmp/fooa07346
    ifdef(`mkstemp', `define(`maketemp', defn(`mkstemp'))',
          `define(`mkstemp', defn(`maketemp'))dnl
    errprint(`warning: potentially insecure maketemp implementation
    ')')
    ⇒
    mkstemp(`doc')
    ⇒docQv83Uw

Unless you use the ``--traditional'` command line option (or ``-G'`, see section Invoking m4), the GNU version of `maketemp` is secure. This means that using the same template to multiple calls will generate multiple files. However, we recommend that you use the new `mkstemp` macro, introduced in GNU M4 1.4.8, which is secure even in traditional mode.

    syscmd(`echo foo??????')dnl
    ⇒foo??????
    define(`file1', maketemp(`fooXXXXXX'))dnl
    ifelse(esyscmd(`echo foo??????'), `foo??????', `no file', `created')
    ⇒created
    define(`file2', maketemp(`fooXX'))dnl
    define(`file3', mkstemp(`fooXXXXXX'))dnl
    ifelse(len(file1), len(file2), `same length', `different')
    ⇒same length
    ifelse(file1, file2, `same', `different file')
    ⇒different file
    ifelse(file2, file3, `same', `different file')
    ⇒different file
    ifelse(file1, file3, `same', `different file')
    ⇒different file
    syscmd(`rm 'file1 file2 file3)
    ⇒
    sysval
    ⇒0

[ << ] | [ >> ] |  |  |  |  |  | [Top] | [Contents] | [Index] | [ ? ]

This document was generated by root on April, 16 2008 using texi2html 1.76.