Linux Shell if-statements - linux

I am trying to write a script to add integers together. My first script works to add numbers
for number in $#; do
sum=$(($sum + $number))
done
echo $sum
Now I am trying to write an if statement that checks if $number is an valid integer and if not display an error message and kill the script.
if [ -z $number]; then
sum=$(($sum + $number))
else
echo $number
echo "Sorry, $number is not a number"
exit
fi
I have been trying to figure this out for a few hours and keep getting stuck and help would be nice

The -z operator doesn't check if the string is a number, it checks if the length of the string is zero.
There isn't an operator to check if a string is an integer, however there are several ways to do this in bash. The answers on this previous discussion should be helpful.

the -z test will just test of the variable is empty (zero length) or not. If you want to know that is has an integer you could use a regex match like
if [[ $number =~ ^-?[0-9]+$ ]]; then
sum=$((sum + number))
else
echo "Sorry, $number is not a number"
exit
fi

Related

Bash script that allows one word as user input

Made a script that the user gives a "parameter" and it prints out if it is a file, directory or non of them. This is it :
#!/bin/bash
read parametros
for filename in *
do
if [ -f "$parametros" ];
then
echo "$parametros is a file"
elif [ -d "$parametros" ];
then
echo "$parametros is a directory"
else
echo " There is not such file or directory"
fi
exit
done
Altough i want the user to be allowed to give only one word as a parameter. How do i make this happen ? (For example if user press space after first word there would be an error message showing "wrong input")
#!/bin/bash
read parametros
if [[ "$parametros" = *[[:space:]]* ]]
then
echo "wrong input"
elif [[ -f "$parametros" ]]
then
echo "$parametros is a file"
elif [[ -d "$parametros" ]]
then
echo "$parametros is a directory"
else
echo " There is not such file or directory"
fi
See http://mywiki.wooledge.org/BashFAQ/031 for the difference between [...] and [[...]].
You have to use the $#. It gives the number of the parameters.
The code will be something like:
if [ "$#" -ne 1 ]; then
printf 'ERROR!\n'
exit 1
fi
First, I'm curious why you want to restrict to one word - a file or directory could have spaces in it, but maybe you are preventing that somehow in your context.
Here are a few ways you could approach it:
Validate the input after they enter it - check if it has any spaces, eg: if [[ "parametros" == *" " ]]; then...
Get one character at a time in a while loop, eg with: read -n1 char
Show an error if it's a space
Break the loop if it's 'enter'
Build up the overall string from the entered characters
1 is obviously much simpler, but maybe 2 is worth the effort for the instant feedback that you are hoping for?

Detect number of argument and the value passed into the bash

I want to make sure my bash script can correctly detect user's input argument. Specifically, user can only pass 1 or 2 or 3 into the script, otherwise the script will be terminated. I wrote the following code:
#!/bin/bash
for args in $#
do
echo $args
done
if [ "$#" != 1 ] && [ "$#" -ne 1 ]; then
echo "Illegal number of parameters"
exit 1
fi
This script can only capture when user does not give any input, but cannot check whether user indeed input the number 1 not other values.
By the way, I am not sure how to express "input argument can accept number 1 or 2 or 3".
$# is an integer, so you have to use integer comparison. You can for example say:
if [ "$#" -ne 1 ]; then
echo "illegal number of parameters"
exit 1
fi
To check that the parameter is either 1, 2 or 3, you can use this regular expression (see something related):
if [[ ! $1 =~ ^(1|2|3)$ ]]; then
echo "the number is not 1, 2 or 3"
exit 1
fi
To express "input argument can accept number 1 or 2 or 3" I would for example say "we can just accept the argument being either 1, 2 or 3".
First off you can detect if the string is null or empty simply by doing the following:
if [ -z "$1" ]
then
echo "Argument $1 contains nothing"
fi
That I would say is your first step, and will allow you to filter out args that have no content.
Following on from that, you'd most likely need to do some comparison work on $1, $2 & $3
I'll just check something and come back to this in a moment.
Update
Just had to go find one of my scripts and check something... :-)
One way I've handled the checking of parms in the past is something like the following
#!/bin/sh
while [ $# -gt 0 ] || [ "$#" -le 4 ]; do
case "$1" in
*[!1-9]*) echo "Text: $1";;
*) echo "Number: $1"
esac
case "$2" in
*[!1-9]*) echo "Text: $2";;
*) echo "Number: $2"
esac
case "$3" in
*[!1-9]*) echo "Text: $3";;
*) echo "Number: $3"
esac
shift
done
Basically a simple regex, if I have more than 0 parameters or less than 4 parameters then I allow it through to a case statement, which then checks the content of each parameter.
This one just has an echo in, but you could just as easy set some flags, and then decide how to continue based on those flags.
For simple range checking however, you might just want to use a one liner similar to the following:
if [[ $# -gt 0 && $# -lt 4 ]]; then echo "Correct number of parameters"; fi
Again setting a flag to use later rather than echoing the results.
I assume you mean the input can only be 1, 2 or 3, so using a case statement is the best way. $1 is the variable that stores your argument, if it is equal to 1 case will execute the code in the block corresponding to the value 1 and so on.
case "$1" in
1) ...
;;
2) ...
;;
3) ...
;;
*) echo "Invalid argument"
;;
esac

