bash check value is integer and in range - variables

I read this stackoverflow question...
Bash: check user input is correct
which does most of what I want however rather then checking it's just an integer I need to check it's an integer in a variable range....
The script looks for files in a directory and then assigns a number to them...
File 1
File 2
File 3
etc....
The user chooses the the number and the script then executes commands against that file.....the variable $FILELIST is the total number of files.
Taking the example from the previous stackoverflow I tried.....
FILENUM=""
while [[ ! ($FILENUM =~ ^[0-$FILELIST]+$) ]]; do
echo " "
echo "Please enter the file number: "
read -p "1 - $FILELIST" FILENUM < /dev/tty
done
echo "$FILENUM"
However this is throwing a syntax error: unexpected "(" (expecting "do") in the while line and I'm not sure why, I suspect $FILELIST has to be bracketed somehow but an explanation as to why the above works would help me understand the problem.
Thanks

bash-specific answers:
You don't need to reinvent the wheel: use the select builtin:
cd /path/to/directory
PS3="Select a file: "
select file in *; do
if [[ $file ]]; then break; fi
done
echo "You selected '$file'"
echo "You selected file number $REPLY"
To check a number is within a certain range, I'd write:
if (( 0 <= $number && $number <= $max )); then echo "in range"; fi
Since you're using ash you might use this as a reference: http://manpages.debian.net/cgi-bin/man.cgi?query=dash
while true; do
FILENUM=""
echo
echo "Please enter the file number: "
read -p "1 - $FILELIST" FILENUM < /dev/tty
if expr "$FILENUM" : '[0-9]\+$' &&
[ $FILENUM -gt 0 ] &&
[ $FILENUM -le $FILELIST ]
then
break
fi
done
echo "$FILENUM"

Related

How do I make a while loop of 2 conditons and stop at true condition

I want to create a while loop that request the user input for yes or no, if the user enter anything else it will loop until the user enters either yes or no
echo "Do you wish to save these settings?"
read response
while [ "$response" != "yes" ] | [ "$response != "no" ]
do
echo "Please enter yes or no only"
echo "Do you wish to save these settings?"
read response
done
when i tried entering yes it still continues to loop but when i enter no it exits the loop
In shell, the | (or pipe) operator is used to filter the output of the command on the left using the command on the right.
For example, the following line of shell:
seq 1 3 | tac
...will result in the lines produced by the command on the left...
1
2
3
...to be filtered by the command on the left (which will emit the lines in reverse order). The output will be:
3
2
1
You're after an operator that performs a boolean operation on the exit statuses of two commands. Since you're looking to continue the loop as long as the response is neither yes or no, the conjunction operator (&&) is what you're after:
echo "Do you wish to save these settings?"
read response
while [ "$response" != "yes" ] && [ "$response" != "no" ]
do
echo "Please enter yes or no only"
echo "Do you wish to save these settings?"
read response
done
If the bash shell will always be available wherever you're running your script, this could be improved further by using [[ ... ]] instead of [ ... ]. Besides a potential performance benefit, another advantage of using [[ is that the requirements on strict quoting are relaxed:
echo "Do you wish to save these settings?"
read response
while [[ $response != yes ]] && [[ $response != no ]]
do
echo "Please enter yes or no only"
echo "Do you wish to save these settings?"
read response
done
A further improvement comes from the knowledge that [[ supports && to conjoin two boolean expressions:
echo "Do you wish to save these settings?"
read response
while [[ $response != yes && $response != no ]]
do
echo "Please enter yes or no only"
echo "Do you wish to save these settings?"
read response
done
Just while true the whole thing until satisfied:
while true
do
echo "Do you wish to save these settings?"
read response
if [[ "$response" = "yes" ]] || [[ "$response" = "no" ]]
then
break
fi
echo "Please enter yes or no only"
done

Calling gammu or gammu-smsd-inject

I have gammu-smsd up and running on a raspberry-pi with jessie. I am using runonreceive to process incoming texts. I have the following script working using runonreceive. In the script I am calling gammu sendsms instead of gammu-smsd-inject as the documentation states. All other references state gammu will not work while gammu-smsd daemon is running. The only reason I got this to work is after pulling my hair out trying to get gammu-smsd-inject to work. Can anyone explain what is going on?
RunOnReceive = /home/jaalfs/bin/sms_back.sh
sms_back.sh
#!/bin/bash
from=$SMS_1_NUMBER
echo "sms_back" >> /home/jaalfs/bin/sms_back.log
echo "Test from: $from" >> /home/jaalfs/bin/sms_back.log
echo -e "\n"
if [ "$from" != "+1310xxxxxxx" ]; then
echo -e "not accepted number \n" >> /home/jaalfs/bin/sms_back.log
exit 0
else
echo "accepted number" >> /home/jaalfs/bin/sms_back.log
echo "hello world!!!!!!" | sudo gammu sendsms TEXT "$from"
echo -e " text sent back \n" >> /home/jaalfs/bin/sms_back.log
exit 0
fi
exit 1

String comparison in ksh never succeeding

I have the next script, and when trying to compare variable value if equals "NO" or "SI" (yes in spanish) it's not working for some reason I keep going all the time through the else (SI) although the real value in the variable is "NO". It's even being printed in the email subject.
I fear I could be some extra invisible character I can't see but it's there?
Here is the script:
#!/usr/bin/ksh
VAR=$(/home/userName/scripts/loadedresource.ksh | egrep 'SI|NO')
MAIL_FILE="testfile.txt"
rm -f $MAIL_FILE
echo "From:Script" > $MAIL_FILE
echo "To:Me<me#company.com>" >> $MAIL_FILE
echo "Subject:RESOURCE LOADED-> $VAR" >> $MAIL_FILE
echo "Content-Type: text/html" >> $MAIL_FILE
echo "<html>" >> $MAIL_FILE
echo "<body style='font-family:calibri;font-size:14px;'>" >> $MAIL_FILE
if [ "$VAR" == "NO" ]
then
echo "<h2> Resource not loaded, please open ticket </h2>" >> $MAIL_FILE
else
echo "<h2> Resource loaded successfully </h2>" >> $MAIL_FILE
fi
mail me#company.com < $MAIL_FILE
== is not a valid comparison operator in POSIX test. If your particular implementation of ksh doesn't implement an extension adding it, you may need to use
if [ "$VAR" = "NO" ]
rather than
if [ "$VAR" == "NO" ]
I'd also consider using egrep -o 'SI|NO' to leave out any other characters from the output of grep, if your copy has GNU extensions.
As another option, consider:
result=$(/home/userName/scripts/loadedresource.ksh)
case $result in
*SI*) echo "Yes" ;;
*NO*) echo "No" ;;
*) echo "Unknown" ;;
esac
As a performance enhancement, by the way:
{
echo "hello"
echo "world"
} >output.txt
...is considerably more efficient than
echo "hello" >output.txt
echo "world" >>output.txt
...which re-opens the output file once for each line.

