views:

247

answers:

3

How do you get the last day of the last month in csh?

Here is the code so far. The cal command below almost works if you execute it from the (FreeBSD sh) command line, but I'm having trouble escaping it properly to run within a script. By almost work, I mean it returns 31, when the last day of February 2010 is 28.

#!/bin/csh
set lastdayoflastmonth=`cal `date '+%m'` `date '+%Y'` | grep . | fmt -1 | tail -1`
echo $lastdayoflastmonth

To be clear:

  • If today is March 26th 2010, it should return the number 28, which is the last day of the February 2010.

  • If today is July 1st 2010, it should return the number 30, which is the last day of June 2010.

Update: working answer received from Joshua Smith in comments below: date -v31d -v-1m '+%d' Thank you!

A: 

I think (if I recall correctly) that you have to double the backticks (``) when 'nesting' them.

Try (untested):

set lastdayoflastmonth=`cal ``date '+%m'`` ``date '+%Y'`` | grep . | fmt -1 | tail -1`
echo $lastdayoflastmonth
ChristopheD
That gives me: "Invalid null command.March 2010 Su Mo Tu We Th Fr Sa 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 032010"
ANE
Are you on Solaris? This link (http://adminschoice.com/solaris-error-messages-e-k#errno98) suggests it is the result of using two or more pipes in a row. I'd try splitting the statement in two 'parts' by redirecting it to a temporary file halfwise and then continuing on the next statement from there...
ChristopheD
+1  A: 

Just use the date command:

date -v31d +'%a'

will give you the date name of the last day of the current month

for next month:

date -v31d -v+1m +'%a'

If you want the previous month:

date -v31d -v-1m +'%a'

-- EDIT: commenter has question about GNU Date ---

If you are using gnu date (the above uses BSD date) you can use the -d flag. It's a little more complicated, though (gnu date doesn't do the same thing with month length fuzziness). to get the last day of the month for last month

for the current month:

date -d "$(date -d "next month" +%Y-%m-1) -1 day" +%a

and for next month

date -d "$(date -d "2 months" +%Y-%m-1) -1 day" +%a

for last month:

date -d "$(date +%Y-%m-1) -1 day" +%a
Joshua Smith
That gives me 03 and 04 respectively, neither of which are the last day of February 2010.
ANE
that's the month %m I changed it to give the day name. You can see the man page for strftime to find out the other codes (for week, hour, etc).
Joshua Smith
That would be `date -v31d +'%d'` then (on my box)
ChristopheD
This seems like it would work, and is nice and short and neat, but the last day of the last month (February 2010) is the 28th, but this gives me 31.
ANE
If you want Feb you would use an offset like -v2m (2nd month of the year). for example:`date -v31d -v2m` +'%d'` would give you 28. or using `date -v31d -v2m +'%a'` would give you Sun (three letter abbrev for day name)
Joshua Smith
date -v31d -v2m +'%d' does produce the right output but only if the current month is March. How do you have date figure out what the last month is automatically, without hardcoding (2nd month of the year)?
ANE
If you want the previous month (ie it is now march but you want feb) you use -v-1m like this `date -v31d -v-1m '+%d'` you can chain the -v options (you can see the whol list of them in the man page).
Joshua Smith
That works. (chaining the -v options) Thanks Joshua!
ANE
Wow! I wish GNU `date` had the `-v` option!
Dennis Williamson
GNU date has the -d option with does pretty much the same things (though with a different syntax).
Joshua Smith
A: 

you can shorten your command to omit the grep/fmt. also, there is no need to cram them into one line.

set month=`date '+%m'`
set year=`date '+%Y'`
set lastdaymonth=`cal $month $year  |tr -s " " "\n"|tail -1`

eg

$ tcsh
$ set month="02"
$ set year="2010"
$ set lastdaymonth=`cal $month $year  |tr -s " " "\n"|tail -1`
$ echo $lastdaymonth
28
$ tcsh --version
tcsh 6.17.00 (Astron) 2009-07-10 (i386-intel-linux) options wide,nls,dl,al,kan,rh,color,filec
ghostdog74
The last day of the last month (February 2010) is the 28th, but this gives me 31.
ANE
no, it does not. it gives me 28
ghostdog74
It returns 31 in csh on FreeBSD, and 31 in csh on Linux. Not sure what you're using?
ANE
i am using tcsh. is csh the only shell you can use?
ghostdog74
Just tried it in tcsh on FreeBSD and tcsh in Linux. It also returns 31. csh is not the only one I can use but tcsh returns the same thing ...
ANE
well, i am not sure what's wrong with your setup. see my edit.
ghostdog74
The problem is with the code I posted up top. date '+%m' doesn't return the last month (02), it returns the current month (03). Am trying to have date spit out the number of the last month, then use that last month number to figure out the number of the last day.
ANE
if you are on linux you should have GNU date. So try `date +%m -d '1 month ago'`
ghostdog74
With GNU date 5.97 I still get 03. However, I need this to work with FreeBSD's date as well without installing a GNU replacement. Thanks though, GD.
ANE