Differences between revisions 6 and 7
Revision 6 as of 2008-11-19 13:46:53
Size: 16126
Editor: GreyCat
Comment:
Revision 7 as of 2008-11-22 14:08:58
Size: 16142
Editor: localhost
Comment: converted to 1.6 markup
Deletions are marked like this. Additions are marked like this.
Line 1: Line 1:
[[Anchor(Parameters)]] <<Anchor(Parameters)>>
Line 31: Line 31:
 * '''$''': Expands to the ["PID"] (process ID number) of the current shell.
 * '''!''': Expands to the ["PID"] of the application most recently executed in the background.
 * '''$''': Expands to the [[PID]] (process ID number) of the current shell.
 * '''!''': Expands to the [[PID]] of the application most recently executed in the background.
Line 36: Line 36:
 * '''BASH_VERSION''': Contains a string describing the version of ["BASH"].  * '''BASH_VERSION''': Contains a string describing the version of [[BASH]].
Line 38: Line 38:
 * '''PPID''': Contains the ["PID"] of the parent process of this shell.  * '''PPID''': Contains the [[PID]] of the parent process of this shell.
Line 64: Line 64:
Remember that ["BASH"] is not Perl or PHP. You need to be very well aware of how ''expansion'' works to avoid '''big''' trouble. If you don't, you'll end up creating very dangerous situations in your scripts, especially when making this mistake with `rm`: Remember that [[BASH]] is not Perl or PHP. You need to be very well aware of how ''expansion'' works to avoid '''big''' trouble. If you don't, you'll end up creating very dangerous situations in your scripts, especially when making this mistake with `rm`:
Line 73: Line 73:
Imagine we have two files, `no secret` and `secret`. The first contains nothing useful, but the second contains the secret that will save the world from impending doom. Unthoughtful as you are, you forgot to '''quote''' your parameter expansion of `file`. ["BASH"] expands the parameter and the result is `rm no secret`. ["BASH"] splits the arguments up by their whitespace as it normally does, and `rm` is passed two arguments; 'no' and 'secret'. As a result, it fails to find the file `no` and it deletes the file `secret`. ''The secret is lost!''

--------
 . '''Good Practice: [[BR]] You should always keep parameter expansions well quoted. This prevents the whitespace or the possible globs inside of them from giving you gray hair or unexpectedly wiping stuff off your computer. The only good PE, is a quoted PE.'''
----
 . '''In The Manual: [http://www.gnu.org/software/bash/manual/bashref.html#SEC23 Shell Parameters], [http://www.gnu.org/software/bash/manual/bashref.html#SEC60 Shell Variables]'''
----
 . '''In the FAQ: [[BR]] [http://wooledge.org/mywiki/BashFAQ/013 How can I concatenate two variables? How do I append a string to a variable?] [[BR]] [http://wooledge.org/mywiki/BashFAQ/025 How can I access positional parameters after $9?]'''
----
 . ''Variable'': A variable is a kind of parameter that you can create and modify directly. It is denoted by a name, which must begin with a letter, and must consist only of letters, digits, and the underscore (`_`). Variable names are case-sensitive. [[BR]] ''Expansion'': Expansion happens when a parameter is prefixed by a dollar sign. ["BASH"] takes the parameter's value and replaces the parameter's expansion by its value before executing the command.
--------



[[Anchor(Variable_Types)]]
Imagine we have two files, `no secret` and `secret`. The first contains nothing useful, but the second contains the secret that will save the world from impending doom. Unthoughtful as you are, you forgot to '''quote''' your parameter expansion of `file`. [[BASH]] expands the parameter and the result is `rm no secret`. [[BASH]] splits the arguments up by their whitespace as it normally does, and `rm` is passed two arguments; 'no' and 'secret'. As a result, it fails to find the file `no` and it deletes the file `secret`. ''The secret is lost!''

--------
 . '''Good Practice: <<BR>> You should always keep parameter expansions well quoted. This prevents the whitespace or the possible globs inside of them from giving you gray hair or unexpectedly wiping stuff off your computer. The only good PE, is a quoted PE.'''
----
 . '''In The Manual: [[http://www.gnu.org/software/bash/manual/bashref.html#SEC23|Shell Parameters]], [[http://www.gnu.org/software/bash/manual/bashref.html#SEC60|Shell Variables]]'''