Ignore ORA-28011 in sqlplus in bash script

I am using sqlplus in a shell script and I am using WHENEVER SQLERROR EXIT 8 and WHENEVER OSERROR EXIT 9 so that I can catch errors using $?.
I will be putting this code on a server that I know gets the password expiry warning/error 'ORA-28011'.
My question is, will my script catch on 'ORA-28011' even though it isn't really an error? If so, how would I go about ignoring it?
My (simplified) code, if it helps:
[...]
CONNECTION_STRING=$USER/$PASS#$TNS
RESULT=$(sqlplus -s /nolog <<-EOF
WHENEVER OSERROR EXIT 9;
WHENEVER SQLERROR EXIT 8;
$OPTIONS
CONNECT $CONNECTION_STRING
$DB_SQL
COMMIT;
EOF)
RETURN_CODE=$?
echo "db_exec: Result -> $RETURN_CODE\n$RESULT"
if [ $RETURN_CODE -eq 0 ]
then
echo "$RESULT"
return 0
else
echo "db_exec: Failed"
return 1
fi
In case anyone is interested, I solved this problem.
ORA-28011 and ORA-28002 do not cause SQL*Plus to exit when using WHENEVER SQLERROR EXIT # or WHENEVER OSERROR EXIT # but will appear in the result. Therefore the code in my question will work, but I need to remove these errors. My updated code is below:
# Run the SQL with the options specified
RESULT=$(sqlplus -s /nolog <<-EOF
WHENEVER SQLERROR EXIT 4;
WHENEVER OSERROR EXIT 5;
SPOOL $TEMP_FILE;
$DB_OPTIONS
$DB_CONNECT
$DB_SQL
COMMIT;
EOF)
# Save the return code
RETURN_CODE=$?
# Log the result
echo "Result -> Code: $RETURN_CODE\n$RESULT" 1>&2
if [ $( grep -cE '^ORA-28002:|^ORA-28011:' $TEMP_FILE) -ge 1 ]
then
echo "Warning -> Password Expiry \n$(grep '^ORA-' $TEMP_FILE)" 1>&2
fi
# Check the return code and catch any SQL*Plus (SP2-) errors that might not have presented an error code
if [ $RETURN_CODE -eq 0 ] && [ $(grep -c '^SP2-[0-9][0-9][0-9][0-9]' $TEMP_FILE) -eq 0 ]
then
# Echo the result, but remove any lines regarding password expiry
echo "$RESULT" | grep -v "^ERROR:" | grep -v "^ORA-[0-9][0-9][0-9][0-9][0-9]"
rm $TEMP_FILE
echo "Success" 1>&2
return 0
elif [ $RETURN_CODE -eq 4 ]
then
echo "Failed -> SQL Error \n$(grep '^ORA-' $TEMP_FILE) $(grep '^SP2-' $TEMP_FILE)" 1>&2
return 4
elif [ $RETURN_CODE -eq 5 ]
then
echo "Failed -> OS Error \n$(grep '^ORA-' $TEMP_FILE) $(grep '^SP2-' $TEMP_FILE)" 1>&2
return 5
elif [ $(grep -c "^SP2-[0-9][0-9][0-9][0-9]" $TEMP_FILE) -ne 0 ]
then
echo "Failed -> SQL*Plus Error \n$(grep '^SP2-' $TEMP_FILE)" 1>&2
return 6
else
echo "Unknown error -> $RETURN_CODE\n$RESULT" 1>&2
return 3
fi

Trying to make grep a variable

#!/bin/bash
echo "Please type the file name"
read filename
echo "Please type the word or phrase you wish to look for"
read string
grep '$string' /home/pi/$filename
I was wondering how I could make grep a variable so I could use a code like this:
if [ $var=~$string ];
then
echo "the string is there
else
echo "sorry string doesn't exist"
To assign the output of grep to a variable:
var = $(grep '$string' /home/pi/$filename)
EDIT
As #staticx pointed out, in your case, where you grep for $string and see if the result again matches $string, it would be easier just to see if grep finds the element by piping it wc -l.
count = $(grep '$string' /home/pi/$filename | wc -l)
if [ count -gt 0 ]; then
# do stuff
fi