Search code examples
linuxbashif-statementvariablesgrep

how can i use grep result from a variable in if/else statment


i am trying to create a condition statement that checks if the grep found if a package is installed. if it is true , then the package should not be installed , and if it is false , then the package should be installed. i am always getting the same result package is not installed no matter which value i put please help (in my case the all packages are installed and grep finds a match. here is code:

chk1=$(yum list installed | grep rpmdevtools) 
chk2=$(yum list installed | grep rpmbuild)
chk3=$(yum list installed | grep rpmdev)
if [[ $chk1 -ne 0 && "$chk2" -ne 0 && "$chk3" -ne 0 ]];then
   echo "package exists"
   sleep 5
else
   echo "package doesn't exists installing .."
   sleep 5
   sudo yum install wget -y
   wget http://mirror.centos.org/centos/7/os/x86_64/Packages/rpmdevtools-8.3-5.el7.noarch.rpm
   sudo yum install rpmdevtools-8.3-5.el7.noarch.rpm -y
fi

Solution

  • You're mixing 2 types of results here : result (i.e. displayed text) and return value.

    TL;DR

    You can verify if the variable $chkX is not empty with [[ ! -z ${chkX} ]], such as :

    if [[ ! -z ${chk1} ]] && [[ ! -z ${chk2} ]] && [[ ! -z ${chk3} ]]; then
    [...]
    

    Or you can do something like this, based on exit codes.

    yum list installed | grep -q vim
    if [[ $? -eq 0 ]]; then
      # do your stuff here when package is installed
    else
      #.. do your stuff here when package isn't installed ..
    fi
    

    or

    if yum list installed | grep -q 'vim' ;then
      # do your stuff here when package is installed
    else
      # .. do your stuff here when package isn't installed ..
    fi
    
    

    When executing in a subshell through $(yum ...) you are storing the result (i.e. displayed text) that's echoed by the command.
    For instance:

    $> yum list installed | grep vim
    vim-common.x86_64                                 2:8.2.3755-1.fc35                    @updates       
    

    If you want the return code or exit code, it's accessible through $?.
    For example:

    $> ls
    [...]
    $> echo $?
    0
    $> ls toto
    ls: cannot access 'toto': No such file or directory
    $> echo $?
    2
    

    Note every command changes the exit code.
    So accessing twice $? will change its value.

    $> ls toto
    ls: cannot access 'toto': No such file or directory
    $> echo $?
    2
    $> echo $?
    0
    

    In your case, you're testing if the text given by yum is mathematically equal to 0:

    chk3=$(yum list installed | grep rpmdev)
    if [[ $chk1 -ne 0 && "$chk2" -ne 0 && "$chk3" -ne 0 ]];then
                                                 ^^^^^^
    

    It's not possible because :

    • no package found -> empty variable
    • one or many package found -> single or multiline text with package information.
    • and you'll never get 0.

    If you run it with test you have various cases of failure:

    # note: rpmdevtools is not installed on by computer
    $> chk1=$(yum list installed | grep rpmdevtools) 
    $> test $chk1 -ne 0
    bash: test: -ne: unary operator expected
    
    # multiple vim-* packages are installed
    $> chk1=$(yum list installed | grep vim) 
    $> test $chk1 -ne 0
    bash: test: too many arguments