This section describes how commands are executed.

Execution of simple commands

A simple command is executed as follows:

  1. All tokens in the simple command are expanded except for assignment and redirection tokens. If an error occurs during expansion, the execution of the simple command is aborted with a non-zero exit status.
    In the following steps, the first word of the expansion results is referred to as command name, and the other words as command arguments. If there is only one word of the expansion results, there are no command argument words. If there are none of the expansion results, there is no command name either.

  2. If the command name exists and there are any redirections specified in the command, they are processed. The word token after each redirection operator is expanded. If an error occurs during processing the redirections (including when expanding the word token), the execution of this simple command is aborted with a non-zero exit status.

    Note
    In other shells, redirections may be processed in a different step: POSIX does not specify the order in which redirections and assignments are processed when there is no command name or the name denotes a special built-in.
  3. Assignments specified in the command, if any, are processed. For each assignment token, the value is expanded and assigned to the specified variable. If an error occurs during assignments (including when expanding the values to be assigned), the execution of this simple command is aborted with a non-zero exit status.

    • If there is no command name or the name denotes a special built-in, the assignments are permanent: the assigned values remain after the command has finished (until the variable is reassigned).

    • Otherwise, the assignments are temporary: the assigned values only last during the execution of this simple command.

    The assigned variables are automatically exported when the command name is specified or the all-export option is enabled.

    Note
    In other shells, assignments may behave differently: For special built-ins and functions, assigned variables may not be exported. For functions, assigned variables may be persistent, that is, may remain even after the execution of the simple command.
  4. If there is no command name, the redirections are processed in a subshell, then the command execution ends. If an error occurs in the redirections, the exit status of the simple command is non-zero. If there were any command substitutions performed in the assignments, the exit status of the simple command is that of the last executed command substitution. Otherwise, the exit status is zero.

  5. A command to be executed is determined using the command search algorithm and the command is executed.

    • If the command is an external command, the command is executed by creating a new subshell and calling the “exec” system call in the subshell. The command name and arguments are passed to the executed command. Exported variables are passed to the executed command as environment variables.

    • If the command is a built-in, the built-in is executed with the command arguments passed to the built-in. As an exception, in the POSIXly-correct mode, the built-in is not executed if it is an elective built-in.

    • If the command is a function, the contents of the function are executed with the command arguments as function arguments.

    If the command was executed, the exit status of this simple command is that of the executed command. If the algorithm failed to determine a command, no command is executed and the exit status is 127. If the shell failed to execute the determined command, the exit status is 126. If the executed command was killed by a signal, the exit status is the signal number plus 384. If the elective built-in was not executed in the POSIXly-correct mode, the exit status is 127.

    Note
    In shells other than yash, the exit status may be different when the command was killed by a signal, because the POSIX standard only requires that the exit status be "greater than 128."

    If the shell is not in the POSIXly-correct mode and the algorithm failed to determine a command, the command eval -i -- "${COMMAND_NOT_FOUND_HANDLER-}" is evaluated. During the command execution, positional parameters are temporarily set to the command name and arguments that resulted in the first step. Any local variables defined during the execution are removed when the execution is finished. The HANDLED local variable is automatically defined with the initial value being the empty string. If the HANDLED variable has a non-empty value when the execution of the command string is finished, the shell pretends that the command was successfully determined and executed. The exit status of the simple command is that of the command string in this case.

A command that is executed in a simple command is determined by the command name using the following algorithm:

  1. If the command name contains a slash (/), the whole name is treated as the pathname of an external command. The external command is determined as the executed command.

  2. If the command name is a special built-in, the built-in is determined as the executed command.

  3. If the command name is the name of an existing function, the function is determined as the executed command.

  4. If the command name is a mandatory or elective built-in, the built-in is determined as the executed command.

  5. If the command name is an extension built-in and the shell is not in the POSIXly-correct mode, the built-in is determined as the executed command.

  6. The shell searches the PATH for a executed command:

    The value of the PATH variable is separated by colons. Each separated part is considered as a directory pathname (an empty pathname denotes the current working directory). The shell searches the directories (in the order of appearance) and checks if any directory directly contains an executable regular file whose name is equal to the command name. If such a file is found:

    • If the command name is the name of a substitutive built-in, the built-in is determined as the executed command.

    • Otherwise, the file is determined as the executed command. (The file will be executed as an external command.)

    If no such file is found, no command is determined as the executed command.

When the shell finds a file that matches the command name during the search above, the shell remembers the pathname of the file if it is an absolute path. When the algorithm above is used for the same command name again, the shell skips searching and directly determines the command to be executed. If an executable regular file no longer exists at the remembered pathname, however, the shell searches again to update the remembered pathname. You can manage remembered pathnames using the hash built-in.

Termination of the shell

The shell exits when it reached the end of input and has parsed and executed all input commands or when the exit built-in is executed. The exit status of the shell is that of the last command the shell executed (or zero if no commands were executed). The exit status of the shell is always between 0 and 255 (inclusive). If the exit status of the last command is 256 or larger, the exit status of the shell will be the remainder of the exit status divided by 256.

If an exit handler has been registered by the trap built-in, the handler is executed just before the shell exits. The exit status of the commands executed in the handler does not affect the exit status of the shell.

If a non-interactive shell encountered one of the following errors, the shell immediately exits with a non-zero exit status:

Note
Some shells other than yash exit when they fail to find a command to execute in command search.

Functions

Functions allow executing a compound command as a simple command. A function can be defined by the function definition command and executed by a simple command. You can use the unset built-in to remove function definitions.

There are no functions predefined when yash is started.

A function is executed by executing its body, which is a compound command. While the function is being executed, positional parameters are set to the arguments given to the function. The old positional parameters are restored when the function execution finishes.

Local variables

Local variables are temporary variables that are defined in a function and exist during the function execution only. They can be defined by the typeset built-in or implicitly created by a for loop. They are removed when the function execution finishes.

Local variables may hide variables that have already been defined before the function execution had started. An existing variable becomes inaccessible if a local variable of the same name is defined in a function. The old variable becomes accessible again when the function execution finishes.

You cannot create a local variable when not executing a function. A normal variable is created if you try to do so.

Command execution environment

The shell holds following properties during execution.

  • The working directory

  • Open file descriptors

  • The file creation mask (umask)

  • The set of signals whose handler is set to “ignore” (trap)

  • Environment variables

  • Resource limits (ulimit)

Those properties are inherited from the invoker of the shell to the shell, and from the shell to each external command executed by the shell.

The properties can be changed during the execution of the shell by built-in commands, variable assignments, etc.

Subshells

A subshell is a copy of the shell process. Subshells are used in execution of groupings, pipelines, etc.

Subshells inherit functions, aliases, etc. defined in the shell as well as the properties above since subshells are copies of the shell process. Notable exceptions are:

  • Traps registered by the trap built-in are all reset in subshells except for ones whose action is set to “ignore”. (See below)

  • The interactive mode and job control are disabled in subshells. Jobs are not inherited by subshells.

Subshells are executed independently of the original shell, so changes of any properties above do not affect those of the original shell.

Note
If the subshell contains a single trap built-in, some shells (but not yash) may not reset the traps on entry to the subshell.