LinuxQuestions.org
Share your knowledge at the LQ Wiki.
Home Forums Tutorials Articles Register
Go Back   LinuxQuestions.org > Forums > Non-*NIX Forums > Programming
User Name
Password
Programming This forum is for all programming questions.
The question does not have to be directly related to Linux and any language is fair game.

Notices


Reply
  Search this Thread
Old 04-25-2012, 08:36 AM   #1
shayno90
Member
 
Registered: Oct 2009
Distribution: Windows10 Linux Mint NST Kali CentOS
Posts: 203
Blog Entries: 3

Rep: Reputation: 24
Bash script for printing days in a specific month (taking into account a leap year)


I have created a rather long winded bash script to print the number of days in the month, and give information about leap years if the current month is February. However I am having difficulty running it and need a better approach to scripting it if you can help? I am testing with if/elsif/else before trying a case function.

Code:
#!/bin/bash

# Leap year check

currentmonth=$(date +"%B")
month=$(date +%m) 
leap=$(date +%Y)
M1=$01
M2=$02
M3=$03
M4=$04
M5=$05
M6=$06
M7=$07
M8=$08
M9=$09
M10=$10
M11=$11
M12=$12
M13=$13
echo "The current month is $currentmonth"
if [ $month -eq $M1 ]; then
    echo "$month has 31 days"
        elif [ $month -eq $M2 ]; then
            echo "$month has 28 days"
        elif [ $month -eq $M3 ]; then
            echo "$month has 31 days"
        elif [ $month -eq $M4 ]; then
            echo "$month has 30 days"
        elif [ $month -eq $M5 ]; then
            echo "$month has 31 days"
        elif [ $month -eq $M6 ]; then
            echo "$month has 30 days"
        elif [ $month -eq $M7 ]; then
            echo "$month has 31 days"
        elif [ $month -eq $M8 ]; then
            echo "$month has 31 days"
        elif [ $month -eq $M9 ]; then
            echo "$month has 30 days"
        elif [ $month -eq $M10 ]; then
            echo "$month has 31 days"
        elif [ $month -eq $M11 ]; then
            echo "$month has 30 days"
        elif [ $month -eq $M12 ]; then
            echo "$month has 31 days"
else [ $[$leap % 400] -eq "0" ]; then
    echo "This is a leap year. February has 29 days"
fi

Last edited by shayno90; 04-25-2012 at 08:38 AM.
 
Old 04-25-2012, 08:46 AM   #2
MensaWater
LQ Guru
 
Registered: May 2005
Location: Atlanta Georgia USA
Distribution: Redhat (RHEL), CentOS, Fedora, CoreOS, Debian, FreeBSD, HP-UX, Solaris, SCO
Posts: 7,831
Blog Entries: 15

Rep: Reputation: 1669Reputation: 1669Reputation: 1669Reputation: 1669Reputation: 1669Reputation: 1669Reputation: 1669Reputation: 1669Reputation: 1669Reputation: 1669Reputation: 1669
You can use "cal" to get the calendar for any month. In your script you're apparently only interested in the current month so the following would get number of days for current month:

Code:
cal |egrep -v [a-z] |wc -w
The cal command by default shows calendar for current month. The egrep -v tells it to exclude the output for any line that contains letters which will be the Month and Day headers so you're left only with the numeric days. wc -w counts the words which will be the number of days in this case.

You can also specify a given month/year with cal. So if you wanted to see if February 2012 was a leap year you could do:
Code:
cal 2 2012 |egrep -v [a-z] |wc -w
You can even get the number of days in a year by specifying only the year (not month) with cal:
Code:
cal 2012 |egrep -v "[a-z]|[0-9][0-9][0-9]" |wc -w
Note the extra characters in the egrep are to exclude any 3 digit number so would exclude the year header (which is 4 digits) but leave all the days (which are 2 digits).

If interested only in the current year you can specify it with the date command:
Code:
cal $(date +%Y) |egrep -v "[a-z]|[0-9][0-9][0-9]" |wc -w

Last edited by MensaWater; 04-25-2012 at 08:54 AM.
 
1 members found this post helpful.
Old 04-25-2012, 09:00 AM   #3
shayno90
Member
 
