Skip to content

Instantly share code, notes, and snippets.

@Kouni
Forked from mohanpedala/bash_strict_mode.md
Created May 27, 2022 03:11
Show Gist options
  • Save Kouni/8cecdccc8c7c5ea6e685e8ad93015f16 to your computer and use it in GitHub Desktop.
Save Kouni/8cecdccc8c7c5ea6e685e8ad93015f16 to your computer and use it in GitHub Desktop.

Revisions

  1. @mohanpedala mohanpedala revised this gist Oct 29, 2021. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion bash_strict_mode.md
    Original file line number Diff line number Diff line change
    @@ -146,4 +146,4 @@ Or consider a script that takes filenames as command line arguments:
    * By default, bash sets this to $' \n\t' - space, newline, tab - which is too eager.
    ## Original Reference
    * Maxwell, A. Unofficial-bash-strict-mode. Retrieved 2018, from http://redsymbol.net/articles/unofficial-bash-strict-mode/
    * **Maxwell, A. Unofficial-bash-strict-mode. Retrieved 2018, from http://redsymbol.net/articles/unofficial-bash-strict-mode/**
  2. @mohanpedala mohanpedala revised this gist Oct 29, 2021. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion bash_strict_mode.md
    Original file line number Diff line number Diff line change
    @@ -146,4 +146,4 @@ Or consider a script that takes filenames as command line arguments:
    * By default, bash sets this to $' \n\t' - space, newline, tab - which is too eager.
    ## Original Reference
    * Maxwell, A. (2017). Unofficial-bash-strict-mode. Retrieved 2018, from http://redsymbol.net/articles/unofficial-bash-strict-mode/
    * Maxwell, A. Unofficial-bash-strict-mode. Retrieved 2018, from http://redsymbol.net/articles/unofficial-bash-strict-mode/
  3. @mohanpedala mohanpedala revised this gist Oct 29, 2021. 1 changed file with 2 additions and 2 deletions.
    4 changes: 2 additions & 2 deletions bash_strict_mode.md
    Original file line number Diff line number Diff line change
    @@ -5,7 +5,7 @@
    - [set -u](#set--u)
    - [set -o pipefail](#set--o-pipefail)
    - [Setting IFS](#setting-ifs)
    - [Citations](#citations)
    - [Original Reference](#original-reference)

    #### set -e, -u, -x, -o pipefail

    @@ -145,5 +145,5 @@ Or consider a script that takes filenames as command line arguments:
    * Setting IFS to $'\n\t' means that word splitting will happen only on newlines and tab characters. This very often produces useful splitting behavior.
    * By default, bash sets this to $' \n\t' - space, newline, tab - which is too eager.
    ## Citations
    ## Original Reference
    * Maxwell, A. (2017). Unofficial-bash-strict-mode. Retrieved 2018, from http://redsymbol.net/articles/unofficial-bash-strict-mode/
  4. @mohanpedala mohanpedala revised this gist Oct 29, 2021. 1 changed file with 8 additions and 8 deletions.
    16 changes: 8 additions & 8 deletions bash_strict_mode.md
    Original file line number Diff line number Diff line change
    @@ -1,11 +1,11 @@
    # Table of Contents
    * [set -e, -u, -x, -o pipefail](#set--e---u---x---o-pipefail)
    * [set -e](#set--e-)
    * [set -x](#set--x-)
    * [set -u](#set--u-)
    * [set -o pipefail](#set--o-pipefail-)
    * [Setting IFS](#setting-ifs)
    * [Citation:](#citation-)
    - [set -e, -u, -x, -o pipefail](#set--e--u--x--o-pipefail)
    - [set -e](#set--e)
    - [set -x](#set--x)
    - [set -u](#set--u)
    - [set -o pipefail](#set--o-pipefail)
    - [Setting IFS](#setting-ifs)
    - [Citations](#citations)

    #### set -e, -u, -x, -o pipefail

    @@ -145,5 +145,5 @@ Or consider a script that takes filenames as command line arguments:
    * Setting IFS to $'\n\t' means that word splitting will happen only on newlines and tab characters. This very often produces useful splitting behavior.
    * By default, bash sets this to $' \n\t' - space, newline, tab - which is too eager.
    ## Citation:
    ## Citations
    * Maxwell, A. (2017). Unofficial-bash-strict-mode. Retrieved 2018, from http://redsymbol.net/articles/unofficial-bash-strict-mode/
  5. @mohanpedala mohanpedala revised this gist Oct 29, 2021. 1 changed file with 7 additions and 7 deletions.
    14 changes: 7 additions & 7 deletions bash_strict_mode.md
    Original file line number Diff line number Diff line change
    @@ -1,11 +1,11 @@
    # Table of Contents
    + [set -e, -u, -x, -o pipefail](#set--e---u---x---o-pipefail)
    + [set -e](#set--e)
    + [set -x](#set--x)
    + [set -u](#set--u)
    + [set -o pipefail](#set--o-pipefail)
    + [Setting IFS](#setting-ifs)
    - [Citation:](#citation-)
    * [set -e, -u, -x, -o pipefail](#set--e---u---x---o-pipefail)
    * [set -e](#set--e-)
    * [set -x](#set--x-)
    * [set -u](#set--u-)
    * [set -o pipefail](#set--o-pipefail-)
    * [Setting IFS](#setting-ifs)
    * [Citation:](#citation-)

    #### set -e, -u, -x, -o pipefail

  6. @mohanpedala mohanpedala revised this gist Oct 29, 2021. 1 changed file with 7 additions and 8 deletions.
    15 changes: 7 additions & 8 deletions bash_strict_mode.md
    Original file line number Diff line number Diff line change
    @@ -1,12 +1,11 @@
    # Table of Contents
    * [set -e, -u, -x, -o pipefail](#set--e---u---x---o-pipefail)
    - [`set -euxo pipefail` is short for:](#-set--euxo-pipefail--is-short-for-)
    - [`set -e`](#-set--e-)
    - [`set -x`](#-set--x-)
    - [`set -u`](#-set--u-)
    - [`set -o pipefail`](#-set--o-pipefail-)
    - [Setting IFS](#setting-ifs)
    * [Citation:](#citation-)
    + [set -e, -u, -x, -o pipefail](#set--e---u---x---o-pipefail)
    + [set -e](#set--e)
    + [set -x](#set--x)
    + [set -u](#set--u)
    + [set -o pipefail](#set--o-pipefail)
    + [Setting IFS](#setting-ifs)
    - [Citation:](#citation-)

    #### set -e, -u, -x, -o pipefail

  7. @mohanpedala mohanpedala revised this gist Oct 29, 2021. 1 changed file with 32 additions and 33 deletions.
    65 changes: 32 additions & 33 deletions bash_strict_mode.md
    Original file line number Diff line number Diff line change
    @@ -7,14 +7,14 @@
    - [`set -o pipefail`](#-set--o-pipefail-)
    - [Setting IFS](#setting-ifs)
    * [Citation:](#citation-)
    ## set -e, -u, -x, -o pipefail

    #### set -e, -u, -x, -o pipefail

    * The `set` lines
    - These lines deliberately cause your script to fail. Wait, what? Believe me, this is a good thing.
    - With these settings, certain common errors will cause the script to immediately fail, explicitly and loudly. Otherwise, you can get hidden bugs that are discovered only when they blow up in production.

    #### `set -euxo pipefail` is short for:
    `set -euxo pipefail` is short for:
    ```
    set -e
    set -u
    @@ -23,33 +23,33 @@
    ```
    #### `set -e`
    * The `set -e` option instructs bash to immediately exit if any command [1] has a non-zero exit status. You wouldn't want to set this for your command-line shell, but in a script it's massively helpful. In all widely used general-purpose programming languages, an unhandled runtime error
    - whether that's a thrown exception in Java, or a segmentation fault in C, or a syntax error in Python - immediately halts execution of the program; subsequent lines are not executed.
    #### set -e
    * The `set -e` option instructs bash to immediately exit if any command [1] has a non-zero exit status. You wouldn't want to set this for your command-line shell, but in a script it's massively helpful. In all widely used general-purpose programming languages, an unhandled runtime error
    - whether that's a thrown exception in Java, or a segmentation fault in C, or a syntax error in Python - immediately halts execution of the program; subsequent lines are not executed.
    - By default, bash does not do this. This default behavior is exactly what you want if you are using bash on the command line
    - you don't want a typo to log you out! But in a script, you really want the opposite.
    - If one line in a script fails, but the last line succeeds, the whole script has a successful exit code. That makes it very easy to miss the error.
    - Again, what you want when using bash as your command-line shell and using it in scripts are at odds here. Being intolerant of errors is a lot better in scripts, and that's what set -e gives you.
    - By default, bash does not do this. This default behavior is exactly what you want if you are using bash on the command line
    - you don't want a typo to log you out! But in a script, you really want the opposite.
    - If one line in a script fails, but the last line succeeds, the whole script has a successful exit code. That makes it very easy to miss the error.
    - Again, what you want when using bash as your command-line shell and using it in scripts are at odds here. Being intolerant of errors is a lot better in scripts, and that's what set -e gives you.
    #### `set -x`
    * Enables a mode of the shell where all executed commands are printed to the terminal. In your case it's clearly used for debugging, which is a typical use case for set -x : printing every command as it is executed may help you to visualize the control flow of the script if it is not functioning as expected.
    #### set -x
    * Enables a mode of the shell where all executed commands are printed to the terminal. In your case it's clearly used for debugging, which is a typical use case for set -x : printing every command as it is executed may help you to visualize the control flow of the script if it is not functioning as expected.
    #### `set -u`
    * Affects variables. When set, a reference to any variable you haven't previously defined - with the exceptions of $* and $@ - is an error, and causes the program to immediately exit. Languages like Python, C, Java and more all behave the same way, for all sorts of good reasons. One is so typos don't create new variables without you realizing it. For example:
    #### set -u
    * Affects variables. When set, a reference to any variable you haven't previously defined - with the exceptions of $* and $@ - is an error, and causes the program to immediately exit. Languages like Python, C, Java and more all behave the same way, for all sorts of good reasons. One is so typos don't create new variables without you realizing it. For example:
    ```
    #!/bin/bash
    firstName="Aaron"
    fullName="$firstname Maxwell"
    echo "$fullName"
    ```
    * Take a moment and look. Do you see the error? The right-hand side of the third line says "firstname", all lowercase, instead of the camel-cased "firstName". Without the -u option, this will be a silent error. But with the -u option, the script exits on that line with an exit code of 1, printing the message "firstname: unbound variable" to stderr.
    * This is what you want: have it fail explicitly and immediately, rather than create subtle bugs that may be discovered too late.
    * Take a moment and look. Do you see the error? The right-hand side of the third line says "firstname", all lowercase, instead of the camel-cased "firstName". Without the -u option, this will be a silent error. But with the -u option, the script exits on that line with an exit code of 1, printing the message "firstname: unbound variable" to stderr.
    * This is what you want: have it fail explicitly and immediately, rather than create subtle bugs that may be discovered too late.
    #### `set -o pipefail`
    * This setting prevents errors in a pipeline from being masked. If any command in a pipeline fails, that return code will be used as the return code of the whole pipeline. By default, the pipeline's return code is that of the last command even if it succeeds. Imagine finding a sorted list of matching lines in a file:
    #### set -o pipefail
    * This setting prevents errors in a pipeline from being masked. If any command in a pipeline fails, that return code will be used as the return code of the whole pipeline. By default, the pipeline's return code is that of the last command even if it succeeds. Imagine finding a sorted list of matching lines in a file:
    ```
    $ grep some-string /non/existent/file | sort
    @@ -58,9 +58,9 @@
    0
    ```
    - Here, grep has an exit code of 2, writes an error message to stderr, and an empty string to stdout.
    - This empty string is then passed through sort, which happily accepts it as valid input, and returns a status code of 0.
    - This is fine for a command line, but bad for a shell script: you almost certainly want the script to exit right then with a nonzero exit code... like this:
    - Here, grep has an exit code of 2, writes an error message to stderr, and an empty string to stdout.
    - This empty string is then passed through sort, which happily accepts it as valid input, and returns a status code of 0.
    - This is fine for a command line, but bad for a shell script: you almost certainly want the script to exit right then with a nonzero exit code... like this:
    ```
    $ set -o pipefail
    @@ -70,7 +70,7 @@
    2
    ```
    #### Setting IFS
    * The IFS variable - which stands for Internal Field Separator - controls what Bash calls word splitting. When set to a string, each character in the string is considered by Bash to separate words. This governs how bash will iterate through a sequence. For example, this script:
    * The IFS variable - which stands for Internal Field Separator - controls what Bash calls word splitting. When set to a string, each character in the string is considered by Bash to separate words. This governs how bash will iterate through a sequence. For example, this script:
    ```
    #!/bin/bash
    @@ -91,10 +91,10 @@
    c
    a b c
    ```
    * In the first for loop, IFS is set to $' '. (The $'...' syntax creates a string, with backslash-escaped characters replaced with special characters - like "\t" for tab and "\n" for newline.) Within the for loops, x and y are set to whatever bash considers a "word" in the original sequence.
    * For the first loop, IFS is a space, meaning that words are separated by a space character.
    * For the second loop, "words" are separated by a newline, which means bash considers the whole value of "items" as a single word. If IFS is more than one character, splitting will be done on any of those characters.
    * Got all that? The next question is, why are we setting IFS to a string consisting of a tab character and a newline? Because it gives us better behavior when iterating over a loop. By "better", I mean "much less likely to cause surprising and confusing bugs". This is apparent in working with bash arrays:
    * In the first for loop, IFS is set to $' '. (The $'...' syntax creates a string, with backslash-escaped characters replaced with special characters - like "\t" for tab and "\n" for newline.) Within the for loops, x and y are set to whatever bash considers a "word" in the original sequence.
    * For the first loop, IFS is a space, meaning that words are separated by a space character.
    * For the second loop, "words" are separated by a newline, which means bash considers the whole value of "items" as a single word. If IFS is more than one character, splitting will be done on any of those characters.
    * Got all that? The next question is, why are we setting IFS to a string consisting of a tab character and a newline? Because it gives us better behavior when iterating over a loop. By "better", I mean "much less likely to cause surprising and confusing bugs". This is apparent in working with bash arrays:
    ```
    #!/bin/bash
    @@ -132,20 +132,19 @@
    Wayne Gretzky
    David Beckham
    ```
    Or consider a script that takes filenames as command line arguments:
    Or consider a script that takes filenames as command line arguments:
    ```
    for arg in $@; do
    echo "doing something with file: $arg"
    done
    ```
    * If you invoke this as myscript.sh notes todo-list 'My Resume.doc', then with the default IFS value, the third argument will be mis-parsed as two separate files - named "My" and "Resume.doc". When actually it's a file that has a space in it, named "My Resume.doc".
    * If you invoke this as myscript.sh notes todo-list 'My Resume.doc', then with the default IFS value, the third argument will be mis-parsed as two separate files - named "My" and "Resume.doc". When actually it's a file that has a space in it, named "My Resume.doc".

    * Which behavior is more generally useful? The second, of course - where we have the ability to not split on spaces. If we have an array of strings that in general contain spaces, we normally want to iterate through them item by item, and not split an individual item into several.
    * Which behavior is more generally useful? The second, of course - where we have the ability to not split on spaces. If we have an array of strings that in general contain spaces, we normally want to iterate through them item by item, and not split an individual item into several.
    * Setting IFS to $'\n\t' means that word splitting will happen only on newlines and tab characters. This very often produces useful splitting behavior.
    * By default, bash sets this to $' \n\t' - space, newline, tab - which is too eager.
    * Setting IFS to $'\n\t' means that word splitting will happen only on newlines and tab characters. This very often produces useful splitting behavior.
    * By default, bash sets this to $' \n\t' - space, newline, tab - which is too eager.
    ## Citation:
    * Maxwell, A. (2017). Unofficial-bash-strict-mode. Retrieved 2018, from http://redsymbol.net/articles/unofficial-bash-strict-mode/
    * Maxwell, A. (2017). Unofficial-bash-strict-mode. Retrieved 2018, from http://redsymbol.net/articles/unofficial-bash-strict-mode/
  8. @mohanpedala mohanpedala revised this gist Oct 29, 2021. 1 changed file with 145 additions and 126 deletions.
    271 changes: 145 additions & 126 deletions bash_strict_mode.md
    Original file line number Diff line number Diff line change
    @@ -1,132 +1,151 @@
    ### set -e, -u, -x, -o pipefail

    The `set` lines
    # Table of Contents
    * [set -e, -u, -x, -o pipefail](#set--e---u---x---o-pipefail)
    - [`set -euxo pipefail` is short for:](#-set--euxo-pipefail--is-short-for-)
    - [`set -e`](#-set--e-)
    - [`set -x`](#-set--x-)
    - [`set -u`](#-set--u-)
    - [`set -o pipefail`](#-set--o-pipefail-)
    - [Setting IFS](#setting-ifs)
    * [Citation:](#citation-)

    ## set -e, -u, -x, -o pipefail

    * The `set` lines
    - These lines deliberately cause your script to fail. Wait, what? Believe me, this is a good thing.
    - With these settings, certain common errors will cause the script to immediately fail, explicitly and loudly. Otherwise, you can get hidden bugs that are discovered only when they blow up in production.

    * `set -euxo pipefail` is short for:
    ```
    set -e
    set -u
    set -o pipefail
    set -x
    ```


    * set -e
    The `set -e` option instructs bash to immediately exit if any command [1] has a non-zero exit status. You wouldn't want to set this for your command-line shell, but in a script it's massively helpful. In all widely used general-purpose programming languages, an unhandled runtime error - whether that's a thrown exception in Java, or a segmentation fault in C, or a syntax error in Python - immediately halts execution of the program; subsequent lines are not executed.

    - By default, bash does not do this. This default behavior is exactly what you want if you are using bash on the command line
    - you don't want a typo to log you out! But in a script, you really want the opposite.
    - If one line in a script fails, but the last line succeeds, the whole script has a successful exit code. That makes it very easy to miss the error.
    - Again, what you want when using bash as your command-line shell and using it in scripts are at odds here. Being intolerant of errors is a lot better in scripts, and that's what set -e gives you.

    * `set -x` enables a mode of the shell where all executed commands are printed to the terminal. In your case it's clearly used for debugging, which is a typical use case for set -x : printing every command as it is executed may help you to visualize the control flow of the script if it is not functioning as expected.

    * `set -u` affects variables. When set, a reference to any variable you haven't previously defined - with the exceptions of $* and $@ - is an error, and causes the program to immediately exit. Languages like Python, C, Java and more all behave the same way, for all sorts of good reasons. One is so typos don't create new variables without you realizing it. For example:
    ```
    #!/bin/bash
    firstName="Aaron"
    fullName="$firstname Maxwell"
    echo "$fullName"
    ```
    * Take a moment and look. Do you see the error? The right-hand side of the third line says "firstname", all lowercase, instead of the camel-cased "firstName". Without the -u option, this will be a silent error. But with the -u option, the script exits on that line with an exit code of 1, printing the message "firstname: unbound variable" to stderr.
    * This is what you want: have it fail explicitly and immediately, rather than create subtle bugs that may be discovered too late.


    * `set -o pipefail` this setting prevents errors in a pipeline from being masked. If any command in a pipeline fails, that return code will be used as the return code of the whole pipeline. By default, the pipeline's return code is that of the last command even if it succeeds. Imagine finding a sorted list of matching lines in a file:
    ```
    $ grep some-string /non/existent/file | sort
    grep: /non/existent/file: No such file or directory
    % echo $?
    0
    ```

    - Here, grep has an exit code of 2, writes an error message to stderr, and an empty string to stdout.
    - This empty string is then passed through sort, which happily accepts it as valid input, and returns a status code of 0.
    - This is fine for a command line, but bad for a shell script: you almost certainly want the script to exit right then with a nonzero exit code... like this:

    ```
    $ set -o pipefail
    $ grep some-string /non/existent/file | sort
    grep: /non/existent/file: No such file or directory
    $ echo $?
    2
    ```
    Setting IFS
    The IFS variable - which stands for Internal Field Separator - controls what Bash calls word splitting. When set to a string, each character in the string is considered by Bash to separate words. This governs how bash will iterate through a sequence. For example, this script:

    ```
    #!/bin/bash
    IFS=$' '
    items="a b c"
    for x in $items; do
    echo "$x"
    done
    IFS=$'\n'
    for y in $items; do
    echo "$y"
    done
    ... will print out this:
    a
    b
    c
    a b c
    ```
    * In the first for loop, IFS is set to $' '. (The $'...' syntax creates a string, with backslash-escaped characters replaced with special characters - like "\t" for tab and "\n" for newline.) Within the for loops, x and y are set to whatever bash considers a "word" in the original sequence.
    * For the first loop, IFS is a space, meaning that words are separated by a space character.
    * For the second loop, "words" are separated by a newline, which means bash considers the whole value of "items" as a single word. If IFS is more than one character, splitting will be done on any of those characters.
    * Got all that? The next question is, why are we setting IFS to a string consisting of a tab character and a newline? Because it gives us better behavior when iterating over a loop. By "better", I mean "much less likely to cause surprising and confusing bugs". This is apparent in working with bash arrays:
    ```
    #!/bin/bash
    names=(
    "Aaron Maxwell"
    "Wayne Gretzky"
    "David Beckham"
    )
    echo "With default IFS value..."
    for name in ${names[@]}; do
    echo "$name"
    done
    echo ""
    echo "With strict-mode IFS value..."
    IFS=$'\n\t'
    for name in ${names[@]}; do
    echo "$name"
    done
    ```
    ```
    ## Output
    With default IFS value...
    Aaron
    Maxwell
    Wayne
    Gretzky
    David
    Beckham
    With strict-mode IFS value...
    Aaron Maxwell
    Wayne Gretzky
    David Beckham
    ```
    Or consider a script that takes filenames as command line arguments:
    ```
    for arg in $@; do
    echo "doing something with file: $arg"
    done
    ```
    * If you invoke this as myscript.sh notes todo-list 'My Resume.doc', then with the default IFS value, the third argument will be mis-parsed as two separate files - named "My" and "Resume.doc". When actually it's a file that has a space in it, named "My Resume.doc".

    * Which behavior is more generally useful? The second, of course - where we have the ability to not split on spaces. If we have an array of strings that in general contain spaces, we normally want to iterate through them item by item, and not split an individual item into several.

    * Setting IFS to $'\n\t' means that word splitting will happen only on newlines and tab characters. This very often produces useful splitting behavior.
    * By default, bash sets this to $' \n\t' - space, newline, tab - which is too eager.
    #### `set -euxo pipefail` is short for:
    ```
    set -e
    set -u
    set -o pipefail
    set -x
    ```


    #### `set -e`
    * The `set -e` option instructs bash to immediately exit if any command [1] has a non-zero exit status. You wouldn't want to set this for your command-line shell, but in a script it's massively helpful. In all widely used general-purpose programming languages, an unhandled runtime error
    - whether that's a thrown exception in Java, or a segmentation fault in C, or a syntax error in Python - immediately halts execution of the program; subsequent lines are not executed.

    - By default, bash does not do this. This default behavior is exactly what you want if you are using bash on the command line
    - you don't want a typo to log you out! But in a script, you really want the opposite.
    - If one line in a script fails, but the last line succeeds, the whole script has a successful exit code. That makes it very easy to miss the error.
    - Again, what you want when using bash as your command-line shell and using it in scripts are at odds here. Being intolerant of errors is a lot better in scripts, and that's what set -e gives you.

    #### `set -x`
    * Enables a mode of the shell where all executed commands are printed to the terminal. In your case it's clearly used for debugging, which is a typical use case for set -x : printing every command as it is executed may help you to visualize the control flow of the script if it is not functioning as expected.

    #### `set -u`
    * Affects variables. When set, a reference to any variable you haven't previously defined - with the exceptions of $* and $@ - is an error, and causes the program to immediately exit. Languages like Python, C, Java and more all behave the same way, for all sorts of good reasons. One is so typos don't create new variables without you realizing it. For example:

    ```
    #!/bin/bash
    firstName="Aaron"
    fullName="$firstname Maxwell"
    echo "$fullName"
    ```
    * Take a moment and look. Do you see the error? The right-hand side of the third line says "firstname", all lowercase, instead of the camel-cased "firstName". Without the -u option, this will be a silent error. But with the -u option, the script exits on that line with an exit code of 1, printing the message "firstname: unbound variable" to stderr.
    * This is what you want: have it fail explicitly and immediately, rather than create subtle bugs that may be discovered too late.


    #### `set -o pipefail`
    * This setting prevents errors in a pipeline from being masked. If any command in a pipeline fails, that return code will be used as the return code of the whole pipeline. By default, the pipeline's return code is that of the last command even if it succeeds. Imagine finding a sorted list of matching lines in a file:

    ```
    $ grep some-string /non/existent/file | sort
    grep: /non/existent/file: No such file or directory
    % echo $?
    0
    ```

    - Here, grep has an exit code of 2, writes an error message to stderr, and an empty string to stdout.
    - This empty string is then passed through sort, which happily accepts it as valid input, and returns a status code of 0.
    - This is fine for a command line, but bad for a shell script: you almost certainly want the script to exit right then with a nonzero exit code... like this:

    ```
    $ set -o pipefail
    $ grep some-string /non/existent/file | sort
    grep: /non/existent/file: No such file or directory
    $ echo $?
    2
    ```
    #### Setting IFS
    * The IFS variable - which stands for Internal Field Separator - controls what Bash calls word splitting. When set to a string, each character in the string is considered by Bash to separate words. This governs how bash will iterate through a sequence. For example, this script:

    ```
    #!/bin/bash
    IFS=$' '
    items="a b c"
    for x in $items; do
    echo "$x"
    done

    IFS=$'\n'
    for y in $items; do
    echo "$y"
    done
    ... will print out this:

    a
    b
    c
    a b c
    ```
    * In the first for loop, IFS is set to $' '. (The $'...' syntax creates a string, with backslash-escaped characters replaced with special characters - like "\t" for tab and "\n" for newline.) Within the for loops, x and y are set to whatever bash considers a "word" in the original sequence.
    * For the first loop, IFS is a space, meaning that words are separated by a space character.
    * For the second loop, "words" are separated by a newline, which means bash considers the whole value of "items" as a single word. If IFS is more than one character, splitting will be done on any of those characters.
    * Got all that? The next question is, why are we setting IFS to a string consisting of a tab character and a newline? Because it gives us better behavior when iterating over a loop. By "better", I mean "much less likely to cause surprising and confusing bugs". This is apparent in working with bash arrays:

    ```
    #!/bin/bash
    names=(
    "Aaron Maxwell"
    "Wayne Gretzky"
    "David Beckham"
    )

    echo "With default IFS value..."
    for name in ${names[@]}; do
    echo "$name"
    done

    echo ""
    echo "With strict-mode IFS value..."
    IFS=$'\n\t'
    for name in ${names[@]}; do
    echo "$name"
    done

    ```
    ```
    ## Output
    With default IFS value...
    Aaron
    Maxwell
    Wayne
    Gretzky
    David
    Beckham

    With strict-mode IFS value...
    Aaron Maxwell
    Wayne Gretzky
    David Beckham
    ```
    Or consider a script that takes filenames as command line arguments:

    ```
    for arg in $@; do
    echo "doing something with file: $arg"
    done
    ```

    * If you invoke this as myscript.sh notes todo-list 'My Resume.doc', then with the default IFS value, the third argument will be mis-parsed as two separate files - named "My" and "Resume.doc". When actually it's a file that has a space in it, named "My Resume.doc".

    * Which behavior is more generally useful? The second, of course - where we have the ability to not split on spaces. If we have an array of strings that in general contain spaces, we normally want to iterate through them item by item, and not split an individual item into several.

    * Setting IFS to $'\n\t' means that word splitting will happen only on newlines and tab characters. This very often produces useful splitting behavior.
    * By default, bash sets this to $' \n\t' - space, newline, tab - which is too eager.

    ## Citation:
    * Maxwell, A. (2017). Unofficial-bash-strict-mode. Retrieved 2018, from http://redsymbol.net/articles/unofficial-bash-strict-mode/
  9. @mohanpedala mohanpedala revised this gist Oct 29, 2021. 1 changed file with 2 additions and 2 deletions.
    4 changes: 2 additions & 2 deletions bash_strict_mode.md
    Original file line number Diff line number Diff line change
    @@ -128,5 +128,5 @@ done
    * Setting IFS to $'\n\t' means that word splitting will happen only on newlines and tab characters. This very often produces useful splitting behavior.
    * By default, bash sets this to $' \n\t' - space, newline, tab - which is too eager.


    [Full Reference Click Here](http://redsymbol.net/articles/unofficial-bash-strict-mode/)
    ## Citation:
    * Maxwell, A. (2017). Unofficial-bash-strict-mode. Retrieved 2018, from http://redsymbol.net/articles/unofficial-bash-strict-mode/
  10. @mohanpedala mohanpedala revised this gist Aug 24, 2021. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion bash_strict_mode.md
    Original file line number Diff line number Diff line change
    @@ -1,4 +1,4 @@
    ### set -e, -u, -x, -o
    ### set -e, -u, -x, -o pipefail

    The `set` lines
    - These lines deliberately cause your script to fail. Wait, what? Believe me, this is a good thing.
  11. @mohanpedala mohanpedala revised this gist Aug 24, 2021. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion bash_strict_mode.md
    Original file line number Diff line number Diff line change
    @@ -1,4 +1,4 @@
    ### set -e, -u, -o, -x pipefail
    ### set -e, -u, -x, -o

    The `set` lines
    - These lines deliberately cause your script to fail. Wait, what? Believe me, this is a good thing.
  12. Mohan P Edala revised this gist May 16, 2021. No changes.
  13. Mohan P Edala revised this gist May 16, 2021. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion bash_strict_mode.md
    Original file line number Diff line number Diff line change
    @@ -1,4 +1,4 @@
    ### set -e, -u, -o pipefail
    ### set -e, -u, -o, -x pipefail

    The `set` lines
    - These lines deliberately cause your script to fail. Wait, what? Believe me, this is a good thing.
  14. Mohan P Edala revised this gist May 16, 2021. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion bash_strict_mode.md
    Original file line number Diff line number Diff line change
    @@ -4,7 +4,7 @@ The `set` lines
    - These lines deliberately cause your script to fail. Wait, what? Believe me, this is a good thing.
    - With these settings, certain common errors will cause the script to immediately fail, explicitly and loudly. Otherwise, you can get hidden bugs that are discovered only when they blow up in production.

    * `set -euo pipefail` is short for:
    * `set -euxo pipefail` is short for:
    ```
    set -e
    set -u
  15. Mohan P Edala revised this gist Apr 21, 2021. 1 changed file with 25 additions and 23 deletions.
    48 changes: 25 additions & 23 deletions bash_strict_mode.md
    Original file line number Diff line number Diff line change
    @@ -1,11 +1,11 @@
    ### set -e, -u, -o pipefail

    The "set" lines
    These lines deliberately cause your script to fail. Wait, what? Believe me, this is a good thing. With these settings, certain common errors will cause the script to immediately fail, explicitly and loudly. Otherwise, you can get hidden bugs that are discovered only when they blow up in production.
    The `set` lines
    - These lines deliberately cause your script to fail. Wait, what? Believe me, this is a good thing.
    - With these settings, certain common errors will cause the script to immediately fail, explicitly and loudly. Otherwise, you can get hidden bugs that are discovered only when they blow up in production.

    * `set -euo pipefail` is short for:
    ```
    set -euo pipefail is short for:
    set -e
    set -u
    set -o pipefail
    @@ -14,37 +14,37 @@ set -x


    * set -e
    The set -e option instructs bash to immediately exit if any command [1] has a non-zero exit status. You wouldn't want to set this for your command-line shell, but in a script it's massively helpful. In all widely used general-purpose programming languages, an unhandled runtime error - whether that's a thrown exception in Java, or a segmentation fault in C, or a syntax error in Python - immediately halts execution of the program; subsequent lines are not executed.

    By default, bash does not do this. This default behavior is exactly what you want if you are using bash on the command line - you don't want a typo to log you out! But in a script, you really want the opposite. If one line in a script fails, but the last line succeeds, the whole script has a successful exit code. That makes it very easy to miss the error.
    The `set -e` option instructs bash to immediately exit if any command [1] has a non-zero exit status. You wouldn't want to set this for your command-line shell, but in a script it's massively helpful. In all widely used general-purpose programming languages, an unhandled runtime error - whether that's a thrown exception in Java, or a segmentation fault in C, or a syntax error in Python - immediately halts execution of the program; subsequent lines are not executed.

    Again, what you want when using bash as your command-line shell and using it in scripts are at odds here. Being intolerant of errors is a lot better in scripts, and that's what set -e gives you.
    - By default, bash does not do this. This default behavior is exactly what you want if you are using bash on the command line
    - you don't want a typo to log you out! But in a script, you really want the opposite.
    - If one line in a script fails, but the last line succeeds, the whole script has a successful exit code. That makes it very easy to miss the error.
    - Again, what you want when using bash as your command-line shell and using it in scripts are at odds here. Being intolerant of errors is a lot better in scripts, and that's what set -e gives you.

    * set -x enables a mode of the shell where all executed commands are printed to the terminal. In your case it's clearly used for debugging, which is a typical use case for set -x : printing every command as it is executed may help you to visualize the control flow of the script if it is not functioning as expected.
    * `set -x` enables a mode of the shell where all executed commands are printed to the terminal. In your case it's clearly used for debugging, which is a typical use case for set -x : printing every command as it is executed may help you to visualize the control flow of the script if it is not functioning as expected.

    * set -u
    set -u affects variables. When set, a reference to any variable you haven't previously defined - with the exceptions of $* and $@ - is an error, and causes the program to immediately exit. Languages like Python, C, Java and more all behave the same way, for all sorts of good reasons. One is so typos don't create new variables without you realizing it. For example:
    * `set -u` affects variables. When set, a reference to any variable you haven't previously defined - with the exceptions of $* and $@ - is an error, and causes the program to immediately exit. Languages like Python, C, Java and more all behave the same way, for all sorts of good reasons. One is so typos don't create new variables without you realizing it. For example:
    ```
    #!/bin/bash
    firstName="Aaron"
    fullName="$firstname Maxwell"
    echo "$fullName"
    ```
    Take a moment and look. Do you see the error? The right-hand side of the third line says "firstname", all lowercase, instead of the camel-cased "firstName". Without the -u option, this will be a silent error. But with the -u option, the script exits on that line with an exit code of 1, printing the message "firstname: unbound variable" to stderr. This is what you want: have it fail explicitly and immediately, rather than create subtle bugs that may be discovered too late.
    * Take a moment and look. Do you see the error? The right-hand side of the third line says "firstname", all lowercase, instead of the camel-cased "firstName". Without the -u option, this will be a silent error. But with the -u option, the script exits on that line with an exit code of 1, printing the message "firstname: unbound variable" to stderr.
    * This is what you want: have it fail explicitly and immediately, rather than create subtle bugs that may be discovered too late.


    * set -o pipefail
    This setting prevents errors in a pipeline from being masked. If any command in a pipeline fails, that return code will be used as the return code of the whole pipeline. By default, the pipeline's return code is that of the last command - even if it succeeds. Imagine finding a sorted list of matching lines in a file:
    * `set -o pipefail` this setting prevents errors in a pipeline from being masked. If any command in a pipeline fails, that return code will be used as the return code of the whole pipeline. By default, the pipeline's return code is that of the last command even if it succeeds. Imagine finding a sorted list of matching lines in a file:
    ```
    $ grep some-string /non/existent/file | sort
    grep: /non/existent/file: No such file or directory
    % echo $?
    0
    ```

    Here, grep has an exit code of 2, writes an error message to stderr, and an empty string to stdout.
    This empty string is then passed through sort, which happily accepts it as valid input, and returns a status code of 0.
    This is fine for a command line, but bad for a shell script: you almost certainly want the script to exit right then with a nonzero exit code... like this:
    - Here, grep has an exit code of 2, writes an error message to stderr, and an empty string to stdout.
    - This empty string is then passed through sort, which happily accepts it as valid input, and returns a status code of 0.
    - This is fine for a command line, but bad for a shell script: you almost certainly want the script to exit right then with a nonzero exit code... like this:

    ```
    $ set -o pipefail
    @@ -75,9 +75,10 @@ b
    c
    a b c
    ```
    In the first for loop, IFS is set to $' '. (The $'...' syntax creates a string, with backslash-escaped characters replaced with special characters - like "\t" for tab and "\n" for newline.) Within the for loops, x and y are set to whatever bash considers a "word" in the original sequence. For the first loop, IFS is a space, meaning that words are separated by a space character. For the second loop, "words" are separated by a newline, which means bash considers the whole value of "items" as a single word. If IFS is more than one character, splitting will be done on any of those characters.

    Got all that? The next question is, why are we setting IFS to a string consisting of a tab character and a newline? Because it gives us better behavior when iterating over a loop. By "better", I mean "much less likely to cause surprising and confusing bugs". This is apparent in working with bash arrays:
    * In the first for loop, IFS is set to $' '. (The $'...' syntax creates a string, with backslash-escaped characters replaced with special characters - like "\t" for tab and "\n" for newline.) Within the for loops, x and y are set to whatever bash considers a "word" in the original sequence.
    * For the first loop, IFS is a space, meaning that words are separated by a space character.
    * For the second loop, "words" are separated by a newline, which means bash considers the whole value of "items" as a single word. If IFS is more than one character, splitting will be done on any of those characters.
    * Got all that? The next question is, why are we setting IFS to a string consisting of a tab character and a newline? Because it gives us better behavior when iterating over a loop. By "better", I mean "much less likely to cause surprising and confusing bugs". This is apparent in working with bash arrays:
    ```
    #!/bin/bash
    names=(
    @@ -120,11 +121,12 @@ for arg in $@; do
    echo "doing something with file: $arg"
    done
    ```
    If you invoke this as myscript.sh notes todo-list 'My Resume.doc', then with the default IFS value, the third argument will be mis-parsed as two separate files - named "My" and "Resume.doc". When actually it's a file that has a space in it, named "My Resume.doc".
    * If you invoke this as myscript.sh notes todo-list 'My Resume.doc', then with the default IFS value, the third argument will be mis-parsed as two separate files - named "My" and "Resume.doc". When actually it's a file that has a space in it, named "My Resume.doc".

    Which behavior is more generally useful? The second, of course - where we have the ability to not split on spaces. If we have an array of strings that in general contain spaces, we normally want to iterate through them item by item, and not split an individual item into several.
    * Which behavior is more generally useful? The second, of course - where we have the ability to not split on spaces. If we have an array of strings that in general contain spaces, we normally want to iterate through them item by item, and not split an individual item into several.

    Setting IFS to $'\n\t' means that word splitting will happen only on newlines and tab characters. This very often produces useful splitting behavior. By default, bash sets this to $' \n\t' - space, newline, tab - which is too eager.
    * Setting IFS to $'\n\t' means that word splitting will happen only on newlines and tab characters. This very often produces useful splitting behavior.
    * By default, bash sets this to $' \n\t' - space, newline, tab - which is too eager.


    [Full Reference Click Here](http://redsymbol.net/articles/unofficial-bash-strict-mode/)
  16. Mohan P Edala revised this gist Apr 21, 2021. 1 changed file with 5 additions and 7 deletions.
    12 changes: 5 additions & 7 deletions bash_strict_mode.md
    Original file line number Diff line number Diff line change
    @@ -84,7 +84,6 @@ names=(
    "Aaron Maxwell"
    "Wayne Gretzky"
    "David Beckham"
    "Anderson da Silva"
    )
    echo "With default IFS value..."
    @@ -98,26 +97,25 @@ IFS=$'\n\t'
    for name in ${names[@]}; do
    echo "$name"
    done
    (Yes, I'm putting my name on a list of great athletes. Indulge me.) This is the output:
    ```
    ```
    ## Output
    With default IFS value...
    Aaron
    Maxwell
    Wayne
    Gretzky
    David
    Beckham
    Anderson
    da
    Silva
    With strict-mode IFS value...
    Aaron Maxwell
    Wayne Gretzky
    David Beckham
    Anderson da Silva
    ```
    Or consider a script that takes filenames as command line arguments:
    ```
    for arg in $@; do
    echo "doing something with file: $arg"
    done
  17. Mohan P Edala revised this gist Apr 21, 2021. 1 changed file with 11 additions and 5 deletions.
    16 changes: 11 additions & 5 deletions bash_strict_mode.md
    Original file line number Diff line number Diff line change
    @@ -36,16 +36,21 @@ Take a moment and look. Do you see the error? The right-hand side of the third l
    * set -o pipefail
    This setting prevents errors in a pipeline from being masked. If any command in a pipeline fails, that return code will be used as the return code of the whole pipeline. By default, the pipeline's return code is that of the last command - even if it succeeds. Imagine finding a sorted list of matching lines in a file:
    ```
    % grep some-string /non/existent/file | sort
    $ grep some-string /non/existent/file | sort
    grep: /non/existent/file: No such file or directory
    % echo $?
    0
    (% is the bash prompt.) Here, grep has an exit code of 2, writes an error message to stderr, and an empty string to stdout. This empty string is then passed through sort, which happily accepts it as valid input, and returns a status code of 0. This is fine for a command line, but bad for a shell script: you almost certainly want the script to exit right then with a nonzero exit code... like this:
    ```

    Here, grep has an exit code of 2, writes an error message to stderr, and an empty string to stdout.
    This empty string is then passed through sort, which happily accepts it as valid input, and returns a status code of 0.
    This is fine for a command line, but bad for a shell script: you almost certainly want the script to exit right then with a nonzero exit code... like this:

    % set -o pipefail
    % grep some-string /non/existent/file | sort
    ```
    $ set -o pipefail
    $ grep some-string /non/existent/file | sort
    grep: /non/existent/file: No such file or directory
    % echo $?
    $ echo $?
    2
    ```
    Setting IFS
    @@ -123,4 +128,5 @@ Which behavior is more generally useful? The second, of course - where we have t

    Setting IFS to $'\n\t' means that word splitting will happen only on newlines and tab characters. This very often produces useful splitting behavior. By default, bash sets this to $' \n\t' - space, newline, tab - which is too eager.


    [Full Reference Click Here](http://redsymbol.net/articles/unofficial-bash-strict-mode/)
  18. Mohan P Edala revised this gist Apr 21, 2021. 1 changed file with 3 additions and 0 deletions.
    3 changes: 3 additions & 0 deletions bash_strict_mode.md
    Original file line number Diff line number Diff line change
    @@ -9,6 +9,7 @@ set -euo pipefail is short for:
    set -e
    set -u
    set -o pipefail
    set -x
    ```


    @@ -19,6 +20,8 @@ By default, bash does not do this. This default behavior is exactly what you wan

    Again, what you want when using bash as your command-line shell and using it in scripts are at odds here. Being intolerant of errors is a lot better in scripts, and that's what set -e gives you.

    * set -x enables a mode of the shell where all executed commands are printed to the terminal. In your case it's clearly used for debugging, which is a typical use case for set -x : printing every command as it is executed may help you to visualize the control flow of the script if it is not functioning as expected.

    * set -u
    set -u affects variables. When set, a reference to any variable you haven't previously defined - with the exceptions of $* and $@ - is an error, and causes the program to immediately exit. Languages like Python, C, Java and more all behave the same way, for all sorts of good reasons. One is so typos don't create new variables without you realizing it. For example:
    ```
  19. phaneindra revised this gist Sep 14, 2018. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion bash_strict_mode.md
    Original file line number Diff line number Diff line change
    @@ -120,4 +120,4 @@ Which behavior is more generally useful? The second, of course - where we have t

    Setting IFS to $'\n\t' means that word splitting will happen only on newlines and tab characters. This very often produces useful splitting behavior. By default, bash sets this to $' \n\t' - space, newline, tab - which is too eager.

    [Reference](http://redsymbol.net/articles/unofficial-bash-strict-mode/)
    [Full Reference Click Here](http://redsymbol.net/articles/unofficial-bash-strict-mode/)
  20. phaneindra revised this gist Sep 14, 2018. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion bash_strict_mode.md
    Original file line number Diff line number Diff line change
    @@ -120,4 +120,4 @@ Which behavior is more generally useful? The second, of course - where we have t

    Setting IFS to $'\n\t' means that word splitting will happen only on newlines and tab characters. This very often produces useful splitting behavior. By default, bash sets this to $' \n\t' - space, newline, tab - which is too eager.

    (Reference)[http://redsymbol.net/articles/unofficial-bash-strict-mode/]
    [Reference](http://redsymbol.net/articles/unofficial-bash-strict-mode/)
  21. phaneindra created this gist Sep 14, 2018.
    123 changes: 123 additions & 0 deletions bash_strict_mode.md
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,123 @@
    ### set -e, -u, -o pipefail

    The "set" lines
    These lines deliberately cause your script to fail. Wait, what? Believe me, this is a good thing. With these settings, certain common errors will cause the script to immediately fail, explicitly and loudly. Otherwise, you can get hidden bugs that are discovered only when they blow up in production.

    ```
    set -euo pipefail is short for:
    set -e
    set -u
    set -o pipefail
    ```


    * set -e
    The set -e option instructs bash to immediately exit if any command [1] has a non-zero exit status. You wouldn't want to set this for your command-line shell, but in a script it's massively helpful. In all widely used general-purpose programming languages, an unhandled runtime error - whether that's a thrown exception in Java, or a segmentation fault in C, or a syntax error in Python - immediately halts execution of the program; subsequent lines are not executed.

    By default, bash does not do this. This default behavior is exactly what you want if you are using bash on the command line - you don't want a typo to log you out! But in a script, you really want the opposite. If one line in a script fails, but the last line succeeds, the whole script has a successful exit code. That makes it very easy to miss the error.

    Again, what you want when using bash as your command-line shell and using it in scripts are at odds here. Being intolerant of errors is a lot better in scripts, and that's what set -e gives you.

    * set -u
    set -u affects variables. When set, a reference to any variable you haven't previously defined - with the exceptions of $* and $@ - is an error, and causes the program to immediately exit. Languages like Python, C, Java and more all behave the same way, for all sorts of good reasons. One is so typos don't create new variables without you realizing it. For example:
    ```
    #!/bin/bash
    firstName="Aaron"
    fullName="$firstname Maxwell"
    echo "$fullName"
    ```
    Take a moment and look. Do you see the error? The right-hand side of the third line says "firstname", all lowercase, instead of the camel-cased "firstName". Without the -u option, this will be a silent error. But with the -u option, the script exits on that line with an exit code of 1, printing the message "firstname: unbound variable" to stderr. This is what you want: have it fail explicitly and immediately, rather than create subtle bugs that may be discovered too late.


    * set -o pipefail
    This setting prevents errors in a pipeline from being masked. If any command in a pipeline fails, that return code will be used as the return code of the whole pipeline. By default, the pipeline's return code is that of the last command - even if it succeeds. Imagine finding a sorted list of matching lines in a file:
    ```
    % grep some-string /non/existent/file | sort
    grep: /non/existent/file: No such file or directory
    % echo $?
    0
    (% is the bash prompt.) Here, grep has an exit code of 2, writes an error message to stderr, and an empty string to stdout. This empty string is then passed through sort, which happily accepts it as valid input, and returns a status code of 0. This is fine for a command line, but bad for a shell script: you almost certainly want the script to exit right then with a nonzero exit code... like this:
    % set -o pipefail
    % grep some-string /non/existent/file | sort
    grep: /non/existent/file: No such file or directory
    % echo $?
    2
    ```
    Setting IFS
    The IFS variable - which stands for Internal Field Separator - controls what Bash calls word splitting. When set to a string, each character in the string is considered by Bash to separate words. This governs how bash will iterate through a sequence. For example, this script:

    ```
    #!/bin/bash
    IFS=$' '
    items="a b c"
    for x in $items; do
    echo "$x"
    done
    IFS=$'\n'
    for y in $items; do
    echo "$y"
    done
    ... will print out this:
    a
    b
    c
    a b c
    ```
    In the first for loop, IFS is set to $' '. (The $'...' syntax creates a string, with backslash-escaped characters replaced with special characters - like "\t" for tab and "\n" for newline.) Within the for loops, x and y are set to whatever bash considers a "word" in the original sequence. For the first loop, IFS is a space, meaning that words are separated by a space character. For the second loop, "words" are separated by a newline, which means bash considers the whole value of "items" as a single word. If IFS is more than one character, splitting will be done on any of those characters.

    Got all that? The next question is, why are we setting IFS to a string consisting of a tab character and a newline? Because it gives us better behavior when iterating over a loop. By "better", I mean "much less likely to cause surprising and confusing bugs". This is apparent in working with bash arrays:
    ```
    #!/bin/bash
    names=(
    "Aaron Maxwell"
    "Wayne Gretzky"
    "David Beckham"
    "Anderson da Silva"
    )
    echo "With default IFS value..."
    for name in ${names[@]}; do
    echo "$name"
    done
    echo ""
    echo "With strict-mode IFS value..."
    IFS=$'\n\t'
    for name in ${names[@]}; do
    echo "$name"
    done
    (Yes, I'm putting my name on a list of great athletes. Indulge me.) This is the output:
    With default IFS value...
    Aaron
    Maxwell
    Wayne
    Gretzky
    David
    Beckham
    Anderson
    da
    Silva
    With strict-mode IFS value...
    Aaron Maxwell
    Wayne Gretzky
    David Beckham
    Anderson da Silva
    Or consider a script that takes filenames as command line arguments:
    for arg in $@; do
    echo "doing something with file: $arg"
    done
    ```
    If you invoke this as myscript.sh notes todo-list 'My Resume.doc', then with the default IFS value, the third argument will be mis-parsed as two separate files - named "My" and "Resume.doc". When actually it's a file that has a space in it, named "My Resume.doc".

    Which behavior is more generally useful? The second, of course - where we have the ability to not split on spaces. If we have an array of strings that in general contain spaces, we normally want to iterate through them item by item, and not split an individual item into several.

    Setting IFS to $'\n\t' means that word splitting will happen only on newlines and tab characters. This very often produces useful splitting behavior. By default, bash sets this to $' \n\t' - space, newline, tab - which is too eager.

    (Reference)[http://redsymbol.net/articles/unofficial-bash-strict-mode/]