Shell commands

Jump to: | ‍ ‍ | OMake Home • Guide Home • Guide (single-page) • Contents (short) • Contents (long)
Index: | ‍ ‍ | All • Variables • Functions • Objects • Targets • Options

# Chapter ‍11 Shell commands

- What is considered a shell command?
- Simple commands
- Globbing
- Background jobs
- Command sequence
- File redirection
- Pipelines
- Conditional execution
- Grouping
- Basic builtin functions
- Job control builtin functions
- Command history

## 11.1 What is considered a shell command?

Syntactically, shell commands are any line starting with

- The name of an executable, which is looked up along `PATH[]` if it is not specified with a relative or an absolute path,
- A builtin, or
- An alias (see the documentation for the `Shell` object for more information),

but not one of the following:

- A variable definition of the form `VAR=string`,
- A function call `f(...)` or method call `o.f(...)`,
- A rule definition containing a colon `string: ...`, or
- A special command, including the following:
  - `if ...`
  - `switch ...`
  - `match ...`
  - `section ...`
  - `return ...`

The syntax of shell commands is similar but not identical to the syntax used by the Un*x-shell ‍bash(1).

Note: The syntax and shell usage is identical on all platforms, including Win32. To avoid portability problems on Win32, it is recommended to avoid the use of the native shell interpreter ‍cmd(1).

Commands can be freely mixed with other code, for example

        LIB = $(dir lib)
        println(The contents of the $(LIB) directory is:)
        ls $(LIB)

Every command has an integer exit code, which is zero or some other integer. A command is said to succeed if its exit code is zero. If a command terminates with a non-zero exit code, osh(1) considers the execution to have failed and tells OMake to abort the current process with an error.

## 11.2 Simple commands

A simple command is specified with the name of an executable optionally followed by arguments passed to this executable. Here are some examples:

        ls
        ls -AF .
        echo Hello world
        /usr/local/bin/cc --version

The command is found using the current search path in the variable ‍`PATH[]`, which should define an array of directories containing the favored executables.

A command may be prefixed by environment variable definitions with the help of the utility ‍env(1).

        # Prints "Hello world"
        env X="Hello world" Y=2 printenv X

        # Pass the include path to the Visual C++
        env include="c:\Program Files\Microsoft SDK\include" cl foo.cpp

## 11.3 Globbing

Commands may contain wildcard patterns. A pattern specifies a set of files through a limited kind of regular expression. Patterns are expanded before the function is executed.

       # List all files with a .c suffix
       ls *.c

       # List all files with a single character prefix, and .c suffix
       ls ?.c

       # Rename the file hello.ml to foo.ml
       mv {hello,foo}.ml

A comprehensive description of OMake ‍glob patterns is given in Section ‍10.4.

## 11.4 Background jobs

A command may also be placed in the background by adding an ampersand ‍(`&`) after the command. Control immediately returns to the shell without waiting for the job to complete. The job continues to run in the background.

        gcc -o hugeprogram *.c &

In osh(1) the ampersand acts command terminator, whereas for bash(1) it is a command separator.

See Section ‍11.11 for some built-in job-control commands.

## 11.5 Command sequence

Sequence commands by separating them with a semi-colon ‍(`;`). The commands get executed from left to right. The exit code of the whole sequence is the exit code of the last command executed. The exit codes of all other commands are ignored.

Notes:

- In osh(1) the semicolon strictly acts as a separator.
- Each command in a sequence is executed in its own sub-shell.
- The property of ignoring all but the last command’s exit code can be used to simulate GNU ‍Make’s `-`‍command-prefix in recipes.

      # GNU Make: ignore exit code of toposort
      tsort:
              - toposort --in-place ids.list

  becomes

      # OMake
      tsort:
              toposort --in-place ids.list; true

## 11.6 File redirection

The input and the output of a command can be redirected from and to files by adding redirection operators after the command.

Redirect input
  command `<` input-file.
Redirect output
  command `>` output-file, command `>>` output-file. The first form truncates output-file, the second form appends to it.
Redirect output and error messages
  command `>&` output-file, command `>>&` output-file. Again, the first form truncates output-file and the second form appends to it.