----
 . '''In the FAQ: <<BR>> [[http://wooledge.org/mywiki/BashFAQ/013|How can I concatenate two variables? How do I append a string to a variable?]] <<BR>> [[http://wooledge.org/mywiki/BashFAQ/025|How can I access positional parameters after $9?]]'''
----
 . ''Variable'': A variable is a kind of parameter that you can create and modify directly. It is denoted by a name, which must begin with a letter, and must consist only of letters, digits, and the underscore (`_`). Variable names are case-sensitive. <<BR>> ''Expansion'': Expansion happens when a parameter is prefixed by a dollar sign. [[BASH]] takes the parameter's value and replaces the parameter's expansion by its value before executing the command.
--------



<<Anchor(Variable_Types)>>
Line 90: Line 90:
Although ["BASH"] is not a typed language, it does have a few different types of variables. These types define the kind of content they have. They are stored in the variable's attributes. Although [[BASH]] is not a typed language, it does have a few different types of variables. These types define the kind of content they have. They are stored in the variable's attributes.
Line 108: Line 108:
As shown above, you can assign arrays using `(...)`. In this case, elements are separated by whitespace; but you can protect an element's whitespace with quotes. If you want to use some form of expansion to assign values to an array, rather than literal, be aware that ["BASH"] will obviously need to perform some form of word splitting to figure out which parts of your expansion should be put in which elements of the array: As shown above, you can assign arrays using `(...)`. In this case, elements are separated by whitespace; but you can protect an element's whitespace with quotes. If you want to use some form of expansion to assign values to an array, rather than literal, be aware that [[BASH]] will obviously need to perform some form of word splitting to figure out which parts of your expansion should be put in which elements of the array:
Line 115: Line 115:
For this word splitting, ["BASH"] looks at the first character in `IFS` again. There, it finds the delimiter to use for splitting the result of the expansion up in elements. For this word splitting, [[BASH]] looks at the first character in `IFS` again. There, it finds the delimiter to use for splitting the result of the expansion up in elements.
Line 132: Line 132:
 . ''String'': A string is a sequence of characters. [[BR]] ''Array'': An array is a list of strings that does not use a delimiter to separate them. [[BR]] ''Integer'': An integer is a form of data that can only contain digits. [[BR]] ''Read Only'': Parameters that are read-only cannot be modified or unset. [[BR]] ''Export'': Variables that are marked for export will be inherited by any subshell.
--------



[[Anchor(Parameter_Expansion)]]
 . ''String'': A string is a sequence of characters. <<BR>> ''Array'': An array is a list of strings that does not use a delimiter to separate them. <<BR>> ''Integer'': An integer is a form of data that can only contain digits. <<BR>> ''Read Only'': Parameters that are read-only cannot be modified or unset. <<BR>> ''Export'': Variables that are marked for export will be inherited by any subshell.
--------



<<Anchor(Parameter_Expansion)>>
Line 146: Line 146:
This example illustrates what basic parameter expansions look like. The second PE results in an empty string. That's because the parameter `USERs` is empty. We did not intend to have the `s` be part of the parameter name. Since there's no way for ["BASH"] to determine whether you want the `s` appended to the name of the parameter or its value you need to use curly brackets to mark the beginning and end of the parameter name. That's what we do in the third PE in our example above. This example illustrates what basic parameter expansions look like. The second PE results in an empty string. That's because the parameter `USERs` is empty. We did not intend to have the `s` be part of the parameter name. Since there's no way for [[BASH]] to determine whether you want the `s` appended to the name of the parameter or its value you need to use curly brackets to mark the beginning and end of the parameter name. That's what we do in the third PE in our example above.
Line 208: Line 208:
 . '''Good Practice: [[BR]] You may be tempted to use external applications such as `sed`, `awk`, `cut`, `perl` or others to modify your strings. Be aware that all of these require an extra process to be started, which in some cases can cause slowdowns. Parameter Expansions are the perfect alternative.'''
----
 . '''In The Manual: [http://www.gnu.org/software/bash/manual/bashref.html#SEC29 Shell Parameter Expansion]'''
----
 . '''In the FAQ: [[BR]] [http://wooledge.org/mywiki/BashFAQ/007 Is there a function to return the length of a string?] [[BR]] [http://wooledge.org/mywiki/BashFAQ/073 How can I use parameter expansion? How can I get substrings? How can I get a file without its extension, or get just a file's extension?] [[BR]] [http://wooledge.org/mywiki/BashFAQ/074 How do I get the effects of those nifty Bash Parameter Expansions in older shells?]'''
 . '''Good Practice: <<BR>> You may be tempted to use external applications such as `sed`, `awk`, `cut`, `perl` or others to modify your strings. Be aware that all of these require an extra process to be started, which in some cases can cause slowdowns. Parameter Expansions are the perfect alternative.'''
