I need to get value from <2018-2099>, if user will type wrong value then script will tell him that value is incorrect and will ask him to type again.
I already have something like this but it doesn't work..
Any suggestions?
#!/bin/bash
read -r -p "Type year [value from 2019-2099]" year
if [[ "$year" =~ ^(20[1-9]|[1-9])+$ ]]; then
mkdir -p "/home/$year/"
else
echo "$year - value is not correct. Try again." >&2 && exit 1
fi
You can use function and until loop to achieve this, consider following code:
readYear() {
read -r -p "Type year [value from 2018-2099]" year
[[ "${year}" =~ ^[0-9]{4}$ ]] && [[ "${year}" -ge 2018 ]] && [[ "${year}" -le 2099 ]]
}
until readYear; do
echo "${year} - value is not correct. Try again." >&2
done
The function returns 0 if the value entered is valid, then the loop terminates.
You can try this:
until
read -r -p "Type year [2019-2099]: " year
[[ $year =~ ^2[0-9]+$ ]] && (( year >= 2018 && year <= 2099 ))
do
echo "Incorrect value" >&2
done
echo "OK: $year"
Related
I have issues with the last if in this example:
#!/bin/bash
sunrise="05:00:00";
currenttime=$(date -u +%H:%M:%S);
sunset="18:00:00"
if [[ "$sunrise" < "$currenttime" ]] ; then
echo works1;
fi
if [[ "$sunset" > "$currenttime" ]] ; then
echo works2;
fi
# during the day:
if [[ "$sunrise" < "$currenttime" ]] && [[ "$currenttime" > "$sunset" ]] ; then
echo works3;
fi
I get the output of the first two echo but not from the last one.
What am I doing wrong?
Of course I'm doing this tests now at 11:30.
If current time is 11:30, then 11:30 is smaller than 18:00 so the last condition of script is false.
Just to make this answer a bit more useful, you can use set -x to print all the steps that the script does which helps to find this kind of bugs.
And also, use "seconds from epoch" when working with time and transform them back at the end of the script: working with integer is much easier and safer than working with strings.
I suspect you want this:
if [[ "$currenttime" <= "$sunrise" ]] ; then
echo "before sunrise"
fi
if [[ "$currenttime" >= "$sunset" ]] ; then
echo "after sunset"
fi
if [[ "$sunrise" < "$currenttime" && "$currenttime" < "$sunset" ]] ; then
echo "daytime"
fi
I am a beginner at unix and I am trying to use a while loop to get a user integer input for 2 numbers, but I need to check if it is an integer and reask if it's not, so I attempted to utilize if statements inside the while loop. I cannot get this to work, what am I doing wrong with the while and if loop?
#! /bin/bash
echo “Enter first number:“
while read number1
do
if[[ $number1 ]] && [ $input -eq $input 2>/dev/null ]
then
echo “$number1”
else
echo "$number1 is not an integer or not defined.Try again”
fi
done
echo “Enter second number:“
while read number2
do
if[[ $number2 ]] && [ $input -eq $input 2>/dev/null ]
then
echo “$number2”
else
echo "$number2 is not an integer or not defined.Try again”
fi
done
If you are trying to get the number and checking it until it becomes integer, Please try the below code.
#!/bin/bash
echo "enter number"
while read number1
do
if ! [[ $number1 =~ ^[0-9]+$ ]]
then
echo "number is not an integer"
else
echo "number is an integer"
exit;
fi
done
I have a bash script:
#!/bin/bash
pathToTestCasesFile=$1
while IFS=';' read -r col1 col2
do
if [[ $col1 == V[0-9]:* ]]; then
echo "decrypt"
if [[ "$(decrypt "$col1")" == "$col2" ]] ; then
echo "$col1 is equal to $col2"
else
echo "$col1 is not equal to $col2"
fi
else
echo "encrypt"
if [[ "$(encrypt $col1)" == "$col2" ]] ; then
echo "$col1 is equal to $col2"
else
echo "$col1 is not equal to $col2"
fi
fi
done < $pathToTestCasesFile
exit 0
Here is the test file:
alex;V1:IVjd9qcAbUrR954gyPDbKw==
V1:IVjd9qcAbUrR954gyPDbKw==;alex
The output looks like this:
encrypt
alex is not equal to V1:IVjd9qcAbUrR954gyPDbKw==
decrypt
V1:IVjd9qcAbUrR954gyPDbKw== is not equal to alex
decrypt
But the output should say that everything is equal.
I am sure that after the commands de -encrypt the value is equal to the other one. I tested it separately.
Maybe there is an issue with the comparisons..
Thanks a lot for helping.
This should work:
#!/bin/bash
while IFS=, read -r col1 col2
do
echo "I got|$col1|$col2|"
if [[ "$col1" =~ V.:.* ]]; then
echo "decrypt"
if [[ "$(decrypt "$col1")" == "$col2" ]] ; then
echo "[$col1] is equal to [$col2]"
else
echo "[$col1] is not equal to [$col2]"
fi
else
echo "encrypt"
if [[ "$(encrypt "$col1")" == "$col2" ]] ; then
echo "[$col1] is equal to [$col2]"
else
echo "[$col1] is not equal to [$col2]"
fi
fi
done < "$pathToTestCasesFile"
for the field separator is used the , comma - as in your code. In the example data you have ;. If you need ; change the IFS=, to IFS=';'.
In BASH shell scripting or using gdate, given a date like "Oct 2011" how do I convert to a year-month number format? Output should be "2011-10", for example.
mydate="Oct 2011"
date --date="$(printf "01 %s" $mydate)" +"%Y-%m"
The parse_datetime interface for GNU date (which is what the example uses) has lots of rules. the Oct 2011 form of the date isn't one of them, so you prepend a "01 " to the front of it and date likes it.
read mon year <<< "Oct 2012"
date -d "$mon 1 $year" "+%Y-%m"
Result:
2012-10
You can convert the month to a number by finding the position of the name string:
#!/bin/bash
month=Oct
months="JanFebMarAprMayJunJulAugSepOctNovDec"
tmp=${months%%$month*}
month=${#tmp}
monthnumber $((month/3+1))
printf "%02d\n" $monthnumber
The output of the script above is:
10
Your specific string you could code:
#!/bin/bash
mydate="Oct 2011"
monthnumber() {
month=$1
months="JanFebMarAprMayJunJulAugSepOctNovDec"
tmp=${months%%$month*}
month=${#tmp}
monthnumber=$((month/3+1))
printf "%02d\n" $monthnumber
}
arr=(`echo ${mydate}`);
month=$(monthnumber ${arr[0]})
year=$(echo ${arr[1]})
echo "$year-$month"
The output would be:
2011-10
case "`date | awk '{print $2 }'`" in
Jan) MON="01" ;;
Feb) MON="02" ;;
Mar) MON="03" ;;
Apr) MON="04" ;;
May) MON="05" ;;
Jun) MON="06" ;;
Jul) MON="07" ;;
Aug) MON="08" ;;
Sep) MON="09" ;;
Oct) MON="10" ;;
Nov) MON="11" ;;
Dec) MON="12" ;;
esac
echo $MON
I'm not sure if there is a shorter way of doing this, but here is one way. This is by no means fool proof. You can improve this by adding other checks to input and make the comparison case insensitive.
#!/bin/ksh
### Validate input
if [ $# -eq 0 ]
then
echo "Usage: $0 InputMonYYYY"
echo "Example: $0 \"Oct 2011\""
exit 1
fi
### Read input
INPUTSTR=$1
MON_STR=`echo $INPUTSTR |cut -d' ' -f1`
YYYY_STR=`echo $INPUTSTR |cut -d' ' -f2`
if [[ "$MON_STR" = "Jan" ]] then
MON_NUM=01
elif [[ "$MON_STR" = "Feb" ]] then
MON_NUM=02
elif [[ "$MON_STR" = "Mar" ]] then
MON_NUM=03
elif [[ "$MON_STR" = "Apr" ]] then
MON_NUM=04
elif [[ "$MON_STR" = "May" ]] then
MON_NUM=05
elif [[ "$MON_STR" = "Jun" ]] then
MON_NUM=06
elif [[ "$MON_STR" = "Jul" ]] then
MON_NUM=07
elif [[ "$MON_STR" = "Aug" ]] then
MON_NUM=08
elif [[ "$MON_STR" = "Sep" ]] then
MON_NUM=09
elif [[ "$MON_STR" = "Oct" ]] then
MON_NUM=10
elif [[ "$MON_STR" = "Nov" ]] then
MON_NUM=11
elif [[ "$MON_STR" = "Dec" ]] then
MON_NUM=12
fi
echo ${YYYY_STR}-${MON_NUM}
Bash4 supports hash-tables (answer by Jim is the correct one though).
Example
#!/bin/bash
declare -A months=( ["Jan"]="01" ["Feb"]="02" )
mydate="Jan 2011"
echo ${mydate:4:8}-"${months["${mydate:0:3}"]}"
Output:
2011-01
Let's kick this dead horse.
If you don't care about invalid month names you can use this function I've written which is quite short (and only does 1 exec) but expects a month to be valid english 3-chars lower or upper case and only requires GNU sed and bash:
m2n() { echo $((-10+$(sed 's/./\U&/g;y/ABCEGLNOPRTUVY/60AC765A77ABB9/;s/./+0x&/g'<<<${1#?}) ));}
For your example I'd do:
read m y <<<"$#"; echo "$y-`m2n $m`"
I found an interesting Bash script that will test if a variable is numeric/integer. I like it, but I do not understand why the "0" is not recognized as a number? I can not ask the author, hi/shi is an anonymous.
#!/bin/bash
n="$1"
echo "Test numeric '$n' "
if ((n)) 2>/dev/null; then
n=$((n))
echo "Yes: $n"
else
echo "No: $n"
fi
Thank you!
UPDATE - Apr 27, 2012.
This is my final code (short version):
#!/bin/bash
ANSWER=0
DEFAULT=5
INDEX=86
read -p 'Not choosing / Wrong typing is equivalent to default (#5): ' ANSWER;
shopt -s extglob
if [[ $ANSWER == ?(-)+([0-9]) ]]
then ANSWER=$((ANSWER));
else ANSWER=$DEFAULT;
fi
if [ $ANSWER -lt 1 ] || [ $ANSWER -gt $INDEX ]
then ANSWER=$DEFAULT;
fi
It doesn't test if it is a numeric/integer. It tests if n evaluates to true or false, if 0 it is false, else (numeric or other character string) it is true.
use pattern matching to test:
if [[ $n == *[^0-9]* ]]; then echo "not numeric"; else echo numeric; fi
That won't match a negative integer though, and it will falsely match an empty string as numeric. For a more precise pattern, enable the shell's extended globbing:
shopt -s extglob
if [[ $n == ?(-)+([0-9]) ]]; then echo numeric; else echo "not numeric"; fi
And to match a fractional number
[[ $n == #(?(-)+([0-9])?(.*(0-9))|?(-)*([0-9]).+([0-9])) ]]