Project

General

Profile

1
#!/bin/bash
2
# Expands bash-style {} expressions.
3
# See <http://www.gnu.org/software/bash/manual/bash.html#Brace-Expansion>.
4
# Usage: [env expand_braces_debug=1] self <in >out
5
# Filters each line from stdin to stdout.
6
# Warning: Due to shell limitations, a blank line will be interpreted as EOF.
7

    
8
sedEreFlag="$(test "$(uname)" = Darwin && echo E || echo r)"
9

    
10
sed () { "$(which sed)" -"$sedEreFlag" "$@";}
11

    
12
echoEach () { local line; for line in "$@"; do echo "$line"; done; }
13

    
14
replaceRecursive ()
15
{
16
    local sedExpr="$1" str="$2" prevStr
17
    while true; do
18
        prevStr="$str"
19
        str="$(echo "$str"|sed -e "$sedExpr")"
20
        test "$str" = "$prevStr" && break # done if nothing replaced
21
    done
22
    echo "$str"
23
}
24

    
25
debug ()
26
{
27
    local label="$1" str="$2"
28
    test -n "$expand_braces_debug" && (echo "** $label:"; echo "$str") >&2
29
}
30

    
31
singleQuote="'"
32
singleQuoteEsc="'\''"
33
CR=$'\r'
34
LF=$'\n'
35
nonBracket="[^][]*" # matches non-[] chars
36
brackets="($nonBracket\[$nonBracket\])*$nonBracket"
37

    
38
while true; do
39
    read -r # get next line from stdin; strips trailing newlines; -r: raw input
40
    line="$REPLY"
41
    test -z "$line" && break # EOF if no line or empty line
42
    
43
    line="${line//$CR/}" # remove \r
44
    origLine="$line"
45
    debug orig "$line"
46
    
47
    line="${line//$singleQuote/$singleQuoteEsc}" # escape single quotes
48
    line="$(echo "$line"|sed -e "s/[^{,}]+/'&'/g")" # escape non-brace chars
49
    # Escape commas inside [], which should not be used for {}.
50
    # Note that '' around "," are closing and opening the escaped string,
51
    # not the other way around.
52
    line="$(replaceRecursive "s/(\[$nonBracket)','/\1,/g" "$line")" # innermost
53
    # Also support one level of nesting, which is the most we currently use.
54
    line="$(replaceRecursive "s/(\[$brackets)','/\1,/g" "$line")" # 1st outer
55
    debug escaped "$line"
56
    
57
    debug expanded
58
    eval echoEach $line # brace-expand $line
59
done
(15-15/58)