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
syntax:basicgrammar [2011/04/12 04:52]
thebonsai avoid weird function names
syntax:basicgrammar [2019/04/01 21:45] (current)
ddebhw Fix a little typo.
Line 3: Line 3:
 {{keywords>​bash shell scripting grammar syntax language}} {{keywords>​bash shell scripting grammar syntax 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 these rules. However, **this is a very theoretical view**, but if you're interested, it may help you to understand why things look like they look+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.
- +
-In the following examples, some commands will be used. If you don't know these commands, just believe the short explanation. Here, they are only used as examples.+
  
 +If you don't know the commands used in the following examples, just trust the explanation.
  
 ===== Simple Commands ===== ===== Simple Commands =====
Line 13: Line 12:
 A simple command is a sequence of optional variable assignments followed by blank-separated words and redirections,​ 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 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.+zero.  The remaining words are passed as arguments to the invoked command.
 </​code>​ </​code>​
  
-Sounds harder than it actually is. It is what you do day-per-day. You enter simple commands with parameters and the shell executes them.+Sounds harder than it actually is. It is what you do daily. You enter simple commands with parametersand the shell executes them.
  
-Every more complex ​operation in Bash can be finally splitted ​into executing such simple commands:+Every complex Bash operation ​can be split into simple commands:
 <​code>​ <​code>​
 ls ls
Line 26: Line 25:
 </​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).+The last one might not be familiar. 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 (in which case 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.+Every command has an exit code. It's a type of return status. The shell can catch it and act on it. Exit code range is from 0 to 255, where 0 means success, and the rest mean either something failed, ​or there is an issue to report back to the calling program.
  
 <wrap center round info 90%> <wrap center round info 90%>
-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]].+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>​ </​wrap>​
  
  
 ===== Pipelines ===== ===== Pipelines =====
-FIXME Missing an additional ​extra article about pipelines and pipelining+FIXME Missing an additional article about pipelines and pipelining
  
 ''​[time [-p]] [ ! ] command [ | command2 ... ]''​ ''​[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.+**Don'​t get confused** about the name "​pipeline." ​It's a grammatic ​name for construct. Such a pipeline isn't necessarily a pair of commands where stdout/​stdin is connected ​via 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:+Pipelines ​are one or more [[basicgrammar##​simple_commands | simple commands]] (separated by the ''​|''​ symbol ​connects ​their input and output), for example:
 <​code>​ls /etc | wc -l</​code>​ <​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.+will execute ''​ls''​ on ''/​etc''​ and **pipe** the output to ''​wc'',​ which will count the lines generated by the ls commandThe result is the number of 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. +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-structure ​will be executedif the pattern "​^root:"​ is **not** found in ''/​etc/​passwd'':​+In this example, the commands in the if stanza ​will be executed if the pattern "​^root:"​ is **not** found in ''/​etc/​passwd'':​
 <​code>​ <​code>​
 if ! grep '​^root:'​ /​etc/​passwd;​ then if ! grep '​^root:'​ /​etc/​passwd;​ then
-  echo "No root-user defined... eh?"+  echo "No root user defined... eh?"
 fi fi
 </​code>​ </​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+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 "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''"​.+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''"​.
  
-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 [[commands:​builtin:​set#​attributes | set option pipefail]] determines the behavior of how bash reports ​the exit code of 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).
  
-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 separate ​subshell.+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 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.+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 pipeline. Like list, ''​PIPESTATUS[]''​ holds the exit status of the last pipeline ​command ​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:+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>​
 # time updatedb # time updatedb
Line 72: Line 71:
  
 ===== Lists ===== ===== Lists =====
-FIXME Missing an additional ​extra article about the list operators+FIXME Missing an additional article about 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>''​. 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.+=> 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! Your whole Bash script technically is one big single list!
  
 ^Operator^Description^ ^Operator^Description^
-|''<​PIPELINE1>​ **<​newline>​** <​PIPELINE2>''​|Newlines completely separate pipelines. The next pipeline is simply ​executedwithout any checks ​or specials ​(Hey! You do that every day! You enter a command and press ''<​RETURN>''​!)| +|''<​PIPELINE1>​ **<​newline>​** <​PIPELINE2>''​|Newlines completely separate pipelines. The next pipeline is executed without any checks(You enter a command and press ''<​RETURN>''​!)| 
-|''<​PIPELINE1>​ **;** <​PIPELINE2>''​|The semicolon does what ''<​newline>''​ does: It completely ​separates the pipelines| +|''<​PIPELINE1>​ **;** <​PIPELINE2>''​|The semicolon does what ''<​newline>''​ does: It 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|+|''<​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>​ **&&​** <​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)| |''<​PIPELINE1>​ **<​nowiki>​||</​nowiki>​** <​PIPELINE2>''​|''<​PIPELINE1>''​ is executed and **only** if its exit code was **not** 0 (FALSE), then ''<​PIPELINE2>''​ is executed (OR-List)|
Line 94: Line 93:
  
 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 108: 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]]|
Line 118: Line 117:
  
 ===== Shell Function Definitions ===== ===== Shell Function Definitions =====
-FIXME Missing an additional ​extra article about shell functions+FIXME Missing an additional 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.**+A shell function definition makes a [[basicgrammar#​compound_commands | compound command]] available ​via a new name. When the function ​runsit 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 more possibilities):​+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 153: 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 funtion ​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 167: 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 179: 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 191: 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 199: 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 210: Line 209:
  
 ===== 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 223: Line 221:
  
 ---- ----
-__A (very ;-)) simple command__+__A (very) simple command__
 <​code>​ <​code>​
 echo "Hello world..."​ echo "Hello world..."​
 </​code>​ </​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 234: 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 246: Line 249:
 </​code>​ </​code>​
   * the [[basicgrammar#​lists | list]] that ''​if''​ **checks** contains a [[basicgrammar#​pipelines | pipeline]] now (because of the ''​!''​)   * the [[basicgrammar#​lists | list]] that ''​if''​ **checks** contains a [[basicgrammar#​pipelines | pipeline]] now (because of the ''​!''​)
- 
  
  
  • syntax/basicgrammar.1302583933.txt
  • Last modified: 2011/04/12 04:52
  • by thebonsai