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
scripting:posparams [2012/02/01 14:42]
jaalto Fix topo in code comment
scripting:posparams [2018/05/12 20:04] (current)
wayeoyuz Typo
Line 6: Line 6:
 ===== Intro ===== ===== Intro =====
  
-The day will come when you want to give arguments to your scripts. These arguments are reflected ​as the **positional parameters** ​inside your scriptMost relevant special parameters are described below:+The day will come when you want to give arguments to your scripts. These arguments are known as **positional parameters**. ​Some relevant special parameters are described below:
 ^Parameter(s)^Description^ ^Parameter(s)^Description^
 |''​$0''​|the first positional parameter, equivalent to ''​argv[0]''​ in C, see [[scripting:​posparams#​the_first_argument | the first argument]]| |''​$0''​|the first positional parameter, equivalent to ''​argv[0]''​ in C, see [[scripting:​posparams#​the_first_argument | the first argument]]|
Line 18: Line 18:
  
 These positional parameters reflect exactly what was given to the These positional parameters reflect exactly what was given to the
-script when it was called. ​There are no special things interpreted:​ +script when it was called. 
-Option-switch parsing (''​-h''​ for displaying help) is not done in this + 
-stage.+Option-switch parsing (e.g. ''​-h''​ for displaying help) is not performed at 
 +this point.
  
 See also [[dict:​terms:​parameter | the dictionary entry for "​parameter"​]]. See also [[dict:​terms:​parameter | the dictionary entry for "​parameter"​]].
Line 27: Line 28:
 ===== The first argument ===== ===== The first argument =====
  
-The very first argument you can access is referenced ​by ''​$0''​. It +The very first argument you can access is referenced ​as ''​$0''​. It 
-usually ​is set to the script'​s name exactly ​like it was called, and +is usually ​set to the script'​s name exactly ​as called, and it's 
-it's set on shell initialization:​+set on shell initialization:​
  
 __Testscript__ - it just echos ''​$0'':​ __Testscript__ - it just echos ''​$0'':​
Line 36: Line 37:
 echo "​$0"​ echo "​$0"​
 </​code>​ </​code>​
-You see, ''​$0''​ is always set to however you call that script (''​$''​ is the prompt...):+You see, ''​$0''​ is always set to the name the script ​is called with (''​>''​ is the prompt...):
 <​code>​ <​code>​
 > ./​testscript ​ > ./​testscript ​
Line 52: Line 53:
 </​code>​ </​code>​
  
-Alsoto be over-exact: ​''​$0''​ is not a positional parameter, it's a +In other terms, ''​$0''​ is not a positional parameter, it's a 
-special parameter independent from the real parameter list. Also it +special parameter independent from the positional ​parameter list. It 
-really ​can be set to anything. In the **ideal** case it's the pathname +can be set to anything. In the **ideal** case it's the pathname 
-of the script, but since this is set on invocation, the invoking+of the script, but since this gets set on invocation, the invoking
 program can easily influence it (the ''​login''​ program does that for program can easily influence it (the ''​login''​ program does that for
-login shells, by prepending ​a dash, for example).+login shells, by prefixing ​a dash, for example).
  
-Inside a function, ''​$0''​ still reflects what was described above. To+Inside a function, ''​$0''​ still behaves as described above. To
 get the function name, use ''​$FUNCNAME''​. get the function name, use ''​$FUNCNAME''​.
  
Line 71: Line 72:
   * in general: ''​$N''​ will become ''​$N-1''​   * in general: ''​$N''​ will become ''​$N-1''​
  
-The command can take a number as argument: ​How many positions to shift. +The command can take a number as argument: ​Number of positions to shift. 
- So, a ''​shift 4'' ​will shift ''​$5''​ to ''​$1''​.+ e.g. ''​shift 4'' ​shifts ​''​$5''​ to ''​$1''​.
  
 ===== Using them ===== ===== Using them =====
Line 91: Line 92:
 </​code>​ </​code>​
  
-Well, it might be useful in one or the other situation, ​but this way +While useful in another ​situation, this way is lacks flexibility. 
-is not very flexibleYou're fixed in your maximum number of arguments+The maximum number of arguments ​is a fixedvalue
 - which is a bad idea if you write a script that takes many filenames - which is a bad idea if you write a script that takes many filenames
 as arguments. as arguments.
Line 98: Line 99:
 => forget that one => forget that one
  
-==== Loopings ​====+==== Loops ====
  
 There are several ways to loop through the positional parameters. There are several ways to loop through the positional parameters.
Line 105: Line 106:
  
 You can code a [[syntax:​ccmd:​c_for | C-style for-loop]] using ''​$#''​ You can code a [[syntax:​ccmd:​c_for | C-style for-loop]] using ''​$#''​
-as end-value. On every iteration, the ''​shift''​-command is used to+as the end value. On every iteration, the ''​shift''​-command is used to
 shift the argument list: shift the argument list:
  
Line 117: Line 118:
 </​code>​ </​code>​
  
-Not very stylish, but okay, usable. The ''​numargs''​ variable is used +Not very stylish, but usable. The ''​numargs''​ variable is used 
-to store the initial value of ''​$#''​ because ​it will change ​due to the +to store the initial value of ''​$#''​ because ​the shift command 
-shifting.+will change ​it as the script runs.
  
 ---- ----
  
-Another way to iterate one-by-one ​is the ''​for''​-loop without given +Another way to iterate one argument at a time is the ''​for''​ loop 
-wordlist, it will use the positional parameters as wordlist ​then:+without ​given wordlist. The loop uses the positional parameters as wordlist:
  
 <​code>​ <​code>​
Line 132: Line 133:
 done done
 </​code>​ </​code>​
-__Advantage:​__ The positional parameters will be preserved ​and not shifted into nirvana!+__Advantage:​__ The positional parameters will be preserved
  
 ---- ----
  
-The next way is similar to the first example (the ''​for''​-loop), but+The next method ​is similar to the first example (the ''​for''​ loop), but
 it doesn'​t test for reaching ''​$#''​. It shifts and checks if ''​$1''​ it doesn'​t test for reaching ''​$#''​. It shifts and checks if ''​$1''​
 still expands to something, using the [[commands:​classictest | test command]]: still expands to something, using the [[commands:​classictest | test command]]:
Line 148: Line 149:
 </​code>​ </​code>​
  
-Looks nice, but it has the disadvantage ​to stop when ''​$1''​ is empty+Looks nice, but has the disadvantage ​of stopping ​when ''​$1''​ is empty
 (null-string). Let's modify it to run as long as ''​$1''​ is defined (null-string). Let's modify it to run as long as ''​$1''​ is defined
-(but may be empty), using [[syntax:​pe#​use_an_alternate_value | parameter expansion for an alternate value]]:+(but may be null), using [[syntax:​pe#​use_an_alternate_value | parameter expansion for an alternate value]]:
  
 <​code>​ <​code>​
Line 167: Line 168:
 ==== All Positional Parameters ==== ==== All Positional Parameters ====
  
-Sometimes it's necessary to just "​relay"​ or "hand through" given+Sometimes it's necessary to just "​relay"​ or "pass" given
 arguments to another program. It's very inefficient to do that in one arguments to another program. It's very inefficient to do that in one
-of these loops, ​also you will destroy integrity, most likely+of these loops, ​as you will destroy integrity, most likely
 (spaces!). (spaces!).
  
-The shell-developers ​invented ​''​$*''​ and ''​$@''​ for this purpose.+The shell developers ​created ​''​$*''​ and ''​$@''​ for this purpose.
  
-As overwiew:+As overview:
  
 ^Syntax ​     ^Effective result ​                ^ ^Syntax ​     ^Effective result ​                ^
Line 182: Line 183:
 |  ''"​$@"'' ​ |  ''"​$1"​ "​$2"​ "​$3"​ ... "​${N}"'' ​ | |  ''"​$@"'' ​ |  ''"​$1"​ "​$2"​ "​$3"​ ... "​${N}"'' ​ |
  
-You see that without ​being quoted (double-quoted), both have the same +Without ​being quoted (double ​quotes), both have the same 
-effect: All positional parameters from ''​$1''​ to the last used one are +effect: All positional parameters from ''​$1''​ to the last one used are 
-expanded without any specials. A subsequent wordsplitting will +expanded without any special handling.
-recognize as much words as expanded before (i.e. it "​doesn'​t preserve +
-words"​).+
  
-When the ''​$*''​ special parameter is doublequoted, it expands to the+When the ''​$*''​ special parameter is double quoted, it expands to the
 equivalent of: ''"​$1c$2c$3c$4c........$N"'',​ where '​c'​ is the first equivalent of: ''"​$1c$2c$3c$4c........$N"'',​ where '​c'​ is the first
 character of ''​IFS''​. character of ''​IFS''​.
  
-But when the ''​$@''​ special parameter is used inside ​doublequotes, it+But when the ''​$@''​ special parameter is used inside ​double quotes, it
 expands to the equivanent of... expands to the equivanent of...
  
 ''"​$1"​ "​$2"​ "​$3"​ "​$4"​ ..... "​$N"''​ ''"​$1"​ "​$2"​ "​$3"​ "​$4"​ ..... "​$N"''​
  
-...which **exactly ​reflects all positional parameters ​like they were +...which **reflects all positional parameters ​as they were 
-initially ​set** and given to the script or the function. If you want+set initially** and passed ​to the script or function. If you want
 to re-use your positional parameters to **call another program** (for to re-use your positional parameters to **call another program** (for
-example in a wrapper-script),​ then this is the choice for you, use the +example in a wrapper-script),​ then this is the choice for you, use 
-doublequoted ​''"​$@"''​.+double quoted ​''"​$@"''​.
  
 Well, let's just say: **You almost always want a quoted ''"​$@"''​!** Well, let's just say: **You almost always want a quoted ''"​$@"''​!**
Line 207: Line 206:
 ==== Range Of Positional Parameters ==== ==== Range Of Positional Parameters ====
  
-Another way to mass-expand the positional parameters is similar to +Another way to mass expand the positional parameters is similar to 
-what is possible for a range of characters using the+what is possible for a range of characters using
 [[syntax:​pe#​substring_expansion | substring expansion]] on normal [[syntax:​pe#​substring_expansion | substring expansion]] on normal
-parameters and the range mass expansion of [[syntax:​arrays | arrays]].+parameters and the mass expansion ​range of [[syntax:​arrays | arrays]].
  
 ''​${@:​START:​COUNT}''​ ''​${@:​START:​COUNT}''​
Line 220: Line 219:
 ''"​${*:​START:​COUNT}"''​ ''"​${*:​START:​COUNT}"''​
  
-The rules for using ''​@''​ or ''​*''​ and the quoting are the same as+The rules for using ''​@''​ or ''​*''​ and quoting are the same as
 above. This will expand ''​COUNT''​ number of positional parameters above. This will expand ''​COUNT''​ number of positional parameters
-starting ​at ''​START''​. ''​COUNT''​ can be omitted (''​${@:​START}''​),​ in +beginning ​at ''​START''​. ''​COUNT''​ can be omitted (''​${@:​START}''​),​ in 
-this case all positional parameters beginning at ''​START''​ are+which caseall positional parameters beginning at ''​START''​ are
 expanded. expanded.
  
-If ''​START''​ is negative, the positional parameters are numbered ​from +If ''​START''​ is negative, the positional parameters are numbered ​in reverse 
-the last one backwards.+starting with the last one.
  
-''​COUNT''​ may not be negative, ​so elements are always counted in the +''​COUNT''​ may not be negative, ​i.e. the element count may not be decremented.
-forward direction.+
  
 __**Example:​**__ __**Example:​**__
Line 238: Line 236:
 </​code>​ </​code>​
  
-:V4: __**Attention**__: ​Since Bash 4, a ''​START''​ of ''​0''​ includes the special parameter ''​$0'',​ i.e. the shell name or whatever ​it'​s ​set to, when the positional parameters are in use. A ''​START''​ of ''​1''​ begins at ''​$1''​. In Bash 3 and older, both ''​0''​ and ''​1''​ began at ''​$1''​.+__**Attention**__: ​As of Bash 4, a ''​START''​ of ''​0''​ includes the special parameter ''​$0'',​ i.e. the shell name or whatever ​$0 is set to, when the positional parameters are in use. A ''​START''​ of ''​1''​ begins at ''​$1''​. In Bash 3 and older, both ''​0''​ and ''​1''​ began at ''​$1''​.
  
 ===== Setting Positional Parameters ===== ===== Setting Positional Parameters =====
  
-Letting the caller set the positional parameters, ​by giving parameters +Setting ​positional parameters ​with command line arguments
-on commandline, ​is not the only way to set them. +is not the only way to set them. 
-The [[ commands:​builtin:​set | set builtin command ]] +The [[ commands:​builtin:​set | builtin command, set ]] 
-can be used to "​artificially"​ change the positional parameters from+may be used to "​artificially"​ change the positional parameters from
 inside the script or function: inside the script or function:
  
Line 261: Line 259:
  
 It's wise to signal "end of options"​ when setting positional It's wise to signal "end of options"​ when setting positional
-parameters this way. If not, dashes might be interpreted as option ​tag+parameters this way. If not, the dashes might be interpreted as an option ​switch
 by ''​set''​ itself: by ''​set''​ itself:
  
Line 268: Line 266:
 set -- ... set -- ...
 set - ... set - ...
 +</​code>​
 +
 +Alternately this will also preserve any verbose (-v) or tracing (-x) flags, which may otherwise be reset by ''​set''​
 +<​code>​
 +set -$- ...
 </​code>​ </​code>​
  
Line 276: Line 279:
 ==== Using a while loop ==== ==== Using a while loop ====
  
-To make your program accept options ​like standard command ​with syntax:+To make your program accept options ​as standard command syntax:
  
 ''​COMMAND [options] <​params>'' ​ # Like 'cat -A file.txt'​ ''​COMMAND [options] <​params>'' ​ # Like 'cat -A file.txt'​
Line 286: Line 289:
 <​code>​ <​code>​
 #!/bin/sh #!/bin/sh
-By keeping ​options in alphabetical orderit'​s ​easy to add more.+Keeping ​options in alphabetical order makes it easy to add more.
  
 while : while :
Line 306: Line 309:
       -v | --verbose)       -v | --verbose)
           #  It's better to assign a string, than a number like "​verbose=1"​           #  It's better to assign a string, than a number like "​verbose=1"​
-   #  because if you're debugging script with "bash -x" code like this:+   #  because if you're debugging ​the script with "bash -x" code like this:
    #    #
    #    if [ "​$verbose"​ ] ...    #    if [ "​$verbose"​ ] ...
Line 339: Line 342:
 ==== Filter unwanted options with a wrapper script ==== ==== Filter unwanted options with a wrapper script ====
  
-This simple wrapper ​allows to filter ​unwanted options (here: ''​-a''​ +This simple wrapper ​enables filtering ​unwanted options (here: ''​-a''​ 
-and ''​--all''​ for ''​ls''​) out of the commandline. It reads the +and ''​--all''​ for ''​ls''​) out of the command line. It reads the 
-positional parameters and builds a (filteredarray out of them, then +positional parameters and builds a filtered array consisting ​of them, then 
-it calls ''​ls''​ with the new option set. It also respects the ''​--''​+calls ''​ls''​ with the new option set. It also respects the ''​--''​
 as "end of options"​ for ''​ls''​ and doesn'​t change anything after it: as "end of options"​ for ''​ls''​ and doesn'​t change anything after it: