2

I'm writing a function that outputs dates. I'd like to allow the user to customize the output by supplying arguments to date with an environment variable. To preserve white space in format strings, I'd like to accept args in an array like this:

function argdates {
    while [ $# -gt 0 ] && date "${DATE_ARGS[@]}" -d @$1
    do shift
    done
}

The user might want to use an array if they have spaces in a date format string:

DATE_ARGS=( -u "+%y/%U, %I%p %a" )
argdates 1476395008 1493172224

# output:
# 16/41, 09PM Thu
# 17/17, 02AM Wed

But in this case, an array might be overkill:

DATE_ARGS="-u -Iseconds"
argdates 1476395008 1493172224

# output:
# date: invalid option -- ' '
# Try 'date --help' for more information.

# output should be:
# 2016-10-13T21:43:28+00:00
# 2017-04-26T02:03:44+00:00

I don't want to require an array for simple cases like this. Is it possible to tell what type the variable is?

  • related unix.stackexchange.com/q/246026/38906 – cuonglm Apr 13 '17 at 4:25
  • In the second case, what's so hard about writing DATE_ARGS=(-u -Iseconds)? – Barmar Apr 13 '17 at 6:22
  • You can't export an array as an environment variable. See stackoverflow.com/questions/5564418/… – Barmar Apr 13 '17 at 6:25
  • @Barmar yes that's basically where I'm at right now: Assume end user is comfortable creating a bash array. But the common way to export arguments for a script to use is the second example, not with an array. – Travis Well Apr 13 '17 at 6:26
1

It seems to me that you may want to let your function pass on any command line options directly to GNU date while treating numerical non-option specially:

argdates () {
    local -a opts
    local timestamp

    while [ "$#" -gt 0 ] && [ "$1" != '--' ] && [[ "$1" != [0-9]* ]]; do
        opts+=( "$1" )
        shift
    done
    [ "$1" = '--' ] && shift

    for timestamp do
        date "${opts[@]}" -d "@$timestamp"
    done

    # or, with a single invocation of "date":
    # printf '@%s\n' "$@" | date "${opts[@]}" -f -
}

This bash function would go through its command line arguments and save them in the opts array, until it hits an argument which is -- (the standard way of signalling the end of options) or that starts with a digit. Each argument saved into opts is shifted off of the list of command line arguments.

Once an argument has been found that is not an option to date, we assume that the rest of the arguments are UNIX epoch timestamps and loop over these, calling date with our saved options for each timestamp. See the comment in the code for how to do this looping more efficiently.

Example invocations:

$ argdates 1476395008 1493172224
Thu Oct 13 23:43:28 CEST 2016
Wed Apr 26 04:03:44 CEST 2017
$ argdates -- 1476395008 1493172224
Thu Oct 13 23:43:28 CEST 2016
Wed Apr 26 04:03:44 CEST 2017
$ argdates +%D 1476395008 1493172224
10/13/16
04/26/17
$ argdates +%F 1476395008 1493172224
2016-10-13
2017-04-26
$ argdates -u 1476395008 1493172224
Thu Oct 13 21:43:28 UTC 2016
Wed Apr 26 02:03:44 UTC 2017
$ argdates -u -Iseconds 1476395008 1493172224
2016-10-13T21:43:28+00:00
2017-04-26T02:03:44+00:00
0

You could do that much easier by giving up on using arrays and letting the user specify DATE_ARGS simply as a string that should be inserted in the command line of date:

$ argdates(){
    for d; do printf %s "$DATE_ARGS" | xargs date -d "@$d"; done
}
$ DATE_ARGS='-u "+%y/%U, %I%p %a"' argdates 1476395008 1493172224
16/41, 09PM Thu
17/17, 02AM Wed
$ DATE_ARGS='-u -Iseconds' argdates 1476395008 1493172224
2016-10-13T21:43:28+00:00
2017-04-26T02:03:44+00:00

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.