Some examples:

        # Write to the "foo" file
        echo Hello world > foo

        # Redirect input from the foo file
        cat < foo

        # Redirect standard output and errors to the foo file
        gcc -o boo *.c >& foo

## 11.7 Pipelines

Pipelines are sequences of commands, where the output of the command on the left-hand side of the pipe ‍operator (`|` and `|&`) is sent to the input of the command on the right-hand side. With `|` the output is redirected, but errors are not; with `|&` both output and errors are redirected. Each command in a pipeline is executed in its own sub-shell.

       # Send the output of the ls command to the printer
       ls *.c | lpr

       # Send output and errors to jyh as email
       gcc -o hugefile *.c |& mail jyh

The pipeline’s exit code is the value of the rightmost command to exit with a non-zero code, or zero if all commands exit successfully. Note that this behavior is different from ordinary command sequences (see Section ‍11.5) and from most other Un*x ‍shells (those which supply `pipefail` set it to `false` by default), but desirable inside OMake ‍recipes.

## 11.8 Conditional execution

Commands may also be composed though conditional evaluation using the `||` and `&&` syntax. The expression `command1 && command2` executes `command2` only if `command1` succeeds. The expression `command1 || command2` executes `command2` only if `command1` fails.

       # Display the x/y file if possible
       cd x && cat y

       # Run foo.exe, or print an error message
       (test -x foo.exe && foo.exe) || echo "foo.exe is not executable"

## 11.9 Grouping

Parenthesis are used for grouping in a pipeline or conditional command. The grouped commands are executed in a separate sub-shell.

In the following expression, the `test`‍function is used to test whether the `foo.exe` file is executable. If it is, the `foo.exe` file is executed. If the file is not executable (or if the `foo.exe` command fails), the message `"foo.exe is not executable"` is printed.

       # Run foo.exe, or print an error message
       (test -x foo.exe && foo.exe) || echo "foo.exe is not executable"

Currently osh(1) does not support grouping within the current shell as does Bash with curly braces ‍(`{}`).

## 11.10 Basic builtin functions

### 11.10.1 echo

The `echo` function prints a string.

    $(echo <args>)
    echo <args>

### 11.10.2 cd

The `cd` function changes the current directory.

        cd(dir)
           dir : Dir

The `cd` function also supports a 2-argument form:

        $(cd dir, e)
           dir : Dir
           e : expression

In the two-argument form, expression `e` is evaluated in the directory `dir`. The current directory is not changed otherwise.

The behavior of the `cd` function can be changed with the `CDPATH` variable, which specifies a search path for directories. This is normally useful only in the osh command interpreter.

        CDPATH : Dir Sequence

For example, the following will change directory to the first directory `./foo`, `~/dir1/foo`, `~/dir2/foo`.

        CDPATH[] =
           .
           $(HOME)/dir1
           $(HOME)/dir2
        cd foo

## 11.11 Job control builtin functions

### 11.11.1 jobs

The `jobs` function prints a list of jobs.

`jobs`

### 11.11.2 bg

The `bg` function places a job in the background.

`bg <pid...>`

### 11.11.3 fg

The `fg` function brings a job to the foreground.

`fg <pid...>`

### 11.11.4 stop

The `stop` function suspends a job.

`stop <pid...>`

### 11.11.5 wait

The `wait` function waits for a job to finish. If no process identifiers are given, the shell waits for all jobs to complete.

`wait <pid...>`

### 11.11.6 kill

The `kill` function signals a job.

`kill [signal] <pid...>`

## 11.12 Command history

### 11.12.1 history

        $(history-index) : Int
        $(history) : String Sequence
        history-file : File
        history-length : Int

The history variables manage the command-line history in osh. They have no effect in omake.

The `history-index` variable is the current index into the command-line history. The `history` variable is the current command-line history.

The `history-file` variable can be redefined if you want the command-line history to be saved. The default value is `~/.omake/osh_history`.

The `history-length` variable can be redefined to specify the maximum number of lines in the history that you want saved. The default value is `100`.

Jump to: | ‍ ‍ | OMake Home • Guide Home • Guide (single-page) • Contents (short) • Contents (long)
Index: | ‍ ‍ | All • Variables • Functions • Objects • Targets • Options