Variables in bash seq replacement ({1..10}) [duplicate]
Asked Answered
O

7

73

Is it possible to do something like this:

start=1
end=10
echo {$start..$end}
# Ouput: {1..10}
# Expected: 1 2 3 ... 10 (echo {1..10})
Overly answered 31/5, 2011 at 17:20 Comment(0)
T
74

In bash, brace expansion happens before variable expansion, so this is not directly possible.

Instead, use an arithmetic for loop:

start=1
end=10
for ((i=start; i<=end; i++))
do
   echo "i: $i"
done

OUTPUT

i: 1
i: 2
i: 3
i: 4
i: 5
i: 6
i: 7
i: 8
i: 9
i: 10
Tara answered 31/5, 2011 at 17:42 Comment(2)
and should output be 1 2 3 4 5 6 7 8 9 10?Thistly
it's possible, but it is a little bit ugly because one starts another shell to do the variable expansion before the brace expansion: start=1;end=10;for i in $(bash -c "echo {$start..$end}");do echo $i;doneNorthwest
T
29

You should consider using seq(1). You can also use eval:

eval echo {$start..$end}

And here is seq

seq -s' ' $start $end
Tref answered 31/5, 2011 at 17:24 Comment(14)
I don't have the seq command in my shellOverly
@Overly Now I understand.Tref
And seq is also deprecated anywayOverly
@Tylio Is it ?! I didn't know. Why is it deprecated ?Tref
@Tref Here: cyberciti.biz/faq/bash-for-loopOverly
@Overly I agree one should favor internal commands / structures over external programs. But what happens if I use something that doesn't support that syntax.. like dash maybe ? Or ash ? Or tcsh ?Tref
@Overly What shell/OS are you in? Solaris? I've never seen seq not present on any Linux distro. In fact, its even in the GNU coreutils: gnu.org/s/coreutils/manual/html_node/seq-invocation.htmlUnderbelly
@Underbelly FreeBSD doesn't have it either (although it's in ports).Tref
@Underbelly coreutils != POSIX standard. Sure, it's there in Linux, but there's more operating systems in the world.Timbering
For what it is worth, "deprecated" does not mean the same thing as "isn't advisable"Reprobation
using eval is as horrid here as in most other places, don't get used to it or you'll find yourself leaving command injection vulnerabilities some dayCooe
To make eval safe here, just force the variables into integers with eval echo {$((start))..$((end))}Client
@phicr, $((var)) is not safe if the value of var has not been sanitized. See Security Implications of using unsanitized data in Shell Arithmetic evaluation.Horwath
@Horwath you're right, I forgot that index evaluation is part of arithmetic and it allows arbitrary commands. Maybe something like $((${var%%\$*})). Altho of course the proper thing to do is to validate the data as valid integers either by code invariants or explicit conditionals. (in the hypothetical case eval is necessary) And I don't know where my head was at 1 yr ago that I didn't realize that my "solution" could easily lead to potentially silent hard to find errors anyway, even if it had been a working one, hehe.Client
A
10

You have to use eval:

eval echo {$start..$end}
Apologize answered 31/5, 2011 at 17:23 Comment(1)
That's like using a jackhammer to pound a nail. It's dangerous (literally, introduces potential shell injection vulnerabilities if any of your values come from untrusted inputs), and not the right tool for the job. for ((i=start; i<end; i++)); do ...; done.Timbering
F
9

If you don't have seq, you might want to stick with a plain for loop

for (( i=start; i<=end; i++ )); do printf "%d " $i; done; echo ""
Feast answered 31/5, 2011 at 17:45 Comment(1)
This is the only working non-scary (ie not eval) answer. Did not know bash had c style loopsDenominative
U
2

I normally just do this:

echo `seq $start $end`
Underbelly answered 31/5, 2011 at 17:27 Comment(5)
Look at my comment to cnicutar's answerOverly
seq is a non-standard tool (literally, not specified in POSIX).Timbering
Let alone the fact that seq is non-standard, but the echo + command substitution is just a silly combination.Cooe
@Cooe not if you need to add a newline.Tireless
@BrunoBronosky, well, the bigger difference is that the unquoted command substitution folds the whitespace to single spaces (unless IFS is changed from the default). So you get the numbers all on the same line, not one line each like the default with seq. But if you want that, you could just use seq -w ' ' 1 10. If you do quote the command substitution, on the other hand, then echo "$(seq 1 10)" and seq 1 10 have exactly the same output. Command substitution strips trailing newlines (there's one), and echo adds one back.Cooe
M
2

Are you positive it has be BASH? ZSH handles this the way you want. This won't work in BASH because brace expansion happens before any other expansion type, such as variable expansion. So you will need to use an alternative method.

Any particular reason you need to combine brace and variable expansion? Perhaps a different approach to your problem will obviate the need for this.

Michaels answered 31/5, 2011 at 17:56 Comment(0)
D
1

use -s ex: seq -s ' ' 1 10 output: 1 2 3 4 5 6 7 8 9 10

Dialogism answered 27/8, 2017 at 7:17 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.