1

I'm trying to create sequences as follows:

startDay=1
endDay=2
dayRange="{$startDay..$endDay}"
echo \[\"$dayRange\",\"{00..02}\"\]

The output is:

["{1..2}","00"] ["{1..2}","01"] ["{1..2}","02"]

When specifying the sequence directly {00..02}, it auto creates "00", "01", "02", but it does not understand the dayRange variable. What I expect it to return is:

["1","00"] ["1","01"] ["1","02"] ["2","00"] ["2","01"] ["2","02"] 

Not sure what I missed. Please advise.

Duc Tran
  • 6,016
  • 4
  • 34
  • 42
  • Brace expansion happens **before** parameter expansion. By the time `$startDay` and `$endDay` are replaced with actual values, `{1..2}`-style expansions are no longer being run. – Charles Duffy Jul 29 '21 at 21:46
  • While there are ugly hacks with `eval`, the sane/reliable/robust thing is to simply _not do that_; loop over the numeric range you want to process with a `for` loop. See https://ideone.com/TZoJxp for an example. – Charles Duffy Jul 29 '21 at 21:48
  • 1
    BTW -- see discussion of this issue in [BashPitfalls #33](https://mywiki.wooledge.org/BashPitfalls#for_i_in_.7B1...24n.7D) – Charles Duffy Jul 29 '21 at 23:13
  • I see, thank you @CharlesDuffy – Duc Tran Jul 29 '21 at 23:22

1 Answers1

1

First idea would be a simple nested for loop:

startDay=1
endDay=2

pfx=
out=

for ((i=startDay; i<=endDay; i++))
do
    for j in {00..02}
    do
         out+="${pfx}[\"${i}\",\"${j}\"]"
         pfx=" "
    done
done

echo "${out}"

This generates:

["1","00"] ["1","01"] ["1","02"] ["2","00"] ["2","01"] ["2","02"]

A bit less coding, and a bit faster, which uses OP's echo ... {00..02} to eliminate one of the for loops:

NOTE: this eliminates the subprocess $(echo ...) call I had in a previous edit.

startDay=1
endDay=2

for ((i=startDay; i<=endDay; i++))
do
    echo -n "[\""${i}"\",\""{00..02}"\"]"
    echo -n " "
done

echo ""

This also generates:

["1","00"] ["1","01"] ["1","02"] ["2","00"] ["2","01"] ["2","02"]

Here's one awk idea:

awk -v start=$"${startDay}" -v end="${endDay}" '
BEGIN {
    pfx=""
    out=""

    for (i=start; i<=end; i++)
        for (j=0; j<=2; j++) {
             out=out pfx "[\"" i "\",\"" sprintf("%02d", j) "\"]"
             pfx=" "
        }
    print out
}'

This also generates:

["1","00"] ["1","01"] ["1","02"] ["2","00"] ["2","01"] ["2","02"]

With the elimination of the earlier subprocess $(echo ...) the first 2 solutions come in with single-digit millisecond timings while the awk solution comes in with low double-digit millisecond timings.

As the number of days (and/or sequence size) increases the first 2 solutions start taking longer (the nested for loop falling farther behind) while the awk solution tends to maintain the same speed.

For really large increases (number of days and/or sequence size) I would expect awk to close in on, and eventually take, the lead.

markp-fuso
  • 28,790
  • 4
  • 16
  • 36