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
|