----
 . '''In The Manual: [[http://www.gnu.org/software/bash/manual/bashref.html#SEC29|Shell Parameter Expansion]]'''
----
 . '''In the FAQ: <<BR>> [[http://wooledge.org/mywiki/BashFAQ/007|Is there a function to return the length of a string?]] <<BR>> [[http://wooledge.org/mywiki/BashFAQ/073|How can I use parameter expansion? How can I get substrings? How can I get a file without its extension, or get just a file's extension?]] <<BR>> [[http://wooledge.org/mywiki/BashFAQ/074|How do I get the effects of those nifty Bash Parameter Expansions in older shells?]]'''

Parameters

Parameters should be seen as a sort of named space in memory where you can store your data. Generally speaking, they will store string data, but can also be used to store integers or arrays.


  • Parameters: Parameters store data that can be retrieved through a symbol or a name.


Special Parameters and Variables

Let's get our vocabulary straight before we get into the real deal. There are Parameters and Variables. Variables are actually just a kind of parameters: parameters that are denoted by a name. Parameters that aren't variables are called Special Parameters. I'm sure you'll understand things better with a few examples:

    $ # Some parameters that aren't variables:
    $ echo My shell is $0, and was started with these options: $-
    My shell is -bash, and was started with these options: himB
    $ # Some parameters that ARE variables:
    $ echo I am $LOGNAME, and I live at $HOME.
    I am lhunath, and I live at /home/lhunath.

Please note: Unlike PHP/Perl/... parameters do NOT start with a $-sign. The $-sign you see in the examples merely causes the parameter that follows it to be expanded. Expansion basically means that the shell replaces it by its content. As such, LOGNAME is the parameter (variable), that contains your username. $LOGNAME will be replaced with its content; which in my case, is lhunath.

I think you've got the drift now. Here's a summary of most Special Parameters:

  • 0: Contains the name of the script. (This is not always reliable.)

  • Positional Parameters: 1, 2, ...; They contain the arguments that were passed to the current script.

  • *: Expands to all the words of all the positional parameters. If double quoted, it expands to a single string containing all the positional parameters separated by the first character of the IFS variable (which will be discussed later).

  • @: Expands to all the words of all the positional parameters. If double quoted, it expands to a list of all the positional parameters as individual words.

  • #: Expands to the number of positional parameters that are currently set.

  • ?: Expands to the exit code of the most recently completed foreground command.

  • $: Expands to the PID (process ID number) of the current shell.

  • !: Expands to the PID of the application most recently executed in the background.

  • _: Expands to the last argument of the last command that was executed.

And here are some examples of Variables that the shell initializes for you:

  • BASH_VERSION: Contains a string describing the version of BASH.

  • HOSTNAME: Contains the hostname of your computer, I swear.

  • PPID: Contains the PID of the parent process of this shell.

  • PWD: Contains the current directory.

  • RANDOM: Each time you expand this variable, a random number between 0 and 32767 is generated.

  • UID: The ID number of the current user.

  • COLUMNS: The number of characters that fit on one line in your terminal. (The width of your terminal in characters.)

  • LINES: The number of lines that fit in your terminal. (The height of your terminal in lines.)

  • HOME: The current user's home directory.

  • PATH: A colon-separated list of paths that will be searched to find the executable for a command that is executed, if it is not an alias, function or builtin command (or absolutely referenced).

  • PS1: Contains a string that describes the format of your shell prompt.

  • TMPDIR: Contains the directory that is used to store temporary files (by the shell).

Of course, you aren't restricted to only these variables. Feel free to define your own:

    $ country=Canada
    $ echo "I am $LOGNAME and I currently live in $country."
    I am lhunath and I currently live in Canada.

Notice what we did to assign the value Canada to the variable country. Remember that you are NOT allowed to have any spaces before or after that equals sign!

    $ language = PHP
    -bash: language: command not found
    $ language=PHP
    $ echo "I'm far too used to $language."
    I'm far too used to PHP.

