2

I want to use strings containing numbers as input to my script. This list can be rather long and may contain consecutive ranges of numbers, so I thought about doing ls style list specification. However, how can I expand this list in my script? To be more specific, I want to run:

myscript node-[2,5-7,10-13]

and be able to loop through node-2, node-5, node-6, etc. in my script.

Update: It seems that I need to use curly brackets and dots for lists. I can convert the string to that, but how do I make the script treat it as a list then? What I can do:

nodelist=`echo $1 | sed 's/\[/\{/' | sed 's/\]/\}/' | sed 's/-/../'`

but for input node[1-3] for example I get:

>echo $nodelist
node{1..3}
Renat
  • 223
  • 3
  • 8

3 Answers3

5

Do you mean something like this?

$ echo node-{2,{5..7},{10..13}}

node-2 node-5 node-6 node-7 node-10 node-11 node-12 node-13

Edit

You could reformat your ranges to be bash-friendly:

echo '[2,5-7,10-13]'|sed -e 's:[[](.*)[]]:{\1}:' -e 's:([0-9]+)[-]([0-9]+):{\1..\2}:g'

{2,{5..7},{10..13}}

Community
  • 1
  • 1
dgeorgiev
  • 919
  • 7
  • 22
  • That could work, but I would like to keep the input with square brackets. I guess I can reformat the input inside the script to conform to this. I have updated my question. – Renat Jan 26 '18 at 14:34
  • Edited my anster to add some example how you can convert your ranges. – dgeorgiev Jan 26 '18 at 14:44
  • Yes, I thought of that, only your solution looks a lot better and takes care of the first dash. How do I expand the result though? BTW, your command gives a `invalid reference \1 on s' command's RHS` error. – Renat Jan 26 '18 at 14:51
  • 1
    Got it. It needs additional `-r` option to use the back references. My question about expanding the converted range still stands though. – Renat Jan 26 '18 at 15:03
  • 1
    Got that too. `eval` does the job :) – Renat Jan 26 '18 at 15:17
  • dgeorgiev, if you are still around, can you with your reformatting command? I think I understood everything, except the pluses in the second substitution. What are they for? – Renat Jan 26 '18 at 16:37
  • The pluses are part of the regular expression `[0-9]+` means match 1 or more number characters. Similar to `[0-9]*` which would match 0 or more number characters – dgeorgiev Jan 26 '18 at 17:26
3

Do brace expansion using ranges

myscript node-2 node-{5..7} node-{10..13}

You can nest it to make it even shorter

myscript node-{2,{5..7},{10..13}}
sjsam
  • 21,411
  • 5
  • 55
  • 102
1

If there is only one item in the list, i.e., no commas in the string, then you end up with double curly braces at the beginning and the end, which makes things a bit ugly when bash expands it. Consider the following, which essentially uses the previous example:

# eval echo $(echo '[2,5-7,10-13]'|sed -r 's:\[(.*)\]:{\1}:;s:([0-9]+)-([0-9]+):{\1..\2}:g')
2 5 6 7 10 11 12 13
# eval echo $(echo '[10-13]'|sed -r 's:\[(.*)\]:{\1}:;s:([0-9]+)-([0-9]+):{\1..\2}:g')
{10} {11} {12} {13}

It behaves more nicely if you strip the leading and trailing curly brace when there are no commas in the string:

# eval echo $(echo '[2,5-7,10-13]'|sed -r 's:\[(.*)\]:{\1}:;s:([0-9]+)-([0-9]+):{\1..\2}:g;s:^\{([^,]*)\}$:\1:')
2 5 6 7 10 11 12 13
# eval echo $(echo '[10-13]'|sed -r 's:\[(.*)\]:{\1}:;s:([0-9]+)-([0-9]+):{\1..\2}:g;s:^\{([^,]*)\}$:\1:')
10 11 12 13