-2

I have a String Variable possible having combinations of Values as Below -

v="2020-01-2020-04,2020-11"

I want the Above values to be converted to an Array as below-

array=(2020-01,2020-02,2020-03,2020-04,2020-11)

Can anyone please help me how can i implement this and interpret the Range part and extract the data in Array accordingly?

Note the Values in the String are Monthdate in Format YYYY-MM

I have tried it using the Below code to Split based on "," but not able to handle the Range-

IN="2020-01-2020-04,2020-11"
arrIN=(${IN//,/ })
echo ${arrIN[1]}         
  • What are you really trying to archive? POSIX shells doesn't support any arrays but the positional `$@` that are set with `set --` explicitly but also set implicitly at different places. – Andreas Louv Jan 21 '22 at 12:25
  • @AndreasLouv bash 4 and above support bot indexd and keyed arrays. https://www.shell-tips.com/bash/arrays/#bash-indexed-array-ordered-lists They are just wonkey at best – Josh Beauregard Jan 21 '22 at 12:44
  • Does this answer your question? [How do I split a string on a delimiter in Bash?](https://stackoverflow.com/questions/918886/how-do-i-split-a-string-on-a-delimiter-in-bash) – Josh Beauregard Jan 21 '22 at 12:47
  • @JoshBeauregard There are ranges in the string – Fravadona Jan 21 '22 at 12:48
  • You can first split on the comma, and then take each item and do some special processing on it if it is a range. Plesae make up your mind whether you want to use bash or sh. You tagged for both, but it does not make much sense in sh, since sh does not have arrays. – user1934428 Jan 21 '22 at 12:57
  • @JoshBeauregard - my question here is how can i handle ranges.. hope im clear – Samrat Saha Jan 21 '22 at 13:15
  • Please review the [help] and in particular [How to ask](/help/how-to-ask) as well as the guidance for providing a [mre]. The problem with too-broad questions is that explaining everything from first principles gets complex, error-prone, long, and boring. – tripleee Jan 21 '22 at 13:17
  • @tripleee - thanks for the suggestion, for now you can forget my post ang ignore and let people who are ready to help let them help – Samrat Saha Jan 21 '22 at 13:19
  • @JoshBeauregard yes, but I refer to POSIX shell, which i assume the [tag:sh] tag means. – Andreas Louv Jan 21 '22 at 15:03

2 Answers2

1

Generating the ranges and storing the dates in a bash array:

  • First define a function that adds a month to a date:
next_month() {
    local y m
    IFS='-' read y m <<< "$1"
    if [ "$m" == 12 ]
    then
        m=1 y=$(( 10#$y + 1 ))
    else
        m=$(( 10#$m + 1 ))
    fi
    printf '%04d-%02d\n' "$y" "$m"
}

which can be trivial with GNU date:

next_month() { date -d "$1-01 +1month" '+%Y-%m'; }

or even BSD date

next_month() { date -j -v '+1m' -f '%Y-%m' "$1" '+%Y-%m'; }
  • Then use it in the main loop that fills the array:
v="2020-01-2020-04,2020-11"

array=()
for date in ${v//,/ }
do
    [[ $date =~ ^([0-9]{4}-(0[1-9]|1[0-2]))(-([0-9]{4}-(0[1-9]|1[0-2])))?$ ]] || continue

    inidate=${BASH_REMATCH[1]}
    enddate=${BASH_REMATCH[4]:-$inidate}

    until [ "$inidate" == "$enddate" ]
    do
        array+=( "$inidate" )
        inidate=$(next_month "$inidate")
    done

    array+=( "$inidate" )
done
  • And you'll get:
declare -p array
# declare -a array='([0]="2020-01" [1]="2020-02" [2]="2020-03" [3]="2020-04" [4]="2020-11")'
Fravadona
  • 13,917
  • 1
  • 23
  • 35
1

With bash, would you please try the following:

#!/bin/bash

v="2020-01-2020-04,2020-11"

IFS=, read -ra a <<< "$v"       # split $v on comma(s) into an array a
for i in "${a[@]}"; do
    if [[ $i =~ ^[0-9]{4}-[0-9]{2}$ ]]; then
        array+=("$i")           # single YYYY-MM
    elif [[ $i =~ ^([0-9]{4})-([0-9]{2})-([0-9]{4})-([0-9]{2})$ ]]; then
                                # range of two YYYY-MM's
        if (( 10#${BASH_REMATCH[1]} != 10#${BASH_REMATCH[3]} )); then
            echo "the range of year not supported."
            exit 1
        else
            for (( j = 10#${BASH_REMATCH[2]}; j <= ${BASH_REMATCH[4]}; j++ )); do
                                # expand the range of months
                array+=( "$(printf "%04d-%02d" $((10#${BASH_REMATCH[1]})) "$j")" )
            done
        fi
    fi
done

(IFS=","; echo "${array[*]}")   # print the result

Output:

2020-01,2020-02,2020-03,2020-04,2020-11
tshiono
  • 21,248
  • 2
  • 14
  • 22