Differences
This shows you the differences between two versions of the page.
Both sides previous revision Previous revision Next revision | Previous revision | ||
scripting:posparams [2013/04/14 12:39] thebonsai Don't tread version 4 special - it has been around for a long time now |
scripting:posparams [2018/05/12 18: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 script. Most 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> | ||
- | Also, to 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 flexible. You'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 a given wordlist. The loop uses the positional parameters as a 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 case, all 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> | ||
- | __**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 order, it'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 (filtered) array 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: | ||