4
\$\begingroup\$
#!/bin/bash

#assigning variables
start="14:00"
duration="150"
title="Exper. Lab"
year="2016"
start2="17:30"
duration2="230"
title2="Calc1"

# Here I refer to dates that the event occurs on piping the variables into gcalcli (Google calendar command line interface) creating a repeated event on my Google calender

for monthday in {09/{1..29..7},09/{6..27..7},10/{4..25..7},10/{6..27..7},11/{1..29..7},11{3..24..7},12/{6..20..7},12/{1..15..7}}
do
(echo $title ; echo "'$monthday/$year $start'"; echo $duration) | ../../../../usr/bin/gcalcli add --calendar 'Class'

done

# Same thing different repeated event





for monthday2 in {09/{12..26..7},10/{3..31..7},11/{7..28..7},12/{5..19..7}}
do
(echo $title2 ; echo "'$monthday2/$year $start2'"; echo $duration2) | ../../../../usr/bin/gcalcli add --calendar 'Class'

done

exit 0

Is there a way I could do this in one loop? Or should I be using another method?

\$\endgroup\$
1
\$\begingroup\$

Your main questions

Is there a way I could do this in one loop?

Yes. The two loops do essentially the same thing, but use different values. The loop should be inside a function, the range of values and the event details should be parameters of the function.

Or should I be using another method?

As it is, the dates of the event are very hard to read. It would be better to have a function that takes start date, end date, and other event details, and use a loop from start date stepping forward one week until the end date is reached.

Furthermore, a "recurring event" is usually not the same event registered n times, but a single event with some parameters. I don't know the API of Google Calendar, but I suggest to check on that, as there might be a much easier method, natural and intuitive method to register a proper recurring event.

Code review

Avoid pointless comments like this one that only state the obvious:

#assigning variables
start="14:00"
duration="150"
title="Exper. Lab"
year="2016"
start2="17:30"
duration2="230"
title2="Calc1"

And there's really no need to define start2, duration2 and title2 at the top of the file. It's unnecessary information at that point. You could define these right before the second loop. You could even reuse the start, duration, title variables. If you did that, the two loop bodies would look identical, and converting to a function would be a trivial step.


Be extremely cautious with long lines like this:

for monthday in {09/{1..29..7},09/{6..27..7},10/{4..25..7},10/{6..27..7},11/{1..29..7},11{3..24..7},12/{6..20..7},12/{1..15..7}}

Can you spot the bug?

Should have been 11/{3..24..7} instead of 11{3..24..7}


A long relative path like this is awful:

... | ../../../../usr/bin/gcalcli add --calendar 'Class'

What if you later need to change the directory of this script or gcalcli? You will have to recalculate the correct depth, and update the script at multiple places (the two loops).

It's better to add ../../../../usr/bin to PATH, and use simply gcalcli. Alternatively, you could define a function like this:

gcalcli() {
    ../../../../usr/bin/gcalcli "$@"
}

Actually, since I don't have gcalcli on my PC, I used this function as a dummy in my tests:

gcalcli() {
    cat
}

Code is easiest to read from top to bottom, with minimal distractions sideways. This line is too long, and I'm forced to scroll to the right to see it:

(echo $title ; echo "'$monthday/$year $start'"; echo $duration) | ../../../../usr/bin/gcalcli add --calendar 'Class'

Avoid multiple statements on one line, break it up like this:

(
echo $title
echo "'$monthday/$year $start'"
echo $duration
) | gcalcli add --calendar 'Class'

Alternative implementation

Consider the alternative implementation below, using some of the suggestions above.

#!/bin/bash

PATH="path_to_gcalcli:$PATH"

add_to_calendar() {
    title=$1
    datetime=$2
    minutes=$3

    (
    echo $title
    echo "'$datetime'"
    echo $minutes
    ) | gcalcli add --calendar 'Class'
}

add_weekly_event() {
    title=$1
    start_time=$2
    minutes=$3
    start_date=$4
    end_date=$5

    event_date=$start_date
    while [[ "$event_date" < "$end_date" ]]; do
        datetime="$(date +%m/%d/%Y -d $event_date) $start_time"
        add_to_calendar "$title" "$datetime" $minutes
        event_date=$(date +%Y/%m/%d -d "$event_date + 1 week")
    done
}

add_weekly_event "Exper. Lab" 14:00 150 2016/09/01 2016/12/21
add_weekly_event "Exper. Lab" 14:00 150 2016/09/06 2016/12/21
add_weekly_event "Calc1" 17:30 230 2016/09/12 2016/12/20

This script is much slower than yours, due to the many calls to date. But it's a lot easier to understand what dates will be added, and it's trivially easy to reuse it for other events.

Note that the add_weekly_event function takes the date parameters in %Y/%m/%d format, where month and day are 0-padded. This is to make the loop condition possible, as the alphabetic ordering of dates in this format coincides with the correct chronological ordering.

Also note that before passing the date to add_to_calendar, it is formatted to (roughly the same) format in your script. I don't know the Google Calendar API, but I suspect this is unnecessary, the %Y/%m/%d format probably works just fine.

For the date parsing and + 1 week calculation, this script depends on GNU date. This is the default on Linux, on other OS you can usually find it in a coreutils package, named gdate. To use gdate instead of date, you can create a function:

date() {
    gdate "$@"
}

But this technique is not my first recommendation. My first recommendation is to check the Google Calendar API to create proper recurring events, instead of manually looping over dates and adding the same event multiple times.

| improve this answer | |
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.