Check a user's input is correctly formatted - linux

I'm trying to validate a user's input when they enter a date into my bash script.
The correct format should be YYYY-MM-DD HH:MM:SS
What I have so far is this, but it's not quite right.
read -p "-" datetime
if [[ $datetime ! "*[^2000-2100]-[^01-12]-[^10-31] [^00-24]:[^00-60]:[^00-60]*" ]]
then
echo "Not a date"
fi

You could say:
if ! date -d "$datetime" >/dev/null 2>&1; then
echo "Not a date"
fi
Using regexp isn't really recommended, but if you insist you could say:
if [[ "$datetime" != 2[0-1][0-9][0-9]-[0-1][0-9]-[0-3][0-9]\ [0-2][0-9]:[0-6][0-9]:[0-6][0-9] ]]; then
then
echo "Not a date"
fi

Related

Check string after cat command in bash

How do I check if a string is contained in the text produced by a cat command in bash? I want to execute a certain action if the string is found in the text.
Like this, using the pipe :
cat my_file | grep my_string
if [ ! $(cat my_file.txt | grep my_text) == "" ]
then echo "exists"
else
echo "not exists"
fi;
Piping to grep is fine if it's a one-time match. Otherwise in bash you can match strings using patterns (==) or regexes (=~) like this:
# date looks like "Mon, Jun 22, 2020 11:04:54 AM"
today=$(date)
[[ $today == Mon* ]] && echo "It's the start of the week"
[[ $today =~ ^(Tue|Wed|Thu) ]] && echo "It's the middle of the week"
[[ $today == Fri* ]] && echo "Thank God It's Friday!"
This is really a comment on the other answer - you can just directly test the exit status of a command
# grep succeeds (exit status 0) if there's a match
# grep -q is to suppress the output of the matched line
# we just care whether there is a match or not
if grep -q my_text my_file.txt; then
echo "exists"
else
echo "not exists"
fi
Simply:
if grep -q my_text file; then
echo "exists"
else
echo "not exists"
fi

How do I read all dates between start date and end date in linux

I want to read all dates between two range of dates and this ranges includes both start date and end date
input_start_date="2013-09-05"
input_end_date="2013-09-10"
START_DATE=$(date -I -d "$input_start_date") || exit -1
END_DATE=$(date -I -d "$input_end_date") || exit -1
d="$START_DATE"
while [ "$d" <= "$END_DATE" ]; do
echo $d
d=$(date -I -d "$d + 1 day")
done
but when I ran the above code I get below error
bash: = 2013-09-10: No such file or directory
Could someone help me to fix this issue
Expected output
2013-09-05
2013-09-06
2013-09-07
2013-09-08
2013-09-09
2013-09-10
start=2013-09-05
end=2013-09-10
while [[ $start < $end ]]
do
printf "$start\n"; start=$(date -d "$start + 1 day" +"%Y-%m-%d")
done
or you can try this one
END=$(date -d "2013-09-10" +%s);
DATE=$(date -d "2013-09-05" +%s);
while [[ "$DATE" -le "$END" ]]; do date -d "#$DATE" +%F; let DATE+=86400; done
The idea is right, but you just got the operator wrong, <= does not work with date strings in bash, you needed a inequality operator != in the condition.
while [ "$d" != "$enddate" ]; do
The <= operator works when used in arithmetic context in bash with the ((..)) operator.
Something little in awk (changed the range a bit since there was no test data, just the expected output):
$ awk '$0>="2013-09-06" && $0<="2013-09-09"' file
2013-09-06
2013-09-07
2013-09-08
2013-09-09
You kind of need a do-while loop here, which bash does not provide. How about
date="$start_date"
while true; do
echo "$date"
[[ $date = "$end_date" ]] && break
date=$(date -d "$date + 1 day" "+%F")
done
Don't use ALL_CAPS_VAR_NAMES -- too easy to mistakenly overwrite shell/system vars.

Bash backup checker [duplicate]

This question already has answers here:
How do I set a variable to the output of a command in Bash?
(15 answers)
Closed 6 years ago.
I'm trying to compare dates from a file and the current day.
The script should run every day and if the dates do not compare it should give a warning.
I made a test file with a 2015 date, but it keeps saying its "equal" to the current date.
#!/bin/bash
today= date +"%m-%d-%y"
filedate= date +"%m-%d-%y" -r fileName.txt
if [ $today == $filedate ];
then
echo $today;
echo $filedate;
echo 'Backup OK';
else
echo $today;
echo $filedate;
echo 'Backup ERROR';
fi
find utility is your friend.
modified=$(find fileName.txt -mtime -1)
if [[ -n $modified ]]; then
echo OK
else
echo ERROR
fi
As a piece of advice you may have to read carefully what atime and ctime means to the system time.
You can assign the date output to the today and filedate variables using command substitution. And you'd better double quote your variables in your comparison test:
today=$(date +"%m-%d-%y")
filedate=$(date +"%m-%d-%y" -r fileName.txt)
echo $today
echo $filedate
if [ "$today" == "$filedate" ];
then
echo $today;
echo $filedate;
echo 'Backup OK';
else
echo $today;
echo $filedate;
echo 'Backup ERROR';
fi
This works for me.
today=$(date +"%m-%d-%y")
filedate=$(date +"%m-%d-%y" -r fileName.txt)
echo $today
echo $filedate
if [ "$today" == "$filedate" ];
then
echo $today;
echo $filedate;
echo 'Backup OK';
else
echo $today;
echo $filedate;
echo 'Backup ERROR';
fi

