Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Both sides previous revision Previous revision
Next revision
Previous revision
syntax:expansion:brace [2013/04/14 12:28]
thebonsai Don't tread version 4 special - it has been around for a long time now
syntax:expansion:brace [2014/09/03 09:56] (current)
glorieul Added an example (probably obvious for most people, but not to rookies like myself)
Line 28: Line 28:
 echo a$PATH b$PATH echo a$PATH b$PATH
 </​code>​ </​code>​
-Another common pitfall is to assume that a range like ''​{1..200}''​ can be expressed with variables using ''​{$a..$b}''​. Due to what I described above, it **simply is not possible**, because it's the very first step in doing expansions. A possible way to achieve this, if you really can't handle this in another way, is using the ''​eval''​ command, which basically evaluates a commandline twice: <​code>​eval echo {$a..$b}</​code>​ This requires that the entire command be properly escaped to avoid unexpected expansions. If the sequence expansion is to be assigned to an array, another method is possible using declaration commands: <​code>​declare -a '​pics=(img{'"​$a..$b"'​}.png)';​ mv "​${pics[@]}"​ ../​imgs</​code>​ This is significantly safer, but one must still be careful to control the values of $a and $b. Both the exact quoting, and explicitly including "​-a"​ are important.+Another common pitfall is to assume that a range like ''​{1..200}''​ can be expressed with variables using ''​{$a..$b}''​. Due to what I described above, it **simply is not possible**, because it's the very first step in doing expansions. A possible way to achieve this, if you really can't handle this in another way, is using the ''​eval''​ command, which basically evaluates a commandline twice: <​code>​eval echo {$a..$b}</​code>​ For instance, when embedded inside a for loop : <​code>​for i in $(eval echo {$a..$b})</​code>​ This requires that the entire command be properly escaped to avoid unexpected expansions. If the sequence expansion is to be assigned to an array, another method is possible using declaration commands: <​code>​declare -a '​pics=(img{'"​$a..$b"'​}.png)';​ mv "​${pics[@]}"​ ../​imgs</​code>​ This is significantly safer, but one must still be careful to control the values of $a and $b. Both the exact quoting, and explicitly including "​-a"​ are important.
  
 The brace expansion is present in two basic forms, **string lists** and **ranges**. The brace expansion is present in two basic forms, **string lists** and **ranges**.
Line 183: Line 183:
 ...which is a kind of a hack, but hey, it works. ...which is a kind of a hack, but hey, it works.
  
 +<div round info>
 +=== More fun ===
 +The most optimal possible brace expansion to expand n arguments of course consists of n's prime factors. We can use the "​factor"​ program bundled with GNU coreutils to emit a brace expansion that will expand any number of arguments.
 +
 +<​code>​
 +function braceify {
 +    [[ $1 == +([[:​digit:​]]) ]] || return
 +    typeset -a a
 +    read -ra a < <(factor "​$1"​)
 +    eval "echo $(printf '​{$(printf ,%%.s {1..%s})}'​ "​${a[@]:​1}"​)"​
 +}
 +
 +printf 'eval printf "​$arg"​%s'​ "​$(braceify 1000000)"​
 +</​code>​
 +
 +"​Braceify"​ generates the expansion code itself. In this example we inject that output into a template which displays the most terse brace expansion code that would expand ''"​$arg"''​ 1,000,000 times if evaluated. In this case, the output is:
 +
 +<​code>​
 +eval printf "​$arg"​{,,​}{,,​}{,,​}{,,​}{,,​}{,,​}{,,,,,​}{,,,,,​}{,,,,,​}{,,,,,​}{,,,,,​}{,,,,,​}
 +</​code>​
 +</​div>​
 ===== New in Bash 4.0 ===== ===== New in Bash 4.0 =====
  
  • syntax/expansion/brace.1365942494.txt
  • Last modified: 2013/04/14 12:28
  • by thebonsai