syntax:basicgrammar

Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Both sides previous revision Previous revision
Next revision
Previous revision
Last revision Both sides next revision
syntax:basicgrammar [2012/11/15 13:33]
ormaaj Mess with this page a bit. Wrote a "commands" section. Some half-finished stuff.
syntax:basicgrammar [2019/01/16 01:01]
jdescole
Line 3: Line 3:
 {{keywords>​bash shell scripting grammar syntax language}} {{keywords>​bash shell scripting grammar syntax language}}
  
-The shell language is built upon a few basic **grammar rules**. ​This article presents a **somewhat ​theoretical view**, ​though some terminology is tweaked a bit in order to avoid discussing too many corner-cases and to present a model that fits with reality most of the time. Having a correct understanding of the basic grammar is extremely important in understanding ​the language.+Bash builds its features on top of a few basic **grammar rules**. ​The code you see everywhere, the code you use, is based on those rules. However, ​**this is a very theoretical view**, ​but if you're interested, it may help you understand why things look the way they look.
  
-===== Commands =====+If you don't know the commands used in the following examples, just trust the explanation.
  
-<wrap center round info 90%>In the shell**everything** ​is command!</wrap>+===== Simple Commands ===== 
 +Bash manual says: 
 +<code> 
 +A simple command is a sequence of optional variable assignments followed by blank-separated words and redirections,​ 
 +and terminated by a control operator. The first word specifies ​the command to be executedand is passed as argument 
 +zero.  The remaining words are passed as arguments to the invoked ​command
 +</code>
  
-Bash is fundamentally a **command oriented language**, and it is very pure in this senseJust as highly functional or object oriented languages derive most or sometimes all of their grammar from primitive notions of //​functions//​ or //objects// respectivelyBash and other POSIX compatible shells build upon the concept of a **command**. The smallest valid chunk of shell code is always a **command**,​ as is every valid line you can enter at a prompt without an error. Likewise, an entire program of thousands of lines can consist of a single (composite) command.+Sounds harder than it actually ​is. It is what you do daily. You enter simple commands with parameters, and the shell executes them.
  
-Problems ​can arise when attempting to draw too many analogies between constructs found in other languages and shell commands. ​These are some useful ways to look at what a command is.+Every complex Bash operation ​can be split into simple ​commands
 +<​code>​ 
 +ls 
 +ls > list.txt 
 +ls -l 
 +LC_ALL=C ls 
 +</​code>​
  
-  * Commands are somewhat like **functions** found in other languages in that they provide for control flow, code reuse, modularity, and have a "scope" ​of sorts to provide some degree of encapsulation. A command has what is called an **execution ​environment** which consists ​of a set of properties local to the command and inherited from the parent execution environmentAll ksh-like shells additionally support function local variables, though this isn'​t ​specified by POSIX and the details can vary drastically between shells.+The last one might not be familiar. That one simply adds "''​LC_ALL=C''​" to the environment of the ''​ls''​ programIt doesn'​t ​affect your current shell. This also works while calling functions, unless Bash runs in POSIX(r) mode (in which case it affects your current shell).
  
-  * Commands can also be thought of as analogous to **programs** or **processes**. This is where the idea of //command// diverges from common language constructs. Importantly,​ each command has its own **implicit I/O**Just like running ​UNIX program, every command has its own file descriptors inherited from some parent environment. The execution environment of a command ​can includefor examplea local set of environment variablestrapped signals, file descriptors,​ and positional parameters. A command may or may not execute in a subshell, in which case the command or commands really have their own execution environment by virtue of being a real independent UNIX process.+Every command has an exit codeIt'​s ​type of return status. The shell can catch it and act on it. Exit code range is from 0 to 255where 0 means successand the rest mean either something failed, or there is an issue to report back to the calling program.
  
