Can I use a variable in a Bash brace expansion?

Below is some sort of pseudo-code for what I’m trying to accomplish:

#!/bin/bash

# I already have the variable below figured out (positive integer):
numlines=$([returns number of lines containing specific characters in a file])

# This is basically what I want to do with it:
for i in {1..$numlines}; do
    # the part below is already figured out as well:        
    do some other stuff
done

I can execute it fine from the command line by inserting the actual number in the `{1..n}’ sequence. I just need to know if it’s possible to include a variable here and how to go about doing it.

  • I have tried exporting it
  • I have tried putting the variable itself in curly braces inside the sequence: {1..${numlines}}
  • I have tried putting it in double-quotes hoping it would expand: {1.."$numlines"}
  • I have tried escaping the $: {1..$numlines}

Do I need to use a set -[something] command in order for this variable to get expanded? I have even tried some forms of using eval…all to no avail.

I just need to know if there is something simple or obscure that I am missing or if this is even possible before I waste anymore time on it.

I could throw together a really, really hackish way of doing it to make it work as needed, but I’d like to avoid that if at all possible and learn the right way to go about doing it.

Answers:

Thank you for visiting the Q&A section on Magenaut. Please note that all the answers may not help you solve the issue immediately. So please treat them as advisements. If you found the post helpful (or not), leave a comment & I’ll get back to you as soon as possible.

Method 1

Unfortunately, there is no way to use a variable in that expansion (AFAIK), since variable expansion happens after brace expansion.

Fortunately, there’s a tool that does the same job.

for i in $(seq 1 $numlines); do
    # stuff
done

seq is from GNU coreutils; no idea how to do it in POSIX.

Method 2

Sure. If you want a for loop that increments an integer variable, use the form of the for loop that increments an integer variable (or more generally performs arithmetic on the loop variable(s)).

for ((i=1; i<=numlines; i++)); do … done

This construct works in bash (and ksh93 and zsh), but not in plain sh. In plain sh, use a while loop and the test ([ … ]) construct.

i=1
while [ "$i" -le "$numlines" ]; do
  …
  i=$((i+1))
done

Method 3

If you must avoid seq, which as Tom Hunt points out seems to be the usual solution to this, then an eval definitely can do it (though, I wouldn’t encourage it):

eval 'for i in {1..'$numlines'}; do echo $i; done'

You can stay POSIX by avoiding the {} expansion, and simply do math and integer comparisons on $numlines:

while [ ! "$numlines" -eq 0 ]; do
     echo "$numlines"
     : $((numlines-=1))
done

Outside of POSIX, bash and ksh and zsh also have C-style for loops:

for((i=0; i<numlines; i++)); do echo $i; done


All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0

0 0 votes
Article Rating
Subscribe
Notify of
guest

0 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
0
Would love your thoughts, please comment.x
()
x