Home » CentOS » C5 BASH IF
CentOS 13 Comments

Being new to some aspects of BASH, I tried to reduce the quantity of scripts by introducing a comparison test into an existing working script.

The script refused to work until I placed [ ] around the actual test. The second test, in the same script, misfunctioned until I removed the
[ ] around the second test.


13 thoughts on - C5 BASH IF

  • I think you are missing some very basic concepts here. First, the shell likes to parse things separated by white space. Second, [ is a synonym for test which is a build-in version of /bin/test, so try ‘man test’ for the syntax of tests. And third, you generally should use double quotes around variables in tests so they continue to exist as an empty string if the variable happens to not be set.

  • I re-ran the script with ‘set -x’ for

    16 if [ $file=’law00css’ ]
    17 then
    18 echo $file
    19 echo “css”
    20 else
    21 echo “no css”
    22 fi

    and received:-

    + ‘[‘ law45p07a01=law00css ‘]’
    + echo law45p07a01
    + echo css css

  • Thanks for that. I assumed if test 1 worked, so would test 2.

    Have re-run test 2 with

    and got

    which is correct (for the first time). It seems that following your good advice and plonking spaces around the = has solved the problem.

    Thank you very much. Now I can go to bed a satisfied person :-)

  • Try using [[ and ]] rather than [ and ]. Under BASH the double form are reserved words with special meaning to the shell whereas the single form are just a synonym for test. Parsing and splitting rules are different, in particular word splitting and pathname expansion are not performed. Consider:

    #!/bin/sh myvar=””
    set -vx
    [[ -n $myvar ]] && echo “non-null”
    [ -n $myvar ] && echo “non-null”

    bash-4.2$ ./X
    [[ -n $myvar ]] && echo “non-null”
    + [[ -n ” ]]
    [ -n $myvar ] && echo “non-null”
    + ‘[‘ -n ‘]’
    + echo non-null non-null bash-4.2$

    Note how in the second case $myvar has been parsed out of existence!


  • You still missed the part about quoting variables. You quote plain strings to hold embedded spaces together (or single-quotes to avoid parsing metacharacters). You use double quotes around $variables so they don’t disappear completely if the variable isn’t set, causing a syntax error. To understand it completely you need to know the order of operations as the shell makes multiple passes over the line, parsing, processing metacharacters, and expanding variables. And I
    don’t know where to find a concise description of that any more.

  • Correct. You invoked the test command with a single argument, the string “law45p07a01=law00css”. With a single argument, the test is just whether that argument in non-null, which it is. To perform a comparison you need 3 separate arguments (2 operands and an operator), not 1.

  • Once upon a time, Les Mikesell said:

    The thing to remember is that originally, the left square bracket [ was an external command (an alias of the “test” command). The shell interpreter just ran commands and tested the output. So, consider everything past the “if” as a single command, and treat it accordingly
    (so quoting arguments just like you would to “ls” or something).

    So, in the above line, $file would be expanded by the shell as part of command argument processing, and it is empty/not set, the command would be run as:

    [ = law00css ]

    That’s invalid syntax. If instead, you call it with $file in quotes:

    [ “” = law00css ]

    That’s valid syntax (and then tests as false).

  • But it is not ‘just’ expansions. You need to know the full order of operations with all the steps – word splitting, quote removal, i/o redirection, groupings, etc., some of which is repeated over the line after some of the other steps happen. I think I saw this in an understandable form for the bourne shell back in the 1980’s but can’t remember it well enough to describe and all the bash docs I’ve seen are way too convoluted to just see the order of operations as a simple set of steps – that you need to know before any of the rest will make sense.

  • It’s the 4 paragraphs at the start of the “EXPANSION” section:

    Expansion is performed on the command line after it has been split into
    words. There are seven kinds of expansion performed: brace expansion,
    tilde expansion, parameter and variable expansion, command substitution,
    arithmetic expansion, word splitting, and pathname expansion.

    The order of expansions is: brace expansion, tilde expansion, parameter,
    variable and arithmetic expansion and command substitution (done in a
    left-to-right fashion), word splitting, and pathname expansion.

    On systems that can support it, there is an additional expansion avail-
    able: process substitution.

    Only brace expansion, word splitting, and pathname expansion can change
    the number of words of the expansion; other expansions expand a single
    word to a single word. The only exceptions to this are the expansions of
    “$@” and “${name[@]}” as explained above (see PARAMETERS).

  • I think that is still an oversimplification because more than expansion is involved and the order related to other steps. When does it do i/o redirection; which things happen before/during starting subshells/pipes; what if you use ‘eval’, etc.?

  • On my bookshelf is a copy of “Learning the bash Shell” by Cameron Newham & Bill Rosenblatt, http://shop.oreilly.com/product/9780596009656.do ISBN 10:0-596-00965-8

    I admit I have not completed reading it for the first time, but it has taught me what I DO know about bash. I would love to compile a list of books others have used to learn what they know about bash. Even if you no longer regularly use what is on your shelf, new community members may be able to locate a copy in a public library and advance their knowledge.