Find the answer to your Linux question:
Results 1 to 6 of 6
Hi all, I'm running on Suse Linux 9.0 Enterprise server and I'm working on several scripts to be used for various tasks. I am not familiar with scripting and I'm ...
  1. #1
    Just Joined!
    Join Date
    Aug 2007
    Posts
    12

    String comparison in Shell scripting.

    Hi all,

    I'm running on Suse Linux 9.0 Enterprise server and I'm working on several scripts to be used for various tasks.

    I am not familiar with scripting and I'm still quite new as a linux operator, so I'm still learning the ropes regarding what commands are available and how to use those commands.

    I am currently writing a script that connects to a database, runs a query and returns that query. Those results are returned, in the form of a string, and placed into a variable.

    I now need to parse that string, looking for specific words and/or expressions to test against, and based on what those results are, perform the appropriate action and return the appropriate information.

    So my question to you is this:

    How do I take this string "this is a test to see if you are working" and look for "test" or "working" or "this" and then perform the appropriate action for each of these words separately?

    Thanks in advance.

  2. #2
    scm
    scm is offline
    Linux Engineer
    Join Date
    Feb 2005
    Posts
    1,044
    Quote Originally Posted by DWillis View Post
    How do I take this string "this is a test to see if you are working" and look for "test" or "working" or "this" and then perform the appropriate action for each of these words separately?
    The simplest way is with grep:
    Code:
    $VAR="this is a test to see if you are working"
    if echo $VAR | grep " test " >/dev/null 2>&1
    then
        # do stuff for "test"
    elif echo $VAR | grep " working " >/dev/null 2>&1
    then
        # do stuff for "working"
    else
        # do stuff for anything else
    fi
    Or you could use case:
    Code:
    $VAR="this is a test to see if you are working"
    case "$VAR" in
    "* test *")       # do stuff for "test" ;;
    "* working *")    # do stuff for "working" ;;
    *)                # do stuff for anything else ;;
    esac

  3. #3
    drl
    drl is offline
    Linux Engineer drl's Avatar
    Join Date
    Apr 2006
    Location
    Saint Paul, MN, USA / CentOS, Debian, Solaris, SuSE
    Posts
    1,117
    Hi.

    I like case because it is quite readable. There are some builtin pattern matching operators in bash, although they are sometimes overlooked, and probably not portable to all other Bourne-style shells. Making a correction in "$VAR=" to "VAR="and fleshing out the script:
    Code:
    #!/bin/bash
    
    # @(#) s1       Demonstrate limited ability of [[ for patterns.
    
    set -o nounset
    echo
    
    echo "GNU bash $BASH_VERSION" >&2
    
    echo
    
    VAR="this is a test to see if you are working"
    
    echo " Original string = |$VAR|"
    echo " Checking for :test:"
    
    if [[ "$VAR" == *test* ]]
    then
        echo do stuff for "test"
    elif [[ "$VAR" == *working* ]]
    then
        echo do stuff for "working"
    else
        echo do stuff for anything else
    fi
    
    exit 0
    producing:
    Code:
    % ./s1
    
    GNU bash 2.05b.0(1)-release
    
     Original string = |this is a test to see if you are working|
     Checking for :test:
    do stuff for test
    cheers, drl
    [[ expression ]]
    Return a status of 0 or 1 depending on the evaluation of the
    conditional expression expression. Expressions are composed of
    the primaries described below under CONDITIONAL EXPRESSIONS.
    Word splitting and pathname expansion are not performed on the
    words between the [[ and ]]; tilde expansion, parameter and
    variable expansion, arithmetic expansion, command substitution,
    process substitution, and quote removal are performed.

    When the == and != operators are used, the string to the right
    of the operator is considered a pattern and matched according to
    the rules described below under Pattern Matching. The return
    value is 0 if the string matches or does not match the pattern [sic],
    respectively, and 1 otherwise. Any part of the pattern may be
    quoted to force it to be matched as a string.

    -- man bash
    Welcome - get the most out of the forum by reading forum basics and guidelines: click here.
    90% of questions can be answered by using man pages, Quick Search, Advanced Search, Google search, Wikipedia.
    We look forward to helping you with the challenge of the other 10%.
    ( Mn, 2.6.n, AMD-64 3000+, ASUS A8V Deluxe, 1 GB, SATA + IDE, Matrox G400 AGP )

  4. #4
    Just Joined!
    Join Date
    Aug 2007
    Posts
    12
    Gentlemen,

    Thank you very much for your responses. I very much appreciate the help. I have a couple of follow up questions for both of you to help in my understanding of the commands and what they really mean.

    Code:
    if [[ "$VAR" == *test* ]]
    what exactly is this line doing and why? why are the "" needed and why are ** used around test? is this because it is considered a regular expression?

    Code:
    echo $VAR | grep " working " >/dev/null 2>&1
    What exactly does the code at the end do? It looks like it's piping the output to a null but what's the rest of the line do?

    thanks again guys. Much appreciated.

  5. #5
    Trusted Penguin Cabhan's Avatar
    Join Date
    Jan 2005
    Location
    Seattle, WA, USA
    Posts
    3,230
    In the case of the first line, let's start with the quotes. This is because Bash is actually stupid. Bash expands variables exactly as they are. So for instance:
    Code:
    VAR=word
    if [[ $VAR == *test* ]]
    =>
    if [[ word == *test* ]]
    
    VAR=two words
    if [[ $VAR == *test* ]]
    =>
    if [[ two words == *test* ]]
    In the first case, it works fine. But in the second, where $VAR has two words, we end up with an invalid expression. Bash expects only a single statement before the '=='. This is why we use the quotes. This way, in either case, it's just a single statement. In Bash scripting, you almost always want to surround variables in quotes in order to get correct behavior.

    As for the *test*, it's not strictly a regular expression, but rather a shell pattern. This is much simpler than a regex (though it is similar). Shell patterns have character classes (the same as in regexes), and the special characters * and ?. * means 0 or more of any character, and ? means a single character. These do not apply to anything, rather they are placeholders. So for instance, the following all match:
    Code:
    atest => ?test
    btest => ?test
    abctest => *test
    testing => test*
    testing => test???
    .hello => [.a]hello
    ahello => [.a]hello
    and so on. So in this case, we're checking to see if $VAR contains the phrase "test" at any point (that is, "test", with 0 or more characters before or after it).

    For the second block of code, this uses I/O redirection. You can read up on the details at:
    http://www.tldp.org/LDP/abs/html/io-redirection.html

    The nitty gritty that this line is doing:
    - Redirect stdout to /dev/null (a special file that just discards anything it is given)
    - Redirect stderr to wherever stdout is pointing
    All programs have 3 file streams by default:
    stdin (0)
    stdout (1)
    stderr (2)

    The URL I showed you explains how to redirect all of these and the basic pattern of redirection. Also note that if you want to redirect both stdout and stderr to the same place, you can do the way shown here, or use "&> /dev/null".

    Also, the greatest reference I have ever found for Bash scripting is:
    http://www.tldp.org/LDP/abs/html/

    Hope that all makes sense.
    DISTRO=Arch
    Registered Linux User #388732

  6. #6
    drl
    drl is offline
    Linux Engineer drl's Avatar
    Join Date
    Apr 2006
    Location
    Saint Paul, MN, USA / CentOS, Debian, Solaris, SuSE
    Posts
    1,117
    Hi.

    A tip o' the hat to Cabhan for his explanation of why the quotes are so important.

    On a related topic, if you have bash3, and if you wanted to use regular expressions in preference to filename expressions, then you can replace the "==" operator with the "=~" operator:
    Code:
    #!/bin/bash3
    
    # @(#) s2       Demonstrate ability of [[ and =~ for regular expressions.
    
    set -o nounset
    echo
    
    echo "GNU bash $BASH_VERSION" >&2
    echo " MUST USE VERSION 3 FOR REGULAR EXPRESSIONS WITH =~ OPERATOR!"
    
    echo
    
    VAR="this is a test to see if you are working"
    
    echo " Original string = |$VAR|"
    echo " Checking for :test:"
    if [[ "$VAR" =~ test ]]
    then
        echo do stuff for "test"
    elif [[ "$VAR" =~ working ]]
    then
        echo do stuff for "working"
    else
        echo do stuff for anything else
    fi
    
    exit 0
    producing:
    Code:
    % ./s2
    
    GNU bash 3.00.16(1)-release
     MUST USE VERSION 3 FOR REGULAR EXPRESSIONS WITH =~ OPERATOR!
    
     Original string = |this is a test to see if you are working|
     Checking for :test:
    do stuff for test
    See Recipe 6.8, page 122 ff, 480 ff in O'Reilly Media -- Bookstore: bash Cookbook, Albing et al. and man bash3 (or whatever it might be on your system) for details ... cheers, drl
    Welcome - get the most out of the forum by reading forum basics and guidelines: click here.
    90% of questions can be answered by using man pages, Quick Search, Advanced Search, Google search, Wikipedia.
    We look forward to helping you with the challenge of the other 10%.
    ( Mn, 2.6.n, AMD-64 3000+, ASUS A8V Deluxe, 1 GB, SATA + IDE, Matrox G400 AGP )

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  
...