{ stuff }* - zero or more of "stuff" { stuff }+ - one or more of "stuff" { stuff }? - zero or one of "stuff" { stuff1 | stuff2 | ... } - stuff1 or stuff2 or ... - a tag to refer (below) to the immediately preceding entity command-line: sequence { "&" }? command: { redirection }* command-core { redirection }* command-core: word-list "(" sequence ")" "(!" sequence ")" "(|" { word "|:" }? { word-list }? "|-" sequence { "|;" sequence }* "|)" "(&" sequence "&)" "(&&" sequence "&)" "(?" sequence { "?-" sequence }? { "?;" sequence }? ")" "(@" { sequence { "@." | "@!." } }* { sequence }? ")" word-list: { word }+ sequence: oror { ";" oror }* oror: andand { "||" andand }* andand: pipeline { "&&" pipeline }* pipeline: command { "|" command }* redirection (semantic notes in []): "<" filename [stdin, O_RDONLY] ">" filename [stdout, O_WRONLY|O_CREAT|O_TRUNC] ">>" filename [stdout, O_WRONLY|O_CREAT|APPEND] ">&" filename [stdout & stderr, O_WRONLY|O_CREAT|O_TRUNC] ">>&" filename [stdout & stderr, O_WRONLY|O_CREAT|O_APPEND] "<>" filename [stdin & stdout, O_RDWR|O_CREAT] "<>>" filename [stdin & stdout, O_RDWR|O_CREAT|O_APPEND] "<>&" filename [stdin/stdout/stderr, O_RDWR|O_CREAT] "<>>&" filename [stdin/stdout/stderr, O_RDWR|O_CREAT|O_APPEND] N"<" filename [fd N, O_RDONLY] N">" filename [fd N, O_WRONLY|O_CREAT|O_TRUNC] N">>" filename [fd N, O_WRONLY|O_CREAT|O_APPEND] N"<>" filename [fd N, O_RDWR|O_CREAT] N"<>>" filename [fd N, O_RDWR|O_CREAT|O_APPEND] N"&"M [fd N, dup from fd M] N"&-" [close fd N] "<|" word [stdin, from pipe read end] ">|" word [stdout, to pipe write end] N"<|" word [fd N, from pipe read end] N">|" word [fd N, to pipe write end] "<||" [stdin, from (| |) input] ">||" [stdout, to (| |) output] N"<||" [fd N, from (| |) input] N">||" [fd N, to (| |) output] filename: word In the redirections, N and M represent nonempty strings of digits. In the above, where no whitespace is shown, no whitespace is permitted. The redirections beginning with < or > must not be preceded without whitespace by a word containing only digits. The ( ) construct simply executes the pipelines in the sequence sequentially. Each one inherits the environment of the ( ) construct. The (! ) construct executes everything within it, like ( ), but arranges that any shell-affecting commands (eg, cd) within do not affect the main shell. The (& &) construct is just like the ( ) construct, except that the shell does not wait for the process(es) involved to exit before considering the command complete. (They still belong to the same process group as the rest of the job, if any.) This construct can thus be used to background a command without it becoming a job to the shell. The (&& &) construct is just like (& &) except that the affected processes are put in a process group of their own. The (| |) construct and the redirectors containing >| or <| work together; they are both a complex pipe construction syntax and a parallel execution syntax. The "sequence"s in the (| |) are executed in parallel. The word-list lists names for pipes; the redirection forms involving names may be used to refer to these pipes by name (redirections involving > redirect to the write end of the pipe, those involving < to the read end). There is no requirement that any words be listed before the |- in a (| |); if none are, the construct provides only parallel execution. The optional word with |: provides a name for the construct as a whole; this word can be used in redirections as if it were a pipe name, but when so used it refers to the stdin and stdout of the (| |) construct as a whole. The redirections using || refer to the stdin and stdout of the smallest enclosing (| |) construct without requiring that it be given a name (names exist so that it is possible to refer to an outer (| |) construct when they are nested). It is an error for a (| |) to have a name that also appears in its word-list. Names are always parsed with reference to the smallest enclosing (| |) that provides a meaning for that name. (? ?- ?; ) is a conditional execution construct. The first sequence is the conditional part; if it succeeds, the ?- part is run, otherwise the ?; part. Either of the latter two may be missing. (They actually may both be missing, but the construct is then rather pointless.) (@ ) is a looping construct. The sequences are executed in order. Whenever @. is encountered, the loop exits if the previous sequence failed; when @!. is encountered, the loop exits if the previous sequence succeeded. (@. = "while"; @!. = "unless".) If the end of the sequences is reached without any exit condition triggering, execution starts over from the beginning again. Except as directed by (&& &) constructs, everything in a command-line is in the same process group. This includes processes run for backquotes. A sequence reflects the exit status of the last oror making it up. An oror succeeds if any of the andands making it up succeeds (and any andands after the first successful andand are not executed); if it fails, it reflects the exit status of the last andand. An andand succeeds if all of the pipelines making it up succeed (and any pipelines after the failing pipeline are not executed); if it fails, it reflects the exit status of the failing pipeline. A pipeline reflects the exit status of the last command in it (but is not considered complete until all its commands finish). A command succeeds if its process exits with exit code 0; it fails if it exits with any other exit code, or if it dies on a signal. A command that cannot be run because an error occurred while setting up to execute it (such as an error opening a redirection file, or an exec()-family error) is considered to have failed with exit(1). ( ) and (! ) constructs are considered to exit with the exit status of their contained sequences. A (| |) construct is considered to succeed if all its sequences succeed; otherwise, it fails with exit(1). (& &) and (&& &) constructs are always considered to succeed immediately. A (? ) construct reflects the exit status of the selected arm; if the selected arm does not exist, the construct succeeds. A (@ ) construct always succeeds. A word is a sequence of zero or more otherwise unspecial characters, optionally intermixed with backslashed characters, quoted strings, and sequences enclosed in (` `) (or (`` `)). With the additional note that no whitespace may appear except as a single-quoted-char, double-quoted-char, \-quoted character, or part of the sequence within a backquote, a word can be described as word: { word-part }+ word-part: word-text "(`" sequence "`)" "(``" { word-text }+ sequence "`)" word-text: "\" "'" { single-quoted-char }* "'" dquote { double-quoted-char }* dquote dquote: single-quoted-char: "\" double-quoted-char: "\" Except as specifically noted, quoted characters may appear only as words or parts of words. Backquoted commands are normally run as late as possible, so as to get the environment (such as the working directory) "correct". Specifically, there are four places backquoted commands may appear according to the above syntax - the four places words appear: - in the word-list that forms a command-core. - in the names associated with a (| |). - in the pipe name associated with a pipe (| |) redirection. - in the filename assocated with a file redirection. Type backquotes are run immediately before the command they are part of. Type and backquotes are more of a pain. Because of timing issues for error-checking, they would have to be run at inconveniently early times; given the intended uses for (| |), it's not clear that such backquotes have any real use, and accordingly they are prohibited entirely. Type backquotes are run when the filename is needed. Type backquotes also must not produce multiple words. If multiple backquotes are needed for a given command, no promises are made about what order they are run in - not even that they _are_ run in an order; the execution of backquote constructs may overlap (provided they are for the same command, or for commands whose execution may overlap). Commands run inside backquotes get /dev/null on stdin and inherit stderr from the environment enclosing the command they belong to (their stdout is captured by the backquote mechanism). For backquotes embedded in redirections, the enclosing environment is the one before any of the command's redirections are done; for backquotes in a command-core, the enclosing environment is the one after all of that command's redirections are done. Backquotes can never generate shell metasyntax. The word-text following (`` is a list of flags, and can include: q do not break; all output is effectively quoted n break at newlines instead of any whitespace l preserve a leading zero-length string t preserve a trailing zero-length string z preserve non-leading non-trailing zero-length strings e error on error (see discussion of errors, below) These may be capitalized to negate them; all are off by default. (` is just like (`` with a zero-length flag string (ie, using all the defaults). When conflicting flags are given, the last one given wins. Unrecognized flag characters are ignored with a message printed. Note that z, t, and l are orthogonal (by default, all zero-length strings are discarded, which in particular means that multiple consecutive separators are collapsed). If a command run in backquotes generates an error, the shell either aborts execution of the enclosing construct that depends on the backquoted output (if the e flag is in effect for the backquote) or ignores the error and uses any output that may have been generated (otherwise). The four places words appear also affect globbing: - in the word-list that forms a command-core. - in the names associated with a (| |). - in the pipe name associated with a pipe (| |) redirection. - in the filename assocated with a file redirection. Type words may glob arbitrarily, except that the first word of such a list must glob to exactly one result. Type and words are not globbed at all - globbing characters are not special within them. Type words are globbed, but must glob to exactly one result. Backquote expansion happens before globbing - but note that backquote-generated characters are effectively quoted; globbing characters take effect only when they are outside the backquotes. Tokens: "&" "(" ")" "(|" "|:" "|-" "|;" "|)" "(&" "&)" "(&&" ";" "||" "&&" "|" "<" ">" ">>" ">&" ">>&" "<>" "<>>" "<>&" "<>>&" "(!" "(`" "(``" "`)" N">" N">>" N"<" N"<>" N"<>>" N"&"M "<|" ">|" N"<|" N">|" "<||" ">||" N"<||" N">||" { word-text }+