-These are crude descriptions and some liberty is taken with the term //​[[http://​pubs.opengroup.org/​onlinepubs/​9699919799/​utilities/​V3_chap02.html#​tag_18_12 | execution environment]]//​. We can't get too specific about what a command ​really ​is because they encompass every construct in the language. Commands can be subdivided into **two main types**: ​**[[basicgrammar##​simple_commands ​| simple]]** and **[[basicgrammar##​compound_commands | compound]]**.+<wrap center round info 90%> 
 +The simple ​command ​construct ​is the **base** for all higher constructs. Everything you execute, from pipelines to functions, finally ends up in (many) simple commands. That's why Bash only has one method to [[syntax:​grammar:​parser_exec ​expand and execute a simple ​command]]. 
 +</​wrap>​
  
-==== Simple Commands ==== 
  
-The Bash manual says: +===== Pipelines ===== 
-<​code>​ +FIXME Missing an additional article about pipelines ​and pipelining
-A simple command is a sequence of optional variable assignments followed by blank-separated words and redirections,​ +
-and terminated by a control operator. The first word specifies the command to be executed, and is passed as argument +
-zero.  The remaining words are passed as  arguments to the invoked command. +
-</​code>​+
  
-A simple command can be any or all of the following:​ +''​[time [-p]] [ ! ] command ​[ | command2 ​... ]''​
-  * A list of zero or more **words**, which designate a **command name** and a list of **arguments**. +
-  * Zero or more simple or compound assignments separated by whitespace which must precede the word list. +
-  * Zero or more **[[syntax/​redirection | redirection operators]]**, which may appear anywhere within the command, but by convention are usually placed after the word list.+
  
-Sounds harder than it actually is. It is what you do day-to-dayYou enter simple commands with parameters and the shell executes them. Remember, there are only two things, //simple// and //​compound//​ commands. Almost everything that isn't a [[basicgrammar##​compound_commands |compound command]] ​is a simple command. Many of the more complex constructs in Bash can be broken down into simple commands.+**Don'​t get confused** about the name "​pipeline." ​It's a grammatic name for a constructSuch a pipeline ​isn'​t ​necessarily ​pair of commands where stdout/​stdin ​is connected via real pipe.
  
