This is a case where eval
might be your best bet. There isn't a security concern as long as you strictly control the content of brace_string
and it allows you to build a list of brace expansions that can do what you want.
#!/bin/bash
make_list() {
brace_string=""
for ((i=0 ; i < $1 ; i++)) ; do
brace_string+="{a..z}"
eval printf "'%s\n'" "${brace_string}"
done
}
make_list "$1" | sort
The problem with {1..$i}
or with building a list of brace expansions in a variable without eval
is that the bash parser evaluates syntax before it expands variables. That means {1..$i}
is just treated like a string because $i
isn't a single character or integer (it gets replaced by an integer later, but bash can't see into the future). eval
works around this by letting you perform all the parsing steps twice, meaning $i
can get replaced on the first parsing and then the brace expansion is valid on the second parsing. And, more relevant to the above example, "$brace_string"
won't be treated as a brace expansion on the first parsing because the variable hasn't been replaced by the time bash does syntax analysis, but it can be handled on a second parsing through eval
.