Reputation: 9093
I'm trying to get the first day of the next quartal, for example now I'd like to get 00:01 2012-01-01
. It shouldn't be too difficult. But I'm stuck with a syntax error because I can't manage to escape everything correctly.
To get the correct month I want to use:
expr `date "+( ( %m - 1 ) / 3 + 1 ) * 3 % 12 + 1"`
The part ( %m - 1 ) / 3 + 1
calculates the number of the current quartal.
However, the *
seems to be wrong there somehow. If I replace it by +
there is no syntax error (the result is just not interesting for me...). I tried to escape the *
by using \*
but this doesn't help. I suppose there is some problem with the backticks.
How can I escape the *
correctly?
Edit: My problem is already solved, but I want to add a short warning for others. Note that you would need to add also leading zeros for the month, if you want to use it directly in a date and to care also about the correct year. So at the end of the day, paxdiablo's suggestion is probably the easiest.
Upvotes: 1
Views: 4087
Reputation: 882226
If you don't mind coding up a bash
function to do this, you can use something like the following getNextQuarter
function:
# getNextQuarter - returns YYYY-MM-DD for the first day of the next quarter.
getNextQuarter() {
m="$(date +%m)"
case $m in
'01' | '02' | '03') echo "$(date +%Y)-04-01" ;;
'04' | '05' | '06') echo "$(date +%Y)-07-01" ;;
'07' | '08' | '09') echo "$(date +%Y)-10-01" ;;
'10' | '11' | '12') echo "$(expr $(date +%Y) + 1)-01-01" ;;
esac
}
nq=$(getNextQuarter)
echo $nq
Even in a shell script, you should consider the readability improvements that can be gained from using well-named functions over possibly cryptic one-liners.
Now that probably won't be blindingly fast but, to be honest, if speed was your main concern, I would be revisiting shell scripts anyway.
Think of what others (or even you six months from now) will think of your code when viewing it. I like to live on the assumption that those who have to maintain my code are psychopaths who know where I live.
Upvotes: 3
Reputation: 6488
The first problem was that * was considered a wildcard after being output by date. I solved this using $[]
(equivalent to $(())
) instead of expr
.
The second issue (at least here on Mac OS X) is that the '%' needs to be escaped by using '%%' (which is valid on all versions of date):
$ echo $(($(date "+( ( %m - 1 ) / 3 + 1 ) * 3 %% 12 + 1")))
1
An alternative I found was using eval, after correctly escaping parentheses:
$ eval "expr $(date "+\( \( %m - 1 \) / 3 + 1 \) '*' 3 %% 12 + 1")"
Both alternatives can be zero-padded using printf
:
$ printf "%02d\n" $(($(date "+( ( %m - 1 ) / 3 + 1 ) * 3 %% 12 + 1")))
01
$ printf "%02d\n" $(eval "expr $(date "+\( \( %m - 1 \) / 3 + 1 \) '*' 3 %% 12 + 1")")
01
Upvotes: 1
Reputation: 27233
You can disable glob expansion using set
, run your calculation and re-enable glob expansion:
set -o noglob
expr `date "+( ( %m - 1 ) / 3 + 1 ) * 3 % 12 + 1"`
set +o noglob
Upvotes: 1
Reputation: 121810
Surround your whole expression with double quotes: the problem is that you have spaces in your command substitution, which doesn't please expr
.
This yields a number, however I surmise you can use arithmetic evaluation more efficiently there:
fge@erwin ~ $ expr "`date "+( ( %m - 1 ) / 3 + 1 ) * 3 % 12 + 1"`"
( ( 12 - 1 ) / 3 + 1 ) * 3 % 12 + 1
fge@erwin ~ $ echo $(($(expr "`date "+( ( %m - 1 ) / 3 + 1 ) * 3 % 12 + 1"`")))
1
Upvotes: 0