bash scripting if-else simple issue

Dude, so sorry about the absolute noob question.
What is the problem with the following code?
I like to have a simple script which says MEH! when there is no input arg, otherwise prints it.
#!/bin/bash
if [${#$1}==0] then
echo "MEH!";
else
echo $1;
fi
OS says the line 4 has a error (unexpected token else at line 4).
So sorry dude.
Thanks in advance.
You probably wanted to use:
#!/bin/bash
if [ ${#1} -eq 0 ]; then
echo "MEH!";
else
echo $1
fi
Problems in your current if [${#$1}==0] then condition:
spaces around [ and ] are needed. For further information, you can check the excellent answer by Charles Bailey in Why equal to operator does not work if its not surrounded by space?.
== is used on string comparison. In this case you want integer comparison, that is -eq. See Bash Conditional Expressions in the manual for a full list of them.
In general, if you want to check if your script is receiving at least a parameter, you'd better do:
if [ $# -ge 1 ]; then
echo "$# parameters given"
else
echo "no parameters given"
fi
or also, as commented by Charles Duffy:
if [ -z "$1" ] # true if the variable $1 has length 0
Last and not least: check the comments below, as good information was provided.

Need to validate the length of a variable and perform an action accordingly in unix

We have a variable with a value in it. My requirement is if the length of the variable is greater than 0(zero) do something else do another thing
Step1: I have a variable with some value say
abc="asdfg"
Step2: Determine the length of the variable
xyz=`echo ${#abc}`
Step3: Now I use a If loop to determine if the variable has value greater than 0
if [[$xyz -gt 0]]; then
echo "success"
else
echo "fail"
fi
I am having a problem at step 3. it does not give me a success message. need assistance
You can check if a variable is not zero length with -n
if [ -n $abc ]; then
echo "success"
fi
if [[$xyz -gt 0]]; then
should be:
if [[ $xyz -gt 0 ]]; then
You need spaces between the brackets and parameters.
You can do it easily like this:
VAR=""
if [ "$VAR" ]; then echo Full; fi
VAR="a"
if [ "$VAR" ]; then echo Full; fi
Full
You are missing some spaces around your square brackets.
A short and fast solution to do this is to use ${#var} directly in an if-test:
if (( ${#abc} )); then
# ...
fi
This removes the unnecessary command-substituion that you have there and tests directly on the length. If the length is zero then the test fails.

How do I deal with empty user input in a Bash script?

When the script asks me for input, I get an error if I just press Return without typing in anything. How do I fix this?
Here's the script:
#!/bin/bash
SUM=0
NUM=0
while true
do echo -n "Pruefungspunkte eingeben ('q' zum Beenden): "
read SCORE
if test "$SCORE" == "q"
then echo "Durchschnittspunktzahl: $AVERAGE."
break
else SUM=`expr $SUM + $SCORE`
NUM=`expr $NUM + 1`
AVERAGE=`expr $SUM / $NUM`
fi
done
How about using good bash practices?
#!/bin/bash
sum=0
num=0
while true; do
read -erp "Pruefungspunkte eingeben ('q' zum Beenden): " score
if [[ $score = q ]]; then
echo "Durchschnittspunktzahl: $average."
break
elif [[ $score =~ ^-?[[:digit:]]+$ ]]; then
((sum+=10#$score))
((++num))
((average=sum/num))
else
echo "Bad number"
fi
done
Good practice:
don't use capitalized variable names
use the [[ builtin instead of the test builtin
don't use backticks, use (( to invoke shell arithmetic
to make sure the user inputs a number, check that a number was really entered. The line
elif [[ $score =~ ^-?[[:digit:]]+$ ]]; then
just does that (see regular expressions). Incidentally it completely solves your original problem, since an empty input will not pass through this test
to prevent problems if a user enters 09 instead of 9, force bash to interpret the input in radix 10. That's why I'm using (10#$score) instead of just score.
Use read with the -p (prompt) option, instead of the clumsy combo echo -n / read
This version is much more robust and well-written than yours. Yet, it still has problems:
will break if user needs large numbers
as shell arithmetic is used, only integers can be used. Moreover, the average given by this program is rounded: if you want the average of 1 and 2 you'll have 1.
To fix both problems, you'll probably want to use bc or dc. But that will be the purpose of another question. Or not.
Initialise $SCORE beforehand or handle empty input like you do in q case.
[[ -z "$SCORE" ]] && echo "\$SCORE is zero, e.g. \"\""
This will test if the variable SCORE is empty string.
You should also set AVERAGE=0 at the beginning.

Resources