Bash If Statement - Giving up hope - linux

I have tried and tried to solve this and with my limited knowledge of BASH i cannot, I have searched but cannot find anything relating to my issue.
COMMAND_WAIT=$(curl --data "SERIAL_NUMBER="$SERIALNUMBER"" h**p://SERVER/device_check_in.php)
echo $COMMAND
if [ "$COMMAND_WAIT" == "REBOOT" ]; then
echo "Reboot Scheduled"
else
echo "Nothing Found"
fi
I have included an echo command of "COMMAND_WAIT" and this displays "REBOOT" as expected but the if statement will just not work?

Try echoing
echo ">>$COMMAND_WAIT<<"
and see if you have any padding. That might be the culprit.

I prefer to use [[]] instead of [] since [ is a builtin (a command) while [[ is a keyword (see bash manual for more details).
if [[ "$VAR" == "VALUE" ]]
then
echo "true";
else
echo "false";
fi
If it's trailling whitespaces, there's many way to skin that cat like suggested here

Related

Error when checking for substring in Bash

I'm quite new to shell scripting and have encountered an issue when trying to check for substrings within a string.
I want to build code that checks if you are running a 64bit-based system. This is indicated by the output of the uname -m && cat /etc/*release command by the x86_64 in the first line.
Here's my code:
INFO=$(uname -m && cat /etc/*release)
if [ "$INFO" == *"x86_64"* ]
then
echo "You are running a 64bit-based system!"
else
echo "Your system architecture is wrong!"
exit
fi
Although I run a 64-bit based system and the x86_64 shows up in the output of my command, the if statement still returns false, so I get the output Your system architecture is wrong!. It should be the opposite.
Can someone help me out by identifying what I did wrong? I also accept general suggestions for improving my approach, but in the first place, I'd like to know where the bug is.
Many thanks for your help!
[
The command [ is equivalent to test command. test doesn't support any kind of advanced matching. test can compare strings with = - comparing strings with == in test is a bash extension.
By doing:
[ "$INFO" == *"x86_64"* ]
You are actually running command like [ "$INFO" == <the list of files that match"x86_64"pattern> ] - the *"x86_64"* undergoes filename expansion. If you would have a file named something_x86_64_something it would be placed there, the same way cat *"x86_64"* would work.
The bash extensions [[ command supports pattern matching. Do:
if [[ "$INFO" == *"x86_64"* ]]
For portable scripting that will always work with any kind of posix shell use case:
case "$INFO" in
*x86_64*) echo yes; ;;
*) echo no; ;;
esac
With bash version >= 3 you can use a regex:
[[ "$INFO" =~ x86_64 ]]
Unsure why it's so but your code starts working after doubling the square brackets:
INFO=$(uname -m && cat /etc/*release)
if [[ "$INFO" = *x86_64* ]]
then
echo "You are running a 64bit-based system!"
else
echo "Your system architecture is wrong!"
exit
fi
Perhaps some explanation can be found under Is double square brackets [[ ]] preferable over single square brackets [ ] in Bash? and alikes.
One way to check 64 bit is to simply grep the output of /bin/arch
if /bin/arch | grep -q x86_64
then
echo "it is 64 bit"
else
echo "it is not"
fi

Scripts works fine in CentOS but not on RHEL5

Below script works fine on CentOS but not on RHEL5:
#!/bin/bash
read -p "enter your value:" ip
if [[ $ip =~ ^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$ ]]
then
echo "valid"
else
echo "invalid"
fi
Run the script and just pass 192.16666 as input, it will say valid. But if you do the same in CentOS, it will say invalid.
Please let me know what is getting wrong.
Thanks
=~ matching was introduced in Bash 3.0-alpha. The =~ semantics changed in 3.2, but it seems that was only to force text matching for right-hand quoted strings, which is irrelevant for this case. Is the version older than that?
Solved it myself by adding single quotes to the regex, as:
#!/bin/bash
read -p "enter your value:" ip
if [[ $ip =~ '^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$' ]]
then
echo "valid"
else
echo "invalid"
fi
Thanks bdw :)

Does not work to execute command in double brackets in bash

In an attempt to stay consistent i have tried to use double brackets [[ ]] in all my if statements. I did however get into a problem when i was going to check the return value for a command i wanted to run. After testing several ways of creating an if statement i found that only without brackets could i execute a command.
The following does not work:
if [[ $command ]] ; then
echo "something"
fi
if [[ $(command) ]] ; then
echo "something"
fi
if [[ ${command} ]] ; then
echo "something"
fi
and the code above makes the if loop true even when the command was not run.
since the code above doesnt work with braces it doesnt work to use this either:
[[ $command ]] || echo "failed"
and it doesnt work in a subshell either.
The following works:
if $command ; then
echo "something"
fi
if $(command) ; then
echo "something"
fi
Why doesnt it work to place a command in an if loop with brackets, and why does the if loops above report true when it didnt even run the command ? I'm using bash version 4.1.9. Ive tried this many times and the if loops are just as simple as the ones i typed above, it just checks if a command was run successfully and exits if it wasnt.
The short answer is:
[ and [[ expect an expression.
if expects a command.
Saying:
[[ $(command) ]]
would essentially execute:
[[ -n <command_output> ]]
which may or may not be what you want. On the other hand, saying:
$command && echo something || echo other
would echo something or other based on the return code of the command (0 and non-zero respectively).
Double braces are a shortcut for test. In your examples, what's happening is that you're testing the shell variable $command for existence.
if [[ $PWD ]]; then
echo PWD is set to a value
fi
if [[ $NOT_A_REAL_VAR ]]; then
echo Nope, its not set
fi
In your second example, you're using command substitution to check that command output something on standard output.
if [[ $(echo hi) ]]; then
echo "echo said hi'
fi
if [[ $(true) ]]; then #true is a program that just quits with successful exit status
echo "This shouldn't execute"
fi
Your third example is the same as your first, pretty much. You use the curly braces if you want to group your variables. for example if you want to put an 's' after something.
WORD=Bike
echo "$WORDS" #won't work because "WORDS" isn't a variable
echo "${WORD}S" # will output "BikeS"
Then in your fifth example, you are running the program that is sitting inside command.
So, if you want to test some strings, use [[ ]] or [ ]. If you just want to test the exit status of a program, then don't use those, just use a bare if.
Check man test for details on the braces.
If you're just checking the return value of the command, drop the double brackets.
if $command
then
echo "Command succeeded"
else
echo "Command failed: $!"
fi
The double brackets are a test command. (Well, not really, but their a takeoff of the single square brackets that were an alias to the test command.) In early Bourne shell, you would see things like:
if test -z "$string"
then
echo "This is an empty string"
fi
The square brackets were syntactic sugar:
if [ -z "$string" ]
then
echo "This is an empty string"
fi
So, if you're not doing an actual test, you can eliminate the double or single square brackets.
If you're using square brackets, you should use the double ones and not the single ones because the double ones are a bit more forgiving and can do a bit more:
if [ -z $string ] # No quotes: This will actually fail if string is zero bytes!
if [[ -z $string ]] # This will work despite the lack of quotes

Issue controlling script flow

I'm new to shell scripting, my script appears to be okay, but its the flow that I'm having an issue controlling. Could someone point out what silly mistake I've made please.
#! /bin/sh
echo "Are you sure youx want to delete $1? Answer y or n"
read ans
echo $ans
if $ans = "y"|"Y"
then
mv $1 /home/parallels/dustbin
echo "File $1 has been deleted"
else echo "File $1 has not been deleted"
fi
Make your if condition like this:
if [ "$ans" = "y" -o "$ans" = "Y" ]
There are a few things wrong with your script. Some are serious, some are less so.
First, the serious problems.
As guru suggested, you need to use square brackets to surround your if condition. This is because if only tests for the output of a condition, it doesn't perform actual string comparisons. Traditionally, a program called /bin/test, which was also called /bin/[ took care of that. These days, that functionality is built in to the shell, but /bin/sh still behaves as if it's a separate program.
In fact, you can do interesting things with if when you don't use square brackets for your condition. For example, if grep -q 'RE' /path/to/file; then is quite common. The grep -q command issues no output, but simply returns a "success" or "fail" that is detected by if.
Second serious problem is that you are echoing a status that may or may not be true. I call this a serious problem because ... well, log messages simply shouldn't make false claims. If the permissions are wrong for the file in $1, or the filename contains a space, then your mv command will fail, but the message will claim that it did not. More on this later.
Next, the less serious problems.
These are mostly style and optimization things.
First off, read on most platforms includes a -p option that lets you specify a prompt. Use this, and you don't need to include an echo command.
Second, your indenting makes it hard to see what the if construct is wrapping. This isn't a huge problem in a program this small, but as you grow, you REALLY want to follow consistent standards.
Third, you can probably get more flexibility in multiple-choice questions like this if you use case statements instead of if.
After all that, here's how I'd write this script:
#!/bin/sh
if [ "$1" = "-y" ]; then
ans=y
shift
elif [ -t 0 ]; then
read -p "Are you sure you want to delete '$1' (y/N) ? " ans
fi
case "$ans" in
Y*|y*)
retval=0
if [ -z "$1" ]; then
retval=64
echo "ERROR: you didn't specify a filename." >&2
if [ ! -f "$1" ]; then
retval=66
echo "ERROR: file '$1' not found!" >&2
elif mv "$1" /home/parallels/dustbin/; then
echo "File '$1' has been deleted" >&2
else
retval=$?
echo "ERROR: file '$1' could not be deleted!" >&2
fi
;;
*)
echo "ABORT: file '$1' has not been deleted" >&2
retval=4
;;
esac
exit $retval
Aside from what's mentioned above, here are some things in this code snippet:
[ "$1" = "-y" ] - if the user specifies a -y option, then we behave as if the question was answered with a "yes".
[ -t 0 ] - this tests whether we are on an interactive terminal. If we are, then it makes sense to ask questions with read.
Y*|y*) - in a case statement, this matches any string that begins with an upper or lower case "y". Valid affirmative responses would therefore be "Y", "yes", "yellow", etc.
[ ! -f "$1" ] - this tests whether the file exists. You can man test or man sh to see the various tests available in shell. (-f may not be the most appropriate for you.)
>&2 - at the end of a line, sends its output to "standard error" instead of "standard out". This changes how output will be handled by pipes, cron, etc. Errors and log data are often sent to stderr, so that stdout can be dedicated to a program's actual output.
mv "$1" ... - The filename is in quotes. This protects you in case the filename has special characters like spaces in it.
$retval - the values for this came from a best guess of the closest item in man sysexits.
retval=$? - this is the exit status of the most recently executed command. In this case, that means we're assigning mv's exit status to the variable $retval, so that if mv failed, the whole script reports the reason for the fail, as far as mv is concerned.
You can also convert the user response to either case and just check it for respective case like
read ans
ans=${ans,,} # make 'ans' lowercase, or use ${ans^^} for making it uppercase
if [ "$ans" = "y" ]
then
....
fi
Below is the perfect code with error handling included
#!/bin/sh
echo "Are you sure you want to delete $1? Answer y or n"
read ans
echo $ans
if [ $ans == "y" ] || [ $ans == "Y" ]
then
if [ -f $1 ]
then
mv $1 /home/parallels/dustbin
echo "File $1 has been deleted"
else
echo " File $1 is not found"
fi
else
echo "File $1 has not been deleted"
fi

Linux Find Binary File

I am attempting to find a binary file in a Linux system using something like this:
if [ -f `which $1` ] then
echo "File Found"
else
echo "File not Found"
fi
while the code works fine the problem is "which" will return a null operator which BASH interprets as something existing so a file always comes back found. Any suggestions would be great.
Thanks
Update
After a bit more thought, there is no reason to use [[ ]] (or [ ] for that matter). There is even no reason to use command substitution either $()
if which "$1" > /dev/null 2>&1; then
echo "found"
else
echo "not found"
fi
If you're using bash then please use the [[ ]] construct. One of the benefits (among many) is that it doesn't have this problem
[[ -f $(which $1) ]] && echo found
Also, `` is deprecated, use $() instead
if [ `which "$1"` != "" ]; then
which won't return "" when it finds the binary.
I like 'hash' for this (if you're a bash user..) (and it's actually more portable behavior than which)
hash blahblah
bash: hash: lklkj: not found
hash /bin/ls <-- silently successful
This method works on Linux and OSX similarly, where-as 'which' has different behavior.

Resources