Using 'grep' in nested if-statement - bash

I'm still finding my way around bash scripting so please bear with me.
At the moment I am trying to write a script that checks a few on a server.
Once check is to see if the GPU driver has is the latest version.
However regardless of the installed GPU driver on the server, the script returns GPU is not upgraded
Here is the code:
#!/bin/bash -x
######################################################
#GENERAL VARIABLES
GPU_DRIVER=270.41.19
######################################################
#Checking if Packsges are Installed
if [ $(uname -r) != $KERNEL_VERSION ]
then
echo "Kernel is not Upgraded"
#INSTALL KENRENL!
#REBOOT!
else if [ ! $(nvidia-smi -q |grep -q $GPU_DRIVER) ]
then
echo "GPU is not Upgraded"
else if [ $(cat /usr/ort/build_number) != $CODE_RELEASE ]
then
echo "Code Release526 Has not Been Installed"
fi
fi
fi
I would like to know why the condition in the if-statement does not apply?
NOTE:
The output of the nvidia-smi looks similar to below:
:~/script$ nvidia-smi -q|grep Driver
Driver Version : 270.41.19
Driver Model

You want to test whether a grep succeeded or failed. That does not require [...] or $(...). You merely need to execute the grep. Contrary to popular belief, [ is not part of the if statement syntax; it is a bash command which succeeds or fails based on the evaluation of a conditional expression. (Usually, you would want to use [[, which is a better conditional evaluator.) The if statement is followed by a series of ordinary bash statements; followed by the keyword then. If the last statement succeeds, the then branch is taken; otherwise the else branch is taken.
Change
else if [ ! $(nvidia-smi -q |grep -q $GPU_DRIVER) ]
to
elif ! nvidia-smi -q | grep -q -F "$GPU_DRIVER"; then
(And the elif will remove the need for the fi matching that if.)
Aside from removing the test built-in ([), I fixed a couple of other things:
grep normally expects patterns to be regexes. In a regex, a . matches any character. I think you are looking for a precise match, so I added the -F flag.
And I put quotes around the $GPU_DRIVER, just in case.
To explain the if ... then ... elif ... fi syntax, here's the entire if statement:
if [[ $(uname -r) != $KERNEL_VERSION ]]; then
echo "Kernel is not Upgraded"
#INSTALL KENRENL!
#REBOOT!
elif ! nvidia-smi -q |grep -q -F "$GPU_DRIVER"; then
echo "GPU is not Upgraded"
elif [[ $(cat /usr/ort/build_number) != $CODE_RELEASE ]]; then
echo "Code Release526 Has not Been Installed"
fi

The grep -q does't return/print anything. It actually sets the return value as 0 or 1. You can check this using $?. So effectively your if statement becomes
[ ! $() ]
The $() returns false always. This results in the behavior you have defined.

Related

How to check if the output of a command contains a string and then run a command if the string exists

Example
if "darwin" in $MACHTYPE;
then
echo "whoa it's a mac!"
fi
And the output should be
whoa it's a mac, if darwin is found in the output of $MACHTYPE
Please guide me!
Provided you're using bash, you could use the =~ operator:
if [[ "$MACHTYPE" =~ "darwin" ]];
then
echo "whoa it's a mac!"
fi
From the bash man page:
An additional binary operator, =~, is available, with the same precedence as == and !=. When it is used, the string to the right of the operator is considered an extended regular expression and matched accordingly (as in regex(3)).
If you don't have a version of bash which supports regular expressions then you can use globbing:
if [[ $MACHTYPE = *darwin* ]]
then
echo "whoa it's a mac!"
fi
Note that you must use [[, not [.
Other shells like sh might support [[ but that is not guaranteed by the standard.
You could evaluate your command directly, for example:
if uname -a | grep -i "darwin" > /dev/null; then
echo "it is a mac"
fi
In this case, grep will exit 0 if found a value and output will be redirected to /dev/null if try then you can call your command, in this case: echo "it is a mac"
The code below can get the output of your command on the cmd, then check if there has the specific word.
command="command here"
if[ `echo $command | grep -c "\"darwin\""` -gt 0 ]; then
Do anything you want here
fi

Getting Bad substitution error with a Shell Script on a mac?

I'm getting an error message "./query.sh: line 5: ${1,,}: bad substitution" whenever I run a shell script in a Mac OSX terminal
#!/bin/bash
dir=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )
if [ "$1" != "" ]; then
letter1=$(echo ${1,,}|(cut -b1))new
if [[ $letter1 == [a-zA-Z0-9] ]]; then
if [ -f "$dir/data/$letter1" ]; then
grep -ai "^$1" "$dir/data/$letter1"
else
letter2=$(echo ${1,,}|cut -b2)
if [[ $letter2 == [a-zA-Z0-9] ]]; then
if [ -f "$dir/data/$letter1/$letter2" ]; then
grep -ai "^$1" "$dir/data/$letter1/$letter2"
else
letter3=$(echo ${1,,}|cut -b3)
if [[ $letter3 == [a-zA-Z0-9] ]]; then
if [ -f "$dir/data/$letter1/$letter2/$letter3" ]; then
grep -ai "^$1" "$dir/data/$letter1/$letter2/$letter3"
fi
else
if [ -f "$dir/data/$letter1/$letter2/symbols" ]; then
grep -ai "^$1" "$dir/data/$letter1/$letter2/symbols"
fi
fi
fi
else
if [ -f "$dir/data/$letter1/symbols" ]; then
grep -ai "^$1" "$dir/data/$letter1/symbols"
fi
fi
fi
else
if [ -f "$dir/data/symbols" ]; then
grep -ai "^$1" "$dir/data/symbols"
fi
fi
else
echo "[*] Example: ./query name#domain.com"
fi
The scripts function is to search throuhg a huge number of data files so could anybody help me pinpoint the source of the problem ?
The ,, operator was introduced in bash 4.0, but /bin/bash on macOS is still version 3.2. You can install a newer version of bash and change your shebang accordingly, or you can use letter1=$(echo "$1" | tr '[:upper:]' '[:lower:]' | cut -b1) instead.
(You can, however, use ${letter:0:1}, ${letter:1:1}, etc, in place of a call to cut to get a single letter from the string.)
My advice is to treat /bin/bash on macOS as nothing more than a POSIX-compatible shell. Use #!/bin/sh if you want a portable script, or use #!/usr/local/bin/bash (or whatever is appropriate, after installing a new version of bash) if you want to take advantage of bash extensions at the expense of portability.
If you are using a subshell to produce the value anyway, you might as well change the call to something which is portable back to earlier versions of Bash.
Running cut -b1 in a subshell (in parentheses) is useless and doing it after the conversion means you convert a potentially long string and then discard everything except the first character.
letter1=$(echo "${1:0:1}" | tr '[:upper:]' '[:lower:]')new
Notice also the double quotes around the argument to echo.
Do you really want the suffix new to be attached to the value? The first condition in the if can never match in that case.
You should probably also refactor the code to avoid the deep "arrow antipattern" and only perform the grep once you have a value for the file name you want to search.
As mentioned in other answers, the builtin bash on Mac is very old and must be upgraded to use some operators, e.g. the caret operator. If you use homebrew, run brew install bash and follow the instructions in this post.

Need some help writing an if statement in UNIX bash scripting

I'm writing a reasonably lengthy script (or what I would consider lengthy - you could probably do it in a few hours). I basically have a file (named .restore.info) which contains files of names. In part of the script, I want to test "If cannot find filename in .restore.info, then says “Error: restored file does not exist”. Apologies if this doesn't make sense for you guys (for me, it does in the grand scheme of things). So if type this in the command line:
sh MYSCRIPT filename
It will search for the string filename in the .restore.info file, and if it cant find anything, it should produce an error message.
Basically, I need the top line of this coded translated into a UNIX bash statement and something that actually makes sense!:
If grep $1 .restore.info returns an exist status of 1; then
echo “Filename does not exist!”
fi
Thanks in advance! Please ask me if you need me to clarify anything more clearly as I know I'm not the best explainer, and I'll get back to you in less than a minute! (+rep and best answer of course will be given!)
You probably only care if grep exits with a non-zero exit status:
if ! grep -q "$1" .restore.info; then
echo "Filename does not exist!"
fi
but if you really do care about a specific exit status (1, in this case):
if ! grep -q "$1" .restore.info && [[ $? -eq 1 ]]; then
echo "Filename does not exist!"
fi
Use grep -q
grep -q "filename" .restore.info && echo "found match"
or
! grep -q "filename" .restore.info && echo "not found"
grep -l 'filename' .restore.info
if [ $? = 0 ];then
echo "found it"
else
echo "not found"
fi

Bash: if (command) |(command)

I know that the following command returns 0 (true) or 1 (false) in the following conditions:
hdparm -C /dev/sda |grep "active/idle"
true if the disk is active, false otherwise. I'd like to programmatically use this result to display another text or use it for monitoring. I've tried with this, but it doesn't work (syntax error):
if [ hdparm -C /dev/sda |grep "active/idle" ]; then
echo sda1 is ON
else
echo sda1 is OFF
fi
How does it work correctly?
Also, is there a clearly understandable, definitive guide on Bash conditional expressions somewhere that would explain all the different kinds of expression statements for every possible situation?
I usually just simply use
if hdparm -C /dev/sda | grep -q 'active/idle' ; then
echo sda1 is ON
else
echo sda1 id OFF
fi
Wrap the conditional statement inside a subshell:
if [ -z "$(hdparm -C /dev/sda |grep "active/idle")" ]; then
-z tests the empty string here. Probably you also have to replace active/idle with active.
EDIT: as #abasu suggests, in this case, it's better to test for the return code of grep, which will be 0 if the expression was matched:
hdparm -C /dev/sda | grep -q "active/idle"
status=$?
if [ $status -eq 0]; then
You will find all details on conditional statements on test man page. However, your shell may expand the syntax further, like bash does.

Debugging BASH IF Conditions

I am getting an error when I try and run my assignment.
#!/bin/bash
## Assignment 2
echo Please enter a User Name:
read u
if [ $u!="root"]; then
echo Searching for Username!
grep $u /etc/passwd|sed 's/$u/hidden/gi'
elif [ $u!="toor"]; then
echo Root is NOT allowed.
else
echo Toor is definetely NOT allowed.
fi
Output:
Please enter a User Name:
user1
./assign2.sh: line 6: [bthiessen: command not found
./assign2.sh: line 9: [bthiessen: command not found
Toor is definetely NOT allowed.
What is wrong with my if statements?
Try that :
#!/bin/bash
echo Please enter a User Name:
read u
if [[ $u != "root" ]]; then
echo Searching for Username!
grep "$u" /etc/passwd | sed "s/$u/hidden/gi"
elif [[ $u != "toor" ]]; then
echo Root is NOT allowed.
else
echo Toor is definetely NOT allowed.
fi
problems founds :
[ $u!="root"] need spaces around !=
if you use variables in sed, you need " quotes, not simple '
note :
[[ is a bash keyword similar to (but more powerful than) the [ command. See http://mywiki.wooledge.org/BashFAQ/031 and http://mywiki.wooledge.org/BashGuide/TestsAndConditionals . Unless you're writing for POSIX sh, we recommend [[
Learn the difference between ' and " and `. See http://mywiki.wooledge.org/Quotes and http://wiki.bash-hackers.org/syntax/words
Whitespace counts here:
if [[ $u!="root" ]]; then
And:
elif [[ $u!="toor" ]]; then
Also prefer [[ over [.
if [ $u!="root"]; then
elif [ $u!="toor"]; then
There needs to be spaces inside the square brackets, and around the != operator. The whitespace is required. It's also good practice to quote "$u" in case the username has spaces or is blank.
if [ "$u" != "root" ]; then
elif [ "$u" != "toor" ]; then
There are other issues with your script which I suppose should be left to you to find.
To debug bash scripts, you can also use bash -x and set -x:
bash -x script.sh runs an existing script with debug messages, it will echo lines before executing them.
With set -x you can enable this behavior directly in your shell script, e.g. in the first line after the shebang. (This is kind of like echo on in Windows scripting.) set +x disables this option.
It is even possible, although hardly useful, to set -x in interactive shells.
This is all nicely explained in the Bash Guide for Beginners, under Debugging Bash scripts.

Resources