Registered: Oct 2009
Distribution: Windows10 Linux Mint NST Kali CentOS
Posts: 203

Original Poster
Blog Entries: 3

Rep: Reputation: 24
Thanks for that MensaWater. I will use that in the future as much simpler. However I am practising some bash scripting with "if/else" statements and was looking for a simpler way to condense the script and achieve the same result as using "cal".
 
Old 04-25-2012, 09:03 AM   #4
catkin
LQ 5k Club
 
Registered: Dec 2008
Location: Tamil Nadu, India
Distribution: Debian
Posts: 8,578
Blog Entries: 31

Rep: Reputation: 1208Reputation: 1208Reputation: 1208Reputation: 1208Reputation: 1208Reputation: 1208Reputation: 1208Reputation: 1208Reputation: 1208
M1=$01 sets the value of M1 to the value of variable 0 with literal string 1 added to it. Try M1=01 etc.
 
Old 04-25-2012, 09:23 AM   #5
catkin
LQ 5k Club
 
Registered: Dec 2008
Location: Tamil Nadu, India
Distribution: Debian
Posts: 8,578
Blog Entries: 31

Rep: Reputation: 1208Reputation: 1208Reputation: 1208Reputation: 1208Reputation: 1208Reputation: 1208Reputation: 1208Reputation: 1208Reputation: 1208
  • You could make the script neater by doing away with the M* variables and dealing with the leap year in the February elif.
  • The variable leap actually holds the year so easier to understand if it has that name.
  • Although the months look like numbers they are actually strings so = is more appropriate than -eq.
  • [[ <test expression> ]] is preferred over [ <test expression> ] for reasons explained here.
  • (( <arithmetic expression> )) is arguably more appropriate for arithmetic testing than the traditional test forms.
  • I would line up the if-elif-else-fi but that is just a personal preference.
Putting that all together:
Code:
#!/bin/bash

# Leap year check

currentmonth=$(date +"%B")
month=$(date +%m) 
year=$(date +%Y)
echo "The current month is $currentmonth"
if [[ $month = 01 ]]; then
    echo "$month has 31 days"
elif [[ $month = 02 ]]; then
    if (( year % 400 != 0 )); then
        echo "$month has 28 days"
    else
        echo "$month has 29 days"
    fi
elif [[ $month -eq 03 ]]; then
    echo "$month has 31 days"
...
elif [[ $month = 12 ]]; then
    echo "$month has 31 days"
else
    echo "Programming error: \$month not in expected 01-012 range: $month" >&2
fi
 
1 members found this post helpful.
Old 04-25-2012, 09:54 AM   #6
shayno90
Member
 
Registered: Oct 2009
Distribution: Windows10 Linux Mint NST Kali CentOS
Posts: 203

Original Poster
Blog Entries: 3

Rep: Reputation: 24
Thanks for that info catkin as I needed to some assistance in trying to formulate an approach to scripting this issue.
Code:
#!/bin/bash

# Leap year check

currentmonth=$(date +%B)
month=$(date +%m) 
year=$(date +%Y)
echo "The current month is $currentmonth"

if [[ $month = 01 ]]; then
    echo "$month has 31 days"
elif [[ $month = 02 ]]; then
    if (( $year % 400 != 0 )); then
        echo "$month has 28 days"
    else 
        echo "$month has 29 days"
    fi            
elif [[ $month = 03 ]]; then
    echo "$month has 31 days"
elif [[ $month = 04 ]]; then
    echo "$month has 30 days"
elif [[ $month = 05 ]]; then
    echo "$month has 31 days"
elif [[ $month = 06 ]]; then
     echo "$month has 30 days"
elif [[ $month = 07 ]]; then
     echo "$month has 31 days"
elif [[ $month = 08 ]]; then
     echo "$month has 31 days"
elif [[ $month = 09 ]]; then
     echo "$month has 30 days"
elif [[ $month = 10 ]]; then
     echo "$month has 31 days"
elif [[ $month = 11 ]]; then
     echo "$month has 30 days"
elif [[ $month = 12 ]]; then
     echo "$month has 31 days"
else
     echo "Programming error: \$month not in expected 01-12 range: $month" >&2