Remember that BASH is not Perl or PHP. You need to be very well aware of how expansion works to avoid big trouble. If you don't, you'll end up creating very dangerous situations in your scripts, especially when making this mistake with rm:

    $ ls
    no secret  secret
    $ file='no secret'
    $ rm $file
    rm: cannot remove `no': No such file or directory

Imagine we have two files, no secret and secret. The first contains nothing useful, but the second contains the secret that will save the world from impending doom. Unthoughtful as you are, you forgot to quote your parameter expansion of file. BASH expands the parameter and the result is rm no secret. BASH splits the arguments up by their whitespace as it normally does, and rm is passed two arguments; 'no' and 'secret'. As a result, it fails to find the file no and it deletes the file secret. The secret is lost!


  • Good Practice:
    You should always keep parameter expansions well quoted. This prevents the whitespace or the possible globs inside of them from giving you gray hair or unexpectedly wiping stuff off your computer. The only good PE, is a quoted PE.




  • Variable: A variable is a kind of parameter that you can create and modify directly. It is denoted by a name, which must begin with a letter, and must consist only of letters, digits, and the underscore (_). Variable names are case-sensitive.
    Expansion: Expansion happens when a parameter is prefixed by a dollar sign. BASH takes the parameter's value and replaces the parameter's expansion by its value before executing the command.


Variable Types

Although BASH is not a typed language, it does have a few different types of variables. These types define the kind of content they have. They are stored in the variable's attributes.

Attributes are settings for a variable. They define the way the variable will behave. Here are the attributes you can assign to a variable:

  • Array: (declare -a [variable]): The variable is an array of strings.

  • Integer: (declare -i [variable]): The variable holds an integer. Assigning values to this variable automatically triggers Arithmetic Evaluation.

  • Read Only: (declare -r [variable]): The variable can no longer be modified or unset.

  • Export: (declare -x [variable]): The variable is marked for export which means it will be inherited by any subshell.

Arrays are basically lists of strings. They are very convenient for their ability to store different elements without relying on a delimiter. That way, you don't need to worry about the fact that this delimiter could possibly end up being part of an element's content and thus split that element up:

    $ files='one:two:three:four'

Here we try to use a string to contain a list of files. To do that, we need to rely on a delimiter to keep the files apart. We choose ':'. As a result, we cannot add any files to the list that have a ':' in their filename. That's why arrays are so convenient:

    $ files=( 'one' 'two' 'three' 'four' '5: five' )

As shown above, you can assign arrays using (...). In this case, elements are separated by whitespace; but you can protect an element's whitespace with quotes. If you want to use some form of expansion to assign values to an array, rather than literal, be aware that BASH will obviously need to perform some form of word splitting to figure out which parts of your expansion should be put in which elements of the array:

    $ files='one:two:three:four'
    $ IFS=:
    $ files=( $files )

For this word splitting, BASH looks at the first character in IFS again. There, it finds the delimiter to use for splitting the result of the expansion up in elements.

Defining variables as integers has the advantage that you can leave out some syntax when trying to assign or modify them:

    $ a=5; a+=2; echo $a; unset a
    52
    $ a=5; let a+=2; echo $a; unset a
    7
    $ declare -i a=5; a+=2; echo $a; unset a
    7
    $ a=5+2; echo $a; unset a
    5+2
    $ declare -i a=5+2; echo $a; unset a
    7


  • String: A string is a sequence of characters.
    Array: An array is a list of strings that does not use a delimiter to separate them.
    Integer: An integer is a form of data that can only contain digits.
    Read Only: Parameters that are read-only cannot be modified or unset.
    Export: Variables that are marked for export will be inherited by any subshell.


Parameter Expansion

Parameter Expansion is the term that refers to any operation that causes a parameter to be expanded (replaced by content). In its most basic appearance, the parameter expansion of a parameter is achieved by prefixing that parameter with a $ sign. In certain situations, additional curly brackets around the parameter's name are required:

    $ echo "'$USER', '$USERs', '${USER}s'"
    'lhunath', '', 'lhunaths'

This example illustrates what basic parameter expansions look like. The second PE results in an empty string. That's because the parameter USERs is empty. We did not intend to have the s be part of the parameter name. Since there's no way for BASH to determine whether you want the s appended to the name of the parameter or its value you need to use curly brackets to mark the beginning and end of the parameter name. That's what we do in the third PE in our example above.

Parameter Expansion can also be used to modify the string that will be expanded. These operations are terribly convenient:

    $ for file in *.JPG *.jpeg
    > do mv "$file" "${file%.*}.jpg"
    > done

The code above can be used to rename all JPEG files with a JPG or a jpeg extension to have a normal jpg extension. The PE (${file%.*}) cuts off everything from the end until it finds a period (.). Then, in the same quotes, a new extension is appended to the expansion result.

Here's a summary of most PEs that are available:

  • ${parameter:-word}: Use Default Values. If 'parameter' is unset or null, the expansion of 'word' is substituted. Otherwise, the value of 'parameter' is substituted.

  • ${parameter:=word}: Assign Default Values. If 'parameter' is unset or null, the expansion of 'word' is assigned to 'parameter'. The value of 'parameter' is then substituted.

  • ${parameter:?word}: Display Error if Null or Unset. If 'parameter' is null or unset, the expansion of 'word' (or a message to that effect if 'word' is not present) is written to the standard error and the shell, if it is not interactive, exits. Otherwise, the value of 'parameter' is substituted.

  • ${parameter:+word}: Use Alternate Value. If 'parameter' is null or unset, nothing is substituted, otherwise the expansion of 'word' is substituted.

  • ${parameter:offset:length} Substring Expansion. Expands to up to 'length' characters of 'parameter' starting at the character specified by 'offset'. If 'length' is omitted, expands to the substring of 'parameter' starting at the character specified by 'offset'.

  • ${#parameter}: The length in characters of the value of 'parameter' is substituted.

  • ${parameter#pattern}: The 'pattern' is anchored to the beginning of 'parameter'. The result of the expansion is the expanded value of 'parameter' with the shortest match deleted.

  • ${parameter##pattern}: The 'pattern' is anchored to the beginning of 'parameter'. The result of the expansion is the expanded value of 'parameter' with the longest match deleted.

  • ${parameter%pattern}: The 'pattern' is anchored to the end of 'parameter'. The result of the expansion is the expanded value of 'parameter' with the shortest match deleted.

  • ${parameter%%pattern}: The 'pattern' is anchored to the end of 'parameter'. The result of the expansion is the expanded value of 'parameter' with the longest match deleted.

  • ${parameter/pattern/string}: The 'pattern' is not anchored but evaluated from left to right in the value of 'parameter'. The result of the expansion is the expanded value of 'parameter' with the first match of 'pattern' replaced by 'string'.

  • ${parameter//pattern/string}: As above, but every match of 'pattern' is replaced.

You will learn them all through experience. They will come in handy far more often than you think they might. Here's a few examples to kickstart you:

    $ file="$HOME/.secrets/007"; \
    > echo "File location: $file"; \
    > echo "Filename: ${file##*/}"; \
    > echo "Directory of file: ${file%/*}"; \
    > echo "Non-secret file: ${file/secrets/not_secret}"; \
    > echo; \
    > echo "Other file location: ${other:-There is no other file}"; \
    > echo "Using file if there is no other file: ${other:=$file}"; \
    > echo "Other filename: ${other##*/}"; \
    > echo "Other file location length: ${#other}"
    File location: /home/lhunath/.secrets/007
    Filename: 007
    Directory of file: /home/lhunath/.secrets
    Non-secret file: /home/lhunath/.not_secret/007
    Other file location: There is no other file
    Using file if there is no other file: /home/lhunath/.secrets/007
    Other filename: 007
    Other file location length: 26

Remember the difference between ${v#p} and ${v##p}. The doubling of the # character means metacharacters will become greedy. The same goes for %:

    $ version=1.5.9; echo "MAJOR: ${version%%.*}, MINOR: ${version#*.}."
    MAJOR: 1, MINOR: 5.9.
    $ echo "Dash: ${version/./-}, Dashes: ${version//./-}."
    Dash: 1-5.9, Dashes: 1-5-9.

Note: You cannot nest PEs together. If you need to execute multiple PEs on a parameter, you will need to use multiple statements:

    $ file=$HOME/image.jpg; file=${file##*/}; echo "${file%.*}"
    image


  • Good Practice:
    You may be tempted to use external applications such as sed, awk, cut, perl or others to modify your strings. Be aware that all of these require an extra process to be started, which in some cases can cause slowdowns. Parameter Expansions are the perfect alternative.




  • Parameter Expansion: Any expansion (see earlier definition) of a parameter. Certain operations are possible during this expansion that are performed on the value that will be expanded.


BashGuide/Parameters (last edited 2017-04-07 00:32:44 by pool-71-188-87-188)