bash condition with regular expression

I'm going to learn bash programming. I just wrote a simple script in order to read numbers from input stream and check them to be in valid numerical format using regular expression.
in fact script should take input until the input be nonnumerical.
but it doesn't work properly.
code:
i=0
echo "plz enter number in valid format: "
while true
do
read input
if [[ $input =~ *[^0-9]* ]]; then
echo "YOU DIDN'T ENTER A VALID NUMBER"
break
else
arr[$i]=$input
echo $input >> inputnums
fi
done
when i enter a number or character condition is true. I mean i have echo "message" in output.
You're mixing shell globing with regex, change your if condition to:
if [[ $input =~ [^0-9] ]]; then
regex should use .* not * as used by shell shell glob.
Remove the * from the regex:
#!/bin/bash
i=0
echo "plz enter number in valid format: "
while true
do
read input
if [[ $input =~ ^[^0-9]+$ ]]; then
echo "YOU DIDN'T ENTER A VALID NUMBER"
break
else
arr[$i]=$input
echo $input
fi
done

check if argument is a valid date in bash shell

I am writing a bash shell script in Linux, this program will accept a date (mm-dd-yyyy) as a parameter. I am wondering if there is a simply way to check if the date is valid? is there an operator and I can just use test to check?
You can check with date -d "datestring"
So date -d "12/31/2012" is valid, but using hyphens, e.g. date -d "12-31-2012", is not valid for date.
You can also use words: date -d 'yesterday' or date -d '1 week ago' are both valid.
You can extract the day, month, and year values from the input date value MM-DD-YYYY and validate it as the unambiguous (ISO) format YYYY-MM-DD instead (you can validate a DD-MM-YYY formatted date as "correct" using date, e.g. 25-12-2010, but it is not a valid MM-DD-YYY date, hence the need to change the date format first)
A valid date in the correct format is OK
30th November 2005 is valid:
$ DATE=11-30-2005; d=${DATE:3:2}; m=${DATE:0:2}; Y=${DATE:6:4}; echo "year=$Y, month=$m, day=$d"; if date -d "$Y-$m-$d" &> /dev/null; then echo VALID; else echo INVALID; fi
year=2005, month=11, day=30
VALID
$ DATE=11-30-2005; if date -d "${DATE:6:4}-${DATE:0:2}-${DATE:3:2}" &> /dev/null; then echo VALID; else echo INVALID; fi
VALID
An invalid date in the correct format is NOT OK
31st November 2005 does not validate:
$ DATE=11-31-2005; d=${DATE:3:2}; m=${DATE:0:2}; Y=${DATE:6:4}; echo "year=$Y, month=$m, day=$d"; if date -d "$Y-$m-$d" &> /dev/null; then echo VALID; else echo INVALID; fi
year=2005, month=11, day=31
INVALID
$ DATE=11-31-2005; if date -d "${DATE:6:4}-${DATE:0:2}-${DATE:3:2}" &> /dev/null; then echo VALID; else echo INVALID; fi
INVALID
A valid date in the incorrect format is NOT OK
20th April 1979 in DD-MM-YYYY format does not validate as a MM-DD-YYYY date:
$ DATE=20-04-1979; d=${DATE:3:2}; m=${DATE:0:2}; Y=${DATE:6:4}; echo "year=$Y, month=$m, day=$d"; if date -d "$Y-$m-$d" &> /dev/null; then echo VALID; else echo INVALID; fi
year=1979, month=20, day=04
INVALID
$ DATE=20-04-1979; if date -d "${DATE:6:4}-${DATE:0:2}-${DATE:3:2}" &> /dev/null; then echo VALID; else echo INVALID; fi
INVALID
Alternate simpler method: use BASH variable string replace hyphens to slashes
$ DATE="04-30-2005"; [[ $(date -d "${DATE//-/\/}" 2> /dev/null) ]] && echo VALID || echo INVALID
VALID
$ DATE="04-31-2005"; [[ $(date -d "${DATE//-/\/}" 2> /dev/null) ]] && echo VALID || echo INVALID
INVALID
For script use, I kept it as simple as I could. Testing the date value with the date function then checking the exit code of the process.
date -d "02/01/2000" 2>: 1>:; echo $?
This will redirect the standard in and standard error to null : and using echo to return the exit code with $? allows me to check for 0=good date and 1=bad date.
The following worked well for me. Many thanks to my co-worker, Tyler Chamberlain, for the OSX solution.
# Validate a given date/time in Bash on either Linux or Mac (OSX).
# Expected date/time format (in quotes from the command line): YYYY-MM-DD HH:MM:SS
# Example(s): ./this_script "2012-02-29 13:00:00" # IS valid
# ./this_script "2013-02-29 13:00:00" # Is NOT valid
START_DATETIME=$1
function report_error_and_exit
{
local MSG=$1
echo "$MSG" >&2
exit 1
}
# We can use OSTYPE to determine what OS we're running on.
# From http://stackoverflow.com/questions/394230/detect-the-os-from-a-bash-script
# Determine whether the given START_DATETIME is valid.
if [[ "$OSTYPE" == "linux-gnu" ]]
then
# Validate the date on a Linux machine (Redhat or Debian). On Linux, this is
# as easy as adding one minute and checking the return code. If one minute
# cannot be added, then the starting value is not a valid date/time.
date -d "$START_DATETIME UTC + 1 min" +"%F %T" &> /dev/null
test $? -eq 0 || report_error_and_exit "'$START_DATETIME' is not a valid date/time value. $OSTYPE"
elif [[ "$OSTYPE" == "darwin"* ]]
then
# Validate the date on a Mac (OSX). This is done by adding and subtracting
# one minute from the given date/time. If the resulting date/time string is identical
# to the given date/time string, then the given date/time is valid. If not, then the
# given date/time is invalid.
TEST_DATETIME=$(date -v+1M -v-1M -jf "%F %T" "$START_DATETIME" +"%F %T" 2> /dev/null)
if [[ "$TEST_DATETIME" != "$START_DATETIME" ]]
then
report_error_and_exit "'$START_DATETIME' is not a valid date/time value. $OSTYPE"
fi
fi
echo "The date/time is valid."
I tested this script on a Red Hat-based system, a Debian-based system and OSX, and it worked as expected on all three platforms. I did not have time to test on Windows (Cygwin).
For validation of YYYY-MM-DD (ISO 8601) dates on OSX in the BASH shell, the following approach validates both the format and the date.
isYYYYMMDDdate() {
[[ "$1" =~ ^[0-9]{4}-[0-9]{2}-[0-9]{2}$ ]] && [[ "$1" == $(date -r $(date -j -f "%Y-%m-%d" "$1" "+%s") '+%Y-%m-%d') ]] &> /dev/null; echo "$?"
}
It first uses a regular expression match to check the format.
Then, it converts the date to epoch time and then back to a date.
If the original and twice-converted dates match, then it is valid.
Test a valid date: 2005-11-30
$ isYYYYMMDDdate 2005-11-30
0
Test an invalid date: 2005-11-31
$ isYYYYMMDDdate 2005-11-31
1
Test a valid date formatted incorrectly: 1979-20-04
$ isYYYYMMDDdate 1979-20-04
1
The date command will parse a date given with the -d argument. If the date is invalid, an error message is printed to STDERR and date exits with an error status. If the date is valid, it prints the date on STDOUT and exits with a success status.
Because of this, date -d "$date" can be used directly in a bash if statement.
The first wrinkle is that to prevent printing a message for valid dates, you need to redirect STDOUT to /dev/null using >/dev/null.
The second wrinkle is that date accepts an empty string as a valid date without complaint. In most cases, that should mean that your user didn't enter a date when they should have. You will want to test for an empty date separately using the test [ "z$date" != "z" ]
date also accepts a variety of formats. If you are using actual bash (as opposed to dash or some of ther sh variety, you could use regular expressions against your preferred format in place of a simple check for an empty string. For example to check my preferred ISO format, I would use: [[ "$date" =~ ^[0-9]{4}-[0-9]{2}-[0-9]{2}$ ]]
date=2001-01-01
if [ "z$date" != "z" ] && date -d "$date" >/dev/null
then
echo "VALID DATE"
fi
If you try this with an invalid date (such as 2001-01-53), it doesn't get into the if and it prints out:
date: invalid date ‘2001-01-53’
Alternately, you could check if the date is invalid and exit:
date=2001-01-01
if [ "z$date" == "z" ]
then
echo "No date specified"
exit 1
fi
if ! [[ "$date" =~ ^[0-9]{4}-[0-9]{2}-[0-9]{2}$ ]]
then
echo "Expected date in YYYY-MM-DD format"
exit 1
fi
if ! date -d "$date" >/dev/null
then
exit 1
fi
echo "VALID DATE"
case statements make it easy to support multiple formats and capturing date-parts, i.e.
case ${date} in
[0-3][0-9]-[0-1][0-9]-[0-9][0-9][0-9][0-9] )
yr=...
mn=...
dy=...
;;
[0-1][0-9]-[0-3][0-9]-[0-9][0-9][0-9][0-9] )
yr=...
dy=...
mn=...
;;
.... other formats
;;
* )
echo "ERROR on date format, from value=$date, expected formats ..."
return 1
;;
esac
I hope this helps.
You can use the strptime() function available in Python's time or datetime modules or Perl's Time::Piece module.

Resources