fi
Not correct yet as:
The current month is April
leaptest.sh: 40: [[: not found
leaptest.sh: 40: [[: not found
leaptest.sh: 40: [[: not found
leaptest.sh: 40: [[: not found
leaptest.sh: 40: [[: not found
leaptest.sh: 40: [[: not found
leaptest.sh: 40: [[: not found
leaptest.sh: 40: [[: not found
leaptest.sh: 40: [[: not found
leaptest.sh: 40: [[: not found
leaptest.sh: 40: [[: not found
leaptest.sh: 40: [[: not found
Programming error: $month not in expected 01-12 range: 04

It has a problem with the final "fi" in the script.

Last edited by shayno90; 04-25-2012 at 09:58 AM.
 
Old 04-25-2012, 09:55 AM   #7
grail
LQ Guru
 
Registered: Sep 2009
Location: Perth
Distribution: Manjaro
Posts: 10,007

Rep: Reputation: 3191Reputation: 3191Reputation: 3191Reputation: 3191Reputation: 3191Reputation: 3191Reputation: 3191Reputation: 3191Reputation: 3191Reputation: 3191Reputation: 3191
Personally I would change the ifs into a case to make it cleaner looking:
Code:
#!/bin/bash

currentmonth=$(date +%B)
month=$(date +%m) 
year=$(date +%Y)

case $month in
    0[13578]|10|12) days=31;;
    0[469]|11)	    days=30;;
    *)	(( year % 400 )) && days=29 || days=28
esac

echo "$month has $days days"
 
Old 04-25-2012, 09:56 AM   #8
grail
LQ Guru
 
Registered: Sep 2009
Location: Perth
Distribution: Manjaro
Posts: 10,007

Rep: Reputation: 3191Reputation: 3191Reputation: 3191Reputation: 3191Reputation: 3191Reputation: 3191Reputation: 3191Reputation: 3191Reputation: 3191Reputation: 3191Reputation: 3191
No you need to check your typing:
Code:
if (( $year % 400] != 0 )); then
 
Old 04-25-2012, 09:59 AM   #9
catkin
LQ 5k Club
 
Registered: Dec 2008
Location: Tamil Nadu, India
Distribution: Debian
Posts: 8,578
Blog Entries: 31

Rep: Reputation: 1208Reputation: 1208Reputation: 1208Reputation: 1208Reputation: 1208Reputation: 1208Reputation: 1208Reputation: 1208Reputation: 1208
@grail: the OP is practising with if-elif-else-fi before moving on to case. And well spotted on that typo
 
Old 04-25-2012, 10:01 AM   #10
shayno90
Member
 
Registered: Oct 2009
Distribution: Windows10 Linux Mint NST Kali CentOS
Posts: 203

Original Poster
Blog Entries: 3

Rep: Reputation: 24
Quote:
Originally Posted by grail View Post
No you need to check your typing:
Code:
if (( $year % 400] != 0 )); then
Yes, I noticed this a few minutes ago and changed it but got the same result.
I wanted to try "if/else" statements before moving on to "case" statements.
 
Old 04-25-2012, 10:16 AM   #11
michaelk
Moderator
 
Registered: Aug 2002
Posts: 25,700

Rep: Reputation: 5895Reputation: 5895Reputation: 5895Reputation: 5895Reputation: 5895Reputation: 5895Reputation: 5895Reputation: 5895Reputation: 5895Reputation: 5895Reputation: 5895
FYI leap year check If I remember correctly is:
if(year%400 ==0 || (year%100 != 0 && year%4 == 0))
 
Old 04-25-2012, 10:27 AM   #12
shayno90
Member
 
Registered: Oct 2009
Distribution: Windows10 Linux Mint NST Kali CentOS
Posts: 203

Original Poster
Blog Entries: 3

Rep: Reputation: 24
Quote:
Originally Posted by michaelk View Post
FYI leap year check If I remember correctly is:
if(year%400 ==0 || (year%100 != 0 && year%4 == 0))
Changing to
Code:
 if ( $year % 400 == 0 ) || ($year % 100 != 0 && $year % 4 == 0); then
or
Code:
 if ( ($year % 400 == 0 ) || ($year % 100 != 0 && $year % 4 == 0) ); then

gives the same output error:
leaptest.sh: 40: [[: not found
leaptest.sh: 40: [[: not found
leaptest.sh: 40: [[: not found
leaptest.sh: 40: [[: not found
leaptest.sh: 40: [[: not found
leaptest.sh: 40: [[: not found
leaptest.sh: 40: [[: not found
leaptest.sh: 40: [[: not found
leaptest.sh: 40: [[: not found
leaptest.sh: 40: [[: not found
leaptest.sh: 40: [[: not found
leaptest.sh: 40: [[: not found
Programming error: 04 not in expected 01-12 range: 04

Line 40 is :
Code:
38 else
39     echo "Programming error: $month not in expected 01-12 range: $month" >&2
40 fi

Last edited by shayno90; 04-25-2012 at 10:28 AM.
 
Old 04-25-2012, 10:52 AM   #13
michaelk
Moderator
 
Registered: Aug 2002
Posts: 25,700

Rep: Reputation: 5895Reputation: 5895Reputation: 5895Reputation: 5895Reputation: 5895Reputation: 5895Reputation: 5895Reputation: 5895Reputation: 5895Reputation: 5895Reputation: 5895
Sorry, I did not put the formula in proper bash syntax.
Code:
if (( ($year % 400) == 0 )) || (( ($year%4) == 0 ) && ($year%100) !=0) )); then
  echo "This is a leap year"
else 
  echo "this is not a leap year"
fi
 
Old 04-25-2012, 11:21 AM   #14
shayno90
Member
 
Registered: Oct 2009
Distribution: Windows10 Linux Mint NST Kali CentOS
Posts: 203

Original Poster
Blog Entries: 3

Rep: Reputation: 24
Quote:
Originally Posted by michaelk View Post
Sorry, I did not put the formula in proper bash syntax.
Code:
if (( ($year % 400) == 0 )) || (( ($year%4) == 0 ) && ($year%100) !=0) )); then
  echo "This is a leap year"
else 
  echo "this is not a leap year"
fi
Syntax is not correct for
Code:
if (( ($year % 400) == 0 )) || (( ($year%4) == 0 ) && ($year%100) !=0) )); then
Syntax error: word unexpected (expecting ")")
The test expression brackets need to be changed.

The nested if/else statement for leap year is the issue as the syntax doesn't allow the script to run and results in previous error messages.
 
Old 04-25-2012, 11:26 AM   #15
grail
LQ Guru
 
Registered: Sep 2009
Location: Perth
Distribution: Manjaro
Posts: 10,007

Rep: Reputation: 3191Reputation: 3191Reputation: 3191Reputation: 3191Reputation: 3191Reputation: 3191Reputation: 3191Reputation: 3191Reputation: 3191Reputation: 3191Reputation: 3191
Quote:
@grail: the OP is practising with if-elif-else-fi before moving on to case. And well spotted on that typo
hmmm ... can see a typo but not read the questions and answers

It would appear that the code in post #6 works just fine for me:
Code:
$ ./leap_year.sh
The current month is April
04 has 30 days
Is that the same way you are running the code?
 
  


Reply

Tags
bash scripting



Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is Off
HTML code is Off



Similar Threads
Thread Thread Starter Forum Replies Last Post
How to print out "n" days ago's year, month and day? ArthurHuang Programming 3 02-10-2011 08:33 PM
Is it a leap year? jdwalk Linux - Newbie 4 02-22-2010 06:06 PM
LXer: Taking the Vista leap? LXer Syndicated Linux News 0 05-13-2008 09:20 AM
LXer: Taking the Vista leap? LXer Syndicated Linux News 0 05-13-2008 08:40 AM
Calculating age in days and month in a bash script jachba Programming 5 06-23-2006 01:37 PM

LinuxQuestions.org > Forums > Non-*NIX Forums > Programming

All times are GMT -5. The time now is 07:20 AM.

Main Menu
Advertisement
My LQ
Write for LQ
LinuxQuestions.org is looking for people interested in writing Editorials, Articles, Reviews, and more. If you'd like to contribute content, let us know.
Main Menu
Syndicate
RSS1  Latest Threads
RSS1  LQ News
Twitter: @linuxquestions
Open Source Consulting | Domain Registration