So I've been trying to write a shell script that shows background processes at a specific date. Here is the problem:: the date is a parameter given by the user. I read the date and validated it, but i don't know what command to use. Also, i tried using ps command but to no success. I do not know if my date format is ok either. Here is what I did:
#!/bin/bash
echo "Date dd-mm-yyyy"
read date
if [[ $date =~ ^[0-9]{2}-[0-9]{2}-[0-9]{4}$ ]]
then echo "Date is valid"
else echo "Date is not valid"
fi
Any help would be much appreciated.
if I understand your question you are trying to validate date format in a shell script, so you have to check form of the input using the regex as below :
#! /bin/bash
isDateInvalid()
{
DATE="${1}"
# Autorized separator char ['space', '/', '.', '_', '-']
SEPAR="([ \/._-])?"
# Date format day[01..31], month[01,03,05,07,08,10,12], year[1900..2099]
DATE_1="((([123][0]|[012][1-9])|3[1])${SEPAR}(0[13578]|1[02])${SEPAR}(19|20)[0-9][0-9])"
# Date format day[01..30], month[04,06,09,11], year[1900..2099]
DATE_2="(([123][0]|[012][1-9])${SEPAR}(0[469]|11)${SEPAR}(19|20)[0-9][0-9])"
# Date format day[01..28], month[02], year[1900..2099]
DATE_3="(([12][0]|[01][1-9]|2[1-8])${SEPAR}02${SEPAR}(19|20)[0-9][0-9])"
# Date format day[29], month[02], year[1904..2096]
DATE_4="(29${SEPAR}02${SEPAR}(19|20(0[48]|[2468][048]|[13579][26])))"
# Match the date in the Regex
if ! [[ "${DATE}" =~ "^(${DATE_1}|${DATE_2}|${DATE_3}|${DATE_4})$" ]]
then
echo -e "ERROR - '${DATE}' invalid!"
else
echo "${DATE} is valid"
fi
}
echo
echo "Exp 1: "`isDateInvalid '12/13/3000'`
echo "Exp 2: "`isDateInvalid '12/11/2014'`
echo "Exp 3: "`isDateInvalid '12 01 2020'`
echo "Exp 4: "`isDateInvalid '28-02-2014'`
echo "Exp 5: "`isDateInvalid '12_02_2002'`
echo "Exp 6: "`isDateInvalid '12.10.2099'`
echo "Exp 7: "`isDateInvalid '31/11/2001'`
Related
Hay everyone,
i want to Implement a dat2iso command as a script or as an alias, which accepts a date in German format DD.MM.YYYY as a parameter and outputs the date in ISO format YYYYMMDD as output (on stdout).
Examples (as an alias or as a script in the system path;
outputs:
$ dat2iso 30.09.2021
20210930
$ dat2iso 01.01.2022
20220101
$ dat2iso 03/10/2021
Error! <-- Because the separator was. required.
$ dat2iso 03.10.21
Error! <-- Because the year YYYY was prescribed with four digits.
$ dat2iso 32.09.2021
Error! <-- Denn einen 32. gibt es nicht.
$ dat2iso 30.13.2021
Error! <-- Because there is no 13th month.
i have come sofar to change the formate but i cant figure the rest but im still working on it:
echo 30.09.2021 | awk -F '.' {'printf "%s%s%s\n",$3,$2,$1'}
A very verbose solution, but it checks for your given exemptions:
cat << EOF > dat2iso
#!/bin/bash
if [[ "\$1" == "" ]];then echo -e "NO INPUT. Exiting."; exit 1 ;fi
echo \$1 | awk -F '.' '/\//{ print "Input Error."; exit(1) }
\$1>31{ print "Too many days."; exit(1) }
\$2>12{ print "Too many months."; exit(1) }
\$3!~/[[:digit:]][[:digit:]][[:digit:]][[:digit:]]/{ print "Not enough year digits."; exit(1) }
{ print \$3\$2\$1 }'
EOF
chmod +x dat2iso
$ ./dat2iso 09.12.2021
20211209
This should achieve what you expected :
#!/bin/bash
dat2iso(){
if [[ $1 =~ ^([[:digit:]]{2})\.([[:digit:]]{2})\.([[:digit:]]{4})$ ]]; then
local date="${BASH_REMATCH[3]}${BASH_REMATCH[2]}${BASH_REMATCH[1]}"
if date -d "$date" >& /dev/null; then
echo "$date"
else
echo "Invalid date value [$date]" >&2
fi
else
echo "Invalid format of input [$1]. Correct format [DD.MM.YYYY]" >&2
fi
}
dat2iso 30.09.2021
I have a little problem here. I am trying to write a script shell that shows background processes, but at a certain date. The date is a positional parameter. I've searched on Internet about the date validation, but all the info I found got me confused. I'm fairly new at this so a little help would be appreciated.
How do I verify if the date parameter is in a valid format in my shell script?
you can use regex :
#! /bin/bash
isDateInvalid()
{
DATE="${1}"
# Autorized separator char ['space', '/', '.', '_', '-']
SEPAR="([ \/._-])?"
# Date format day[01..31], month[01,03,05,07,08,10,12], year[1900..2099]
DATE_1="((([123][0]|[012][1-9])|3[1])${SEPAR}(0[13578]|1[02])${SEPAR}(19|20)[0-9][0-9])"
# Date format day[01..30], month[04,06,09,11], year[1900..2099]
DATE_2="(([123][0]|[012][1-9])${SEPAR}(0[469]|11)${SEPAR}(19|20)[0-9][0-9])"
# Date format day[01..28], month[02], year[1900..2099]
DATE_3="(([12][0]|[01][1-9]|2[1-8])${SEPAR}02${SEPAR}(19|20)[0-9][0-9])"
# Date format day[29], month[02], year[1904..2096]
DATE_4="(29${SEPAR}02${SEPAR}(19|20(0[48]|[2468][048]|[13579][26])))"
# Match the date in the Regex
if ! [[ "${DATE}" =~ "^(${DATE_1}|${DATE_2}|${DATE_3}|${DATE_4})$" ]]
then
echo -e "ERROR - '${DATE}' invalid!"
else
echo "${DATE} is valid"
fi
}
echo
echo "Exp 1: "`isDateInvalid '12/13/3550'`
echo "Exp 2: "`isDateInvalid '12/11/20322'`
echo "Exp 3: "`isDateInvalid '12 01 2000'`
echo "Exp 4: "`isDateInvalid '28-02-2014'`
echo "Exp 5: "`isDateInvalid '12_02_2002'`
echo "Exp 6: "`isDateInvalid '12.10.2099'`
echo "Exp 7: "`isDateInvalid '31/11/2020'`
If I'm understanding correctly, you want to input a date and filter background processes by that input and you are looking for a way to validate the input using the shell?
If you can break out the year/month/day into a slash-separated format, you can use the date command to test if the date stamp is valid. This runs under bash, other shells may be different
bad
$ echo -n "year :"; read year; echo -n "month :"; read month; echo -n "day :"; read day; date -d "$year/$month/$day" || echo "Not a valid date"
year :9999
month :32
day :32
date: invalid date ‘9999/32/32’
Not a valid date
good
$ echo -n "year :"; read year; echo -n "month :"; read month; echo -n "day :"; read day; date -d "$year/$month/$day" || echo "Not a valid date"
year :2020
month :3
day :23
Mon Mar 23 00:00:00 CDT 2020
I want to check whether its AM or PM in a shell script. I have tried this:
if ( `date "+%p"` -eq "AM" ); then echo "Yes"; else "NO"; fi
But it shows:
AM: command not found
Also tried = instead of -eq.
Two issues in your current statement:
1) the format specifier %p in GNU date utility may contain lowercase of either AM or PM - depending on your current locale. It's better to use %P specifier as it contains lowercase presentation
2) In bash, -eq - is integer comparison operator, not for string comparison
The right way would be:
if [ `date +%P` = "am" ]; then echo 'Yes'; else echo 'No'; fi
To deal with any locale you may compare the current hour value (given by %H) with midday hour 12:
if [ `date +%H` -lt 12 ]; then echo 'Yes'; else echo 'No'; fi
The locale can specify language- and/or country- specific strings to use in place of am and pm. For example:
$ LC_TIME=hu_HU date +%P
de
$ LC_TIME=fr_FR date +%P
$ LC_TIME=en_EN date +%P
pm
Instead, check the hour to see which half of the day would be used to provide a value for %P:
h=$(date +%H)
if (( h < 12 )); then
echo YES # am
else
echo NO # pm
fi
Or, force a known locale:
ampm=$(LC_TIME=C date +%P)
if [[ $ampm = am ]]; then
...
else
...
fi
here
# String comparision with =
# [ ] instead if ()
if [ `date "+%p"` = "AM" ]; then
echo "Yes";
else
echo "NO"; # Missed echo here
fi
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
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.