-Some examples+Pipelines are one or more [[basicgrammar##​simple_commands | simple commands]] (separated by the ''​|''​ symbol connects their input and output), for example
-__A (very ;-)) simple command__+<​code>​ls /etc | wc -l</​code>​ 
 +will execute ''​ls''​ on ''/​etc''​ and **pipe** the output to ''​wc'',​ which will count the lines generated by the ls command. The result is the number of directory entries in /etc. 
 + 
 +The last command in the pipeline will set the exit code for the pipeline. This exit code can be "​inverted"​ by prefixing an exclamation mark to the pipeline: An unsuccessful pipeline will exit "​successful"​ and vice versa. 
 +In this example, the commands in the if stanza will be executed if the pattern "​^root:"​ is **not** found in ''/​etc/​passwd'':​
 <​code>​ <​code>​
-echo "Hello world..."+if ! grep '​^root:'​ /​etc/​passwd;​ then 
 +  ​echo "No root user defined... eh?" 
 +fi
 </​code>​ </​code>​
 +Yes, this is also a pipeline (although there is no pipe!), because the **exclamation mark to invert the exit code** can only be used in a pipeline.
 +If ''​grep'''​s exit code is 1 (FALSE) (the text was not found), the leading ''​!''​ will "​invert"​ the exit code, and the shell sees (and acts on) exit code 0 (TRUE) and the ''​then''​ part of the ''​if''​ stanza is executed. One could say we checked for "''​not grep "​^root"​ /​etc/​passwd''"​.
  
-__All of the following are simple commands__ +The [[commands:​builtin:​set#​attributes | set option pipefail]] determines the behavior ​of how bash reports ​the exit code of a pipeline. If it's set, then the exit code (''​$?''​is the last command that exits with non zero status, if none fail, it's zero. If it's not set, then ''​$?''​ always holds the exit code of the last command ​(as explained above).
-<code>​x=5</​code+
-<​code>>​tmpfile</​code>​ +
-<​code>​{x}<"​$x"​ _=${x=<(echo moo)} <&0$(cat <&"​$x"​ >&2)</​code>​+
  
 +The shell option ''​[[internals:​shell_options#​lastpipe | lastpipe]]''​ will execute the last element in a pipeline construct in the current shell environment,​ i.e. not a subshell.
 +
 +There'​s also an array ''​PIPESTATUS[]''​ that is set after a foreground pipeline is executed. Each element of ''​PIPESTATUS[]''​ reports the exit code of the respective command in the pipeline. Note: (1) it's only for foreground pipe and (2) for higher level structure that is built up from a pipeline. Like list, ''​PIPESTATUS[]''​ holds the exit status of the last pipeline command executed.
 +
 +Another thing you can do with pipelines is log their execution time. Note that **''​time''​ is not a command**, it is part of the pipeline syntax:
 <​code>​ <​code>​
-ls +# time updatedb 
-ls > list.txt +real    3m21.288s 
-ls -l +user    0m3.114s 
-LC_ALL=C ls+sys     ​0m4.744s
 </​code>​ </​code>​
  
-The last one might not be familiar to you. That one simply adds "''​LC_ALL=C''"​ to the environment of the ''​ls''​-program. It doesn'​t affect your current shell. This also works while calling functions, unless Bash runs in POSIX(r) mode (then it affects your current shell). 
  
-Every command has a so-called exit code - it's a kind of return status. The shell can catch it and react on it. It goes from 0 to 255, where 0 means success, and the rest means any kind of failure or issue to report back to the caller.+===== Lists ===== 
 +FIXME Missing an additional article about list operators
  
-<wrap center round info 90%> +A list is a sequence of one or more [[basicgrammar#​pipelines ​pipelines]] separated by one of the operators '';'',​ ''&'',​ ''&&'',​ or ''​││'',​ and optionally terminated by one of '';'',​ ''&'',​ or ''​<newline>''​.
-The simple command construct ​is the **base** for all higher constructs. Everything you execute, form pipelines to functions, finally ends up in (many) simple commands. That's why Bash only has one method to [[syntax:​grammar:​parser_exec ​finally expand and execute a simple command]]+
-</wrap>+
  
-  ​http://pubs.opengroup.org/onlinepubs/​9699919799/​utilities/​V3_chap02.html#​tag_18_09_01+=> It's a group of **pipelines** separated or terminated by **tokens** that all have **different meanings** for Bash. 
 + 
 +Your whole Bash script technically is one big single list! 
 + 
 +^Operator^Description^ 
 +|''<​PIPELINE1>​ **<​newline>​** <​PIPELINE2>''​|Newlines completely separate pipelinesThe next pipeline is executed without any checks. You enter a command and press ''<​RETURN>''​!)| 
 +|''<​PIPELINE1>​ **;** <​PIPELINE2>''​|The semicolon does what ''<​newline>''​ does: It separates the pipelines| 
 +|''<​PIPELINE>​ **&** <​PIPELINE>''​|The pipeline in front of the ''&''​ is executed **asynchronously** ("in the background"​). If a pipeline follows this, it is executed immediately after the async pipeline starts| 
 +|''<​PIPELINE1>​ **&&​** <​PIPELINE2>''​|''<​PIPELINE1>''​ is executed and **only** if its exit code was 0 (TRUE), then ''<​PIPELINE2>''​ is executed (AND-List)| 
 +|''<​PIPELINE1>​ **<​nowiki>​||<​/nowiki>​** <​PIPELINE2>''​|''<​PIPELINE1>''​ is executed and **only** if its exit code was **not** 0 (FALSE), then ''<​PIPELINE2>''​ is executed (OR-List)| 
 + 
 +**Note:** POSIX calls this construct a "​compound lists".
  
-==== Compound Commands ====+===== Compound Commands ​=====
  
 See also the [[syntax:​ccmd:​intro | list of compound commands]]. See also the [[syntax:​ccmd:​intro | list of compound commands]].
  
 There are two forms of compound commands: There are two forms of compound commands:
-  * forming ​a new syntax element using lists as "​body"​ +  * form a new syntax element using a list as "​body"​ 
-  * complete ​independant syntax elements +  * completly ​independant syntax elements 
-Basicallyit'​s ​everything else that's not described ​elsewhere ​in this article. Compound commands have the following characteristics:​+Essentially, everything else that's not described in this article. Compound commands have the following characteristics:​
   * they **begin** and **end** with a specific keyword or operator (e.g. ''​for ... done''​)   * they **begin** and **end** with a specific keyword or operator (e.g. ''​for ... done''​)
   * they can be redirected as a whole   * they can be redirected as a whole
  
-See the following table for a short overview (without ​details - really ​just a plain overview!):+See the following table for a short overview (no details - just an overview):
 ^Compound command syntax^Description^ ^Compound command syntax^Description^
 |''​( <​LIST>​ )''​|Execute ''<​LIST>''​ in an extra subshell => [[syntax:​ccmd:​grouping_subshell | article]]| |''​( <​LIST>​ )''​|Execute ''<​LIST>''​ in an extra subshell => [[syntax:​ccmd:​grouping_subshell | article]]|
Line 82: Line 107:
 |''​for <​NAME>​ in <​WORDS>​ ; do <​LIST>​ ; done''​|Executes ''<​LIST>''​ while setting the variable ''<​NAME>''​ to one of ''<​WORDS>''​ on every iteration (classic for-loop) => [[syntax:​ccmd:​classic_for | article]]| |''​for <​NAME>​ in <​WORDS>​ ; do <​LIST>​ ; done''​|Executes ''<​LIST>''​ while setting the variable ''<​NAME>''​ to one of ''<​WORDS>''​ on every iteration (classic for-loop) => [[syntax:​ccmd:​classic_for | article]]|
 |''​for <​nowiki>​((</​nowiki>​ <​EXPR1>​ ; <​EXPR2>​ ; <​EXPR3>​ )) ; do <​LIST>​ ; done''​|C-style for-loop (driven by arithmetic expressions) => [[syntax:​ccmd:​c_for | article]]| |''​for <​nowiki>​((</​nowiki>​ <​EXPR1>​ ; <​EXPR2>​ ; <​EXPR3>​ )) ; do <​LIST>​ ; done''​|C-style for-loop (driven by arithmetic expressions) => [[syntax:​ccmd:​c_for | article]]|
-|''​select <​NAME>​ in <​WORDS>​ ; do <​LIST>​ ; done''​|Providing ​simple menus => [[syntax:​ccmd:​user_select | article]]| +|''​select <​NAME>​ in <​WORDS>​ ; do <​LIST>​ ; done''​|Provides ​simple menus => [[syntax:​ccmd:​user_select | article]]| 
-|''​case <​WORD>​ in <​PATTERN>​) <​LIST>​ ;; ... esac''​|Decicions ​based on pattern matching - executing ''<​LIST>''​ on match => [[syntax:​ccmd:​case | article]]| +|''​case <​WORD>​ in <​PATTERN>​) <​LIST>​ ;; ... esac''​|Decisions ​based on pattern matching - executing ''<​LIST>''​ on match => [[syntax:​ccmd:​case | article]]| 
-|''​if <​LIST>​ ; then <​LIST>​ ; else <​LIST>​ ; fi''​|The if-clause: ​making ​decisions based on exit codes => [[syntax:​ccmd:​if_clause | article]]|+|''​if <​LIST>​ ; then <​LIST>​ ; else <​LIST>​ ; fi''​|The if clause: ​makes decisions based on exit codes => [[syntax:​ccmd:​if_clause | article]]|
 |''​while <​LIST1>​ ; do <​LIST2>​ ; done''​|Execute ''<​LIST2>''​ while ''<​LIST1>''​ returns TRUE (exit code) => [[syntax:​ccmd:​while_loop | article]]| |''​while <​LIST1>​ ; do <​LIST2>​ ; done''​|Execute ''<​LIST2>''​ while ''<​LIST1>''​ returns TRUE (exit code) => [[syntax:​ccmd:​while_loop | article]]|
 |''​until <​LIST1>​ ; do <​LIST2>​ ; done''​|Execute ''<​LIST2>''​ until ''<​LIST1>''​ returns TRUE (exit code) => [[syntax:​ccmd:​until_loop | article]]| |''​until <​LIST1>​ ; do <​LIST2>​ ; done''​|Execute ''<​LIST2>''​ until ''<​LIST1>''​ returns TRUE (exit code) => [[syntax:​ccmd:​until_loop | article]]|
  
-=== Function Definition Command === 
-FIXME Missing an additional extra article about shell functions 
  
-A shell function definition basically makes a [[basicgrammar#​compound_commands | compound command]] available under a new name. The speciality now is, that function, when ran, has its own "​private"​ set of positional parameters and I/O descriptors. It acts like a script in the script. Simple said: **You create a new command.** 
  
-The definition is easy (one of more possibilities):​+ 
 +===== Shell Function Definitions ===== 
 +FIXME Missing an additional article about shell functions 
 + 
 +A shell function definition makes a [[basicgrammar#​compound_commands | compound command]] available via a new name. When the function runs, it has its own "​private"​ set of positional parameters and I/O descriptors. It acts like a script-within-the-script. Simply stated: **You'​ve created a new command.** 
 + 
 +The definition is easy (one of many possibilities):​
  
 ''<​NAME>​ () <​COMPOUND_COMMAND>​ <​REDIRECTIONS>''​ ''<​NAME>​ () <​COMPOUND_COMMAND>​ <​REDIRECTIONS>''​
  
-which usually ​is used with the ''​{...;​ }''​ compound command, and thus looks like+which is usually ​used with the ''​{...;​ }''​ compound command, and thus looks like:
 <​code>​ <​code>​
 print_help() { echo "​Sorry,​ no help available";​ } print_help() { echo "​Sorry,​ no help available";​ }
 </​code>​ </​code>​
  
-Like told above, a function definition can have any [[basicgrammar#​compound_commands | compound command]] as body. Structures like+As above, a function definition can have any [[basicgrammar#​compound_commands | compound command]] as body. Structures like
 <​code>​ <​code>​
 countme() for ((x=1;​x<​=9;​x++));​ do echo $x; done countme() for ((x=1;​x<​=9;​x++));​ do echo $x; done
 </​code>​ </​code>​
-are unusual, but perfectly valid since the for-loop construct is a compound command!+are unusual, but perfectly validsince the for loop construct is a compound command!
  
-If there are **redirections** specified, ​these are not performed ​on function ​definition, they are performed ​on function ​execution:+If **redirection** is specified, ​the redirection is not performed ​when the function ​is defined. It is performed ​when the function ​runs:
 <​code>​ <​code>​
-# this will NOT perform the redirection (on definition time)+# this will NOT perform the redirection (at definition time)
 f() { echo ok ; } > file f() { echo ok ; } > file
  
Line 124: Line 152:
 </​code>​ </​code>​
  
-The space between ''​NAME''​ and ''​()''​ is optional, usually you just see it without.+The space between ''​NAME''​ and ''​()''​ is optional, usually you see it without ​the space.
  
-I suggest ​to use the first form. It's specified in POSIX and all Bourne-like shells seem to support it.+I suggest ​using the first form. It's specified in POSIX and all Bourne-like shells seem to support it.
  
-__**Note:​**__ Before version ''​2.05-alpha1'',​ Bash only recognized the definition using curly braces (''​name() { ... }''​), also, other shells allow the definition using **any** command (not only compound command set).+__**Note:​**__ Before version ''​2.05-alpha1'',​ Bash only recognized the definition using curly braces (''​name() { ... }''​),​ other shells allow the definition using **any** command (not just the compound command set).
  
-To execute a function like a regular shell script you would put it together like this:+To execute a function like a regular shell script you put it together like this:
  
 <​code>​ <​code>​
Line 138: Line 166:
 mycmd() mycmd()
 { {
-  # this $1 is the one of the function!+  # this $1 belongs to the function!
   find / -iname "​$1"​   find / -iname "​$1"​
 } }
  
-# this $1 is the one of the script itself!+# this $1 belongs ​the script itself!
 mycmd "​$1"​ # Execute command immediately after defining function ​ mycmd "​$1"​ # Execute command immediately after defining function ​
  
Line 150: Line 178:
 **Just informational(1):​** **Just informational(1):​**
  
-Internally, for forking, Bash stores ​the function definitions in environment variables. Variables with the content "//() ....//"​.+Internally, for forking, Bash stores function definitions in environment variables. Variables with the content "//() ....//"​.
  
-Something ​like the following works without "​officially"​ declaring a function:+Something ​similar to the following works without "​officially"​ declaring a function:
 <​code>​ <​code>​
 $ export testfn="​() { echo test; }" $ export testfn="​() { echo test; }"
Line 162: Line 190:
 **Just informational(2):​** **Just informational(2):​**
  
-It is possible to set function names containing slashes:+It is possible to create ​function names containing slashes:
  
 <​code>​ <​code>​
Line 170: Line 198:
 </​code>​ </​code>​
  
-The elements of this name aren't subject to path search, of course.+The elements of this name aren't subject to path search.
  
-The weird names a function ​can have should not be used. Quote from the maintainer:+Weird function ​names should not be used. Quote from the maintainer:
   * //   * //
 It was a mistake to allow such characters in function names (`unset'​ doesn'​t It was a mistake to allow such characters in function names (`unset'​ doesn'​t
Line 178: Line 206:
 for backwards compatibility,​ but I don't have to encourage their use. for backwards compatibility,​ but I don't have to encourage their use.
 // //
- 
-  * http://​pubs.opengroup.org/​onlinepubs/​9699919799/​utilities/​V3_chap02.html#​tag_18_09_05 
- 
-===== Pipelines ===== 
-FIXME Missing an additional extra article about pipelines and pipelining 
- 
-''​[time [-p]] [ ! ] command [ | command2 ... ]''​ 
- 
-**Don'​t get confused** about the name "​pipeline"​ here, it's a grammar name for that construct, such a pipeline isn't necessarily a pair of commands where stdout/​stdin is connected through a real pipe. 
- 
-Basically, pipelines are one or more [[basicgrammar##​simple_commands | simple commands]] (when more, separated by the ''​|''​-symbol and connecting their input and output), for example: 
-<​code>​ls /etc | wc -l</​code>​ 
-will execute ''​ls''​ on ''/​etc''​ and **pipe** the output to ''​wc'',​ which will count lines. That way, you simply count your directory entries in /etc. 
- 
-The last command in the pipeline will also set the exit code for the pipeline. This exit code can be "​reversed"​ by preceeding an exclamation-mark to the pipeline: An unsuccessful pipeline will end up "​successful"​ and vice versa. 
-In this example, the commands in the if-structure will be executed, if the pattern "​^root:"​ is **not** found in ''/​etc/​passwd'':​ 
-<​code>​ 
-if ! grep '​^root:'​ /​etc/​passwd;​ then 
-  echo "No root-user defined... eh?" 
-fi 
-</​code>​ 
-Yes, this is also a pipeline (though there is no piping!), because the **exclamation mark to reverse the exit code** can only be used in pipelines. 
-If ''​grep'''​s exit code is 1 (FALSE) (the text was not found), the leading ''​!''​ will "​reverse"​ the exit code for the shell, the shell sees (and reacts on) exit code 0 (TRUE) and the ''​then''​-path of the ''​if''​-clause is executed. One could say we checked for "''​not grep "​^root"​ /​etc/​passwd''"​. 
- 
-The [[commands:​builtin:​set#​attributes | set option pipefail]] determines the behavior of how bash reports exit code of pipeline. If it's set, then the exit code (''​$?''​) is the last command that exits with non-0 status, if none fails, it's 0. If it's not set, then ''​$?''​ always holds the exit code of the last command (as explained above). 
- 
-The shell option ''​[[internals:​shell_options#​lastpipe | lastpipe]]''​ will make the last element in a pipeline construct being executed in the current shell environment,​ not in a separate subshell. 
- 
-There'​s also an array ''​PIPESTATUS[]''​ that is set after a foreground pipeline is executed. Each element of ''​PIPESTATUS[]''​ reports the exit code of each respective command in the pipeline. Note: (1) it's only for foreground pipe and (2) for higher level structure that is built up from pipeline, like list, ''​PIPESTATUS[]''​ holds only the last pipeline executed. 
- 
-Another thing you can do with pipelines is logging their execution time. Note that **''​time''​ is not a command**, it belongs to the special words for pipeline-syntax:​ 
-<​code>​ 
-# time updatedb 
-real    3m21.288s 
-user    0m3.114s 
-sys     ​0m4.744s 
-</​code>​ 
- 
-  * http://​pubs.opengroup.org/​onlinepubs/​9699919799/​utilities/​V3_chap02.html#​tag_18_09_02 
- 
-===== Lists ===== 
-FIXME Missing an additional extra article about the list operators 
- 
-A list is a sequence of one or more [[basicgrammar#​pipelines | pipelines]] separated by one of the operators '';'',​ ''&'',​ ''&&'',​ or ''​││'',​ and optionally terminated by one of '';'',​ ''&'',​ or ''<​newline>''​. 
- 
-=> It's a bunch of **pipelines** separated or terminated by **tokens** that all have **different meanings** for Bash. 
- 
-Your whole Bash script technically is one big single list! 
- 
-^Operator^Description^ 
-|''<​PIPELINE1>​ **<​newline>​** <​PIPELINE2>''​|Newlines completely separate pipelines. The next pipeline is simply executed, without any checks or specials (Hey! You do that every day! You enter a command and press ''<​RETURN>''​!)| 
-|''<​PIPELINE1>​ **;** <​PIPELINE2>''​|The semicolon does what ''<​newline>''​ does: It completely separates the pipelines| 
-|''<​PIPELINE>​ **&** <​PIPELINE>''​|The pipeline infront of that ''&''​ is executed **async** ("in background"​) - if a pipeline follows this, it is immediately executed after the async one was started| 
-|''<​PIPELINE1>​ **&&​** <​PIPELINE2>''​|''<​PIPELINE1>''​ is executed and **only** if its exit code was 0 (TRUE), then ''<​PIPELINE2>''​ is executed (AND-List)| 
-|''<​PIPELINE1>​ **<​nowiki>​||</​nowiki>​** <​PIPELINE2>''​|''<​PIPELINE1>''​ is executed and **only** if its exit code was **not** 0 (FALSE), then ''<​PIPELINE2>''​ is executed (OR-List)| 
- 
-**Note:** POSIX calls this construct a "​compound lists"​. 
- 
-  * http://​pubs.opengroup.org/​onlinepubs/​9699919799/​utilities/​V3_chap02.html#​tag_18_09_03 
  
  
 ===== Grammar summary ===== ===== Grammar summary =====
-Not much of correct definitions,​ just some short **slogans**:​ 
   * a [[basicgrammar#​simple_commands | simple command]] is just a command and its arguments   * a [[basicgrammar#​simple_commands | simple command]] is just a command and its arguments
   * a [[basicgrammar#​pipelines | pipeline]] is one or more [[basicgrammar#​simple_commands | simple command]] probably connected in a pipe   * a [[basicgrammar#​pipelines | pipeline]] is one or more [[basicgrammar#​simple_commands | simple command]] probably connected in a pipe
   * a [[basicgrammar#​lists | list]] is one or more [[basicgrammar#​pipelines | pipelines]] connected by special operators   * a [[basicgrammar#​lists | list]] is one or more [[basicgrammar#​pipelines | pipelines]] connected by special operators
   * a [[basicgrammar#​compound_commands | compound command]] is a [[basicgrammar#​lists | list]] or a special command that forms a new meta-command   * a [[basicgrammar#​compound_commands | compound command]] is a [[basicgrammar#​lists | list]] or a special command that forms a new meta-command
-  * a [[basicgrammar#​shell_function_definitions | function definition]] makes a [[basicgrammar#​compound_commands | compound command]] available under a new name, and in some kind of separate environment+  * a [[basicgrammar#​shell_function_definitions | function definition]] makes a [[basicgrammar#​compound_commands | compound command]] available under a new name, and separate environment
  
  
Line 253: Line 221:
  
 ---- ----
 +__A (very) simple command__
 +<​code>​
 +echo "Hello world..."​
 +</​code>​
  
 +__All of the following are simple commands__
 +<​code>​x=5</​code>​
 +<​code>>​tmpfile</​code>​
 +<​code>​{x}<"​$x"​ _=${x=<​(echo moo)} <&​0$(cat <&"​$x"​ >&​2)</​code>​
 ---- ----
 __A common compound command__ __A common compound command__
Line 261: Line 237:
 fi fi
 </​code>​ </​code>​
-  * the [[basicgrammar#​compound_commands | compound command]] for the ''​if''​-clause+  * the [[basicgrammar#​compound_commands | compound command]] for the ''​if''​ clause
   * the [[basicgrammar#​lists | list]] that ''​if''​ **checks** actually contains the [[basicgrammar#​simple_commands | simple command]] ''​[ -d /data/mp3 ]''​   * the [[basicgrammar#​lists | list]] that ''​if''​ **checks** actually contains the [[basicgrammar#​simple_commands | simple command]] ''​[ -d /data/mp3 ]''​
   * the [[basicgrammar#​lists | list]] that ''​if''​ **executes** contains a simple command (''​cp mymusic.mp3 /​data/​mp3''​)   * the [[basicgrammar#​lists | list]] that ''​if''​ **executes** contains a simple command (''​cp mymusic.mp3 /​data/​mp3''​)
  
  
-Let'​s ​reverse the exit code of the test command, only one thing changes:+Let'​s ​invert ​test command ​exit code, only one thing changes:
 <​code>​ <​code>​
 if ! [ -d /data/mp3 ]; then if ! [ -d /data/mp3 ]; then
Line 277: Line 253:
 ===== See also ===== ===== See also =====
  
-  * [[syntax:​ccmd:​intro | List of compound commands]] +  * Internal: ​[[syntax:​ccmd:​intro | List of compound commands]] 
-  * [[syntax:​grammar:​parser_exec | Parsing and execution of simple commands]] +  * Internal: ​[[syntax:​grammar:​parser_exec | Parsing and execution of simple commands]] 
-  * [[syntax:​quoting | Quoting and escaping]] +  * Internal: ​[[syntax:​quoting | Quoting and escaping]] 
-  * [[syntax:​expansion:​intro | Introduction to expansions and substitutions]] +  * Internal: ​[[syntax:​expansion:​intro | Introduction to expansions and substitutions]] 
-  * [[syntax:​words | Some words about words...]] +  * Internal: ​[[syntax:​words | Some words about words...]]
-  * [[http://​pubs.opengroup.org/​onlinepubs/​9699919799/​utilities/​V3_chap02.html#​tag_18_10 | shell grammar]]+
  
  • syntax/basicgrammar.txt
  • Last modified: 2019/04/01 21:45
  • by ddebhw