diff options
author | AnotherTest <ali.mpfard@gmail.com> | 2020-07-16 22:34:30 +0430 |
---|---|---|
committer | Andreas Kling <kling@serenityos.org> | 2020-08-14 10:31:52 +0200 |
commit | 0950fd1438e8479fe8dbab0c6eaad0e8639d079c (patch) | |
tree | c5a526dced1cce07c9514e2aeee4b3b015a568cc | |
parent | a2b99dd3ea0d7fcc6804c2b4c0fdddddbffb47d2 (diff) | |
download | serenity-0950fd1438e8479fe8dbab0c6eaad0e8639d079c.zip |
Shell: Start writing a man page
This patch adds two man pages describing the parts of the shell that
have been so far finalised.
-rw-r--r-- | Base/usr/share/man/man1/Shell.md | 40 | ||||
-rw-r--r-- | Base/usr/share/man/man5/Shell.md | 266 | ||||
-rw-r--r-- | Shell/Parser.h | 4 |
3 files changed, 309 insertions, 1 deletions
diff --git a/Base/usr/share/man/man1/Shell.md b/Base/usr/share/man/man1/Shell.md new file mode 100644 index 0000000000..0705124d5b --- /dev/null +++ b/Base/usr/share/man/man1/Shell.md @@ -0,0 +1,40 @@ +## Name + +`Shell` - Shell, the command language interpreter + +## Synopsis + +```**sh +$ Shell [--skip-shellrc] +$ Shell [--skip-shellrc] command_file [arguments...] +$ Shell [--skip-shellrc] -c command_string [arguments...] +``` + +## Description + +The `Shell` utility is a command language interpreter, which reads commands from either a command string, a specified file, or the standard input. +The command language shall be described in [`Shell`(5)](../man5/Shell.md), _The Shell Command Language_. + +Any extra arguments passed into `arguments` are placed in the local variable `$ARGV` and can also be accessed through the special variable `$*`. + +**NOTE**: + +The `Shell` utility does not promise POSIX `sh` interoperability. + +## Options + +* `-c`, `--command-string`: Executes the given string as a command and exits +* `--skip-shellrc`: Skips running the initialisation file (at `~/.shellrc`) + +## Examples + +```sh +# Start an interactive REPL, ignoring the shellrc +Shell --skip-shellrc + +# Execute a given string +Shell -c 'rm foo*' + +# Execute the contents of a file with some arguments +Shell foo a b c +``` diff --git a/Base/usr/share/man/man5/Shell.md b/Base/usr/share/man/man5/Shell.md new file mode 100644 index 0000000000..3821ceeb4a --- /dev/null +++ b/Base/usr/share/man/man5/Shell.md @@ -0,0 +1,266 @@ +## Name + +The Shell Command Language + +## Introduction + +The shell operates according to the following general steps: + +* Some string is read from a source, be it a file, the standard input, or a command string (see [`Shell`(1)](../man1/Shell.md)) +* The shell parses the input to an abstract syntax tree +* The shell performs various expansions and/or resolutions on the nodes +* The shell performs various type checks and syntactic checks +* The shell interprets the AST, evaluating commands as needed +* For each given command, the shell flattens all the string/list arguments +* For each given command, the shell records the applicable redirections +* Should a command be executed, the shell applies the redirections, and executes the command with the flattened argument list +* Should a command need waiting, the shell shall wait for the command to finish, and continue execution + +Any text below is superceded by the formal grammar defined in the _formal grammar_ section. + +## General Token Recognition + +This section describes the general tokens the language accepts, it should be noted that due to nature of the language, some tokens are valid only in a specific context. + +##### Bareword +String of characters that are not _Special_ or _Syntactic Elements_ + +##### Glob +String of characters containing at least one of `*?` in _bareword_ position + +##### Single Quoted String +Any sequence of characters between two single quotes (`'`) + +##### Double Quoted String +Any sequence of _Double Quoted String Part_ tokens: +* Barewords +* Single Quotes +* Variable References +* Evaluate expressions +* Escaped sequences + +##### Variable Reference +Any sequence of _Identifier_ characters, or a _Special Variable_ follwing a `$` + +##### Evaluate expression +Any expression following a `$` that is not a variable reference: +* Inline execution: A _syntactic list_ following a `$`: +* Dynamic evaluation: Any other expression following a `$` + +##### Lists +Any two expressions joined by the Join operator (` ` [whitespace]), or a _variable reference_ referring to a list value +* Syntactic Lists: Any _list_ enclosed in parentheses (`(` and `)`) + +##### Comments +Any text following a `#` in _bareword_ position, up to but not including a newline + +##### Keywords +The following tokens: +* `for` in command name position +* `in` as a syntactic element of a `for` expression + +##### Special characters +Any of the following: +* `;` in bareword position +* `\\n` (a newline) in _bareword_ position +* Any of `(){}` +* Any of `*?` not in _glob_ position + +##### Tilde +Any initial path segment starting with the character `~` in _bareword_ position, Optionally followed by a _bareword_ for the username + +## Redirections +The shell can create various redirections to file descriptors of a command before executing it, the general syntax for redirections is an optional file descriptor, followed by a redirection operator, followed by a destination. + +There are four redirection operators corresponding to various file descriptor open modes: `Read`, `Write`, `WriteAppend` and `ReadWrite`, respectively `<`, `>`, `>>` and `<>`. + +A special syntactic element `&fd` can reference a file descriptor as a destination. + +Redirections take two main forms, Read/Write redirections, and fd closure redirections. +##### Read/Write +* Allowed operators: all +* Allowed destinations: file paths (any shell _expression_) and _file descriptor references_ + +##### Close +* Allowed operators: `Write` (`>`) +* Allowed destinations: the special "close" reference `&-` + +#### Examples +```sh +# Redirect the standard error to a file, and close the standard input +$ 2> foo 1>&- + +# Redirect a file as read-write into the standard input +$ 1<>foo + +# Redirect the standard output to /dev/null +$ >/dev/null +``` + +## Expansions +The shell performs various expansions, in different stages. + +* Glob Expansion: Globs shall be expanded to a list. + +* Variable Expansion: Variables shall be expanded preserving their types. + +* Juxtaposition Expansion: Juxtapositions shall be expanded as list products. + +* Other expansions: Tildes, Evaluate expressions, etc. shall be expanded as needed. + +### Juxtapositions +Any two expressions joined without any operator are considered to be in a Juxtaposition, with the resulting value being the list product of two expressions. +For instance, `(1 2)(3 4)` shall be evaluated to `(13 14 23 24)` by calculating the list product of the two expressions `(1 2)` and `(3 4)`. + +### Tildes +Any bareword starting with a tilde (`~`) and spanning up to the first path separator (`/`) - or EOL - is considered to be a tilde expansion with the text between the tilde and the separator being the _username_, which shall be expanded to a single string containing the home directory of the given _username_ (or the current user if no username is provided). + +### Evaluate +Evaluate expressions take the general form of a dollar sign (`$`) followed by some _expression_, which is evaluated by the rules below. +- Should the _expression_ be a string, it shall be evaluated as a dynamic variable lookup by first evaluating the string, and then looking up the given variable. +- Should the _expression_ be a list or a command, it shall be converted to a command, whose output (from the standard output) shall be captured, and split to a list with the shell local variable `IFS` (or the default splitter `\n` (newline, 0x0a)). It should be noted that the shell option `inline_exec_keep_empty_segments` will determine whether empty segments in the split list shall be preserved when this expression is evaluated, this behaviour is disabled by default. + +## Commands + +A `Command` is a single simple command, containing arguments and redirections for a single program. The shell can evaluate a sequence of commands, a conditional relation between commands, or various semantic elements composed of commands and intrinsics. + +Commands can be either calls to Shell builtins, or external programs. + +## Shell Semantic Elements +The commands can be composed into semantic elements, producing composite commands: + +### Sequences +A sequence of commands, executed serially independent of each other: `Commanad ; Command ; Command ...` + +It should be noted that a newline (`\\n`) can be substituted for the semicolon (`;`). + +#### Example +```sh +# Do one thing, then do another +echo foo; echo bar +``` + +### Logical Relations +A sequence of commands whose execution depends somehow on the result of another + +##### `Command && Command && Command ...` (AND) +Short-circuiting command evaluations, will cancel the entire chain should any command fails (have a non-zero exit code) + +##### `Command || Command || Command ...` (OR) +Short-circuiting command evaluation, will continue down the chain if any command fails. + +It should be noted that `And` chains bind more tightly than `Or` chains, so an expression of the form `C1 && C2 || C3` is understood as "evaluate `C1`, if successful, evaluate `C2`, if not successful, evaluate `C3`". + +#### Examples +```sh +# Create file if not found +test -f foo.txt || touch foo.txt + +# Announce execution status of a command +rm test && echo "deleted!" || echo "failed with $?" +``` + +#### Loops + +##### For Loops +For Loops evaluate a sequence of commands once per element in a given list. +The shell has two forms of _for loops_, one with an explicitly named iteration variable, and one with an implicitly named one. +The general syntax follows the form `for name in expr { sequence }`, and allows omitting the `name in` part to implicitly name the variable `it`. + +A for-loop evaluates the _sequence_ once per every element in the _expr_, seetting the local variable _name_ to the element being processed. + +The Shell shall cancel the for loop if two consecutive commands are interrupted via any of SIGINT (\^C), SIGQUIT (\^\\) or SIGKILL. + +#### Examples +```sh +# Iterate over every non-hidden file in the current directory, and prepend '1-' to its name. +$ for * { mv $it 1-$it } + +# Iterate over a sequence and write each element to a file +$ for i in $(seq 1 100) { echo $i >> foo } +``` + +## Formal Grammar + +### Shell Grammar +``` +toplevel :: sequence? + +sequence :: variable_decls? or_logical_sequence terminator sequence + | variable_decls? or_logical_sequence '&' sequence + | variable_decls? control_structure terminator sequence + | variable_decls? or_logical_sequence + | variable_decls? terminator sequence + +or_logical_sequence :: and_logical_sequence '|' '|' and_logical_sequence + | and_logical_sequence + +and_logical_sequence :: pipe_sequence '&' '&' and_logical_sequence + | pipe_sequence + +terminator :: ';' + | '\n' + +variable_decls :: identifier '=' expression (' '+ variable_decls)? ' '* + | identifier '=' '(' pipe_sequence ')' (' '+ variable_decls)? ' '* + +pipe_sequence :: command '|' pipe_sequence + | command + +control_structure :: for_loop + +for_loop :: 'for' ws+ (identifier ' '+ 'in' ws*)? expression ws+ '{' toplevel '}' + +command :: redirection command + | list_expression command? + +redirection :: number? '>'{1,2} ' '* string_composite + | number? '<' ' '* string_composite + | number? '>' '&' number + | number? '>' '&' '-' + +list_expression :: ' '* expression (' '+ list_expression)? + +expression :: evaluate expression? + | string_composite expression? + | comment expession? + | '(' list_expression ')' expression? + +evaluate :: '$' '(' pipe_sequence ')' + | '$' expression {eval / dynamic resolve} + +string_composite :: string string_composite? + | variable string_composite? + | bareword string_composite? + | glob string_composite? + +string :: '"' dquoted_string_inner '"' + | "'" [^']* "'" + +dquoted_string_inner :: '\' . dquoted_string_inner? {concat} + | variable dquoted_string_inner? {compose} + | . dquoted_string_inner? + | '\' 'x' digit digit dquoted_string_inner? + | '\' [abefrn] dquoted_string_inner? + +variable :: '$' identifier + | '$' '$' + | '$' '?' + | '$' '*' + | '$' '#' + | ... + +comment :: '#' [^\n]* + +bareword :: [^"'*$&#|()[\]{} ?;<>] bareword? + | '\' [^"'*$&#|()[\]{} ?;<>] bareword? + +bareword_with_tilde_expansion :: '~' bareword? + +glob :: [*?] bareword? + | bareword [*?] + +digit :: <native hex digit> +number :: <number in base 10> +identifier :: <string of word characters> +``` diff --git a/Shell/Parser.h b/Shell/Parser.h index 06c4e7905e..7de24b82aa 100644 --- a/Shell/Parser.h +++ b/Shell/Parser.h @@ -125,7 +125,9 @@ variable_decls :: identifier '=' expression (' '+ variable_decls)? ' '* pipe_sequence :: command '|' pipe_sequence | command -control_structure :: 'for' ws+ (identifier ' '+ 'in' ws*)? expression ws+ '{' toplevel '}' +control_structure :: for_loop + +for_loop :: 'for' ws+ (identifier ' '+ 'in' ws*)? expression ws+ '{' toplevel '}' command :: redirection command | list_expression command? |