Skip to content

Commit

Permalink
expand: support zero-padding in brace expansions
Browse files Browse the repository at this point in the history
Per "man bash":

    When either x or y begins with a zero, the shell attempts to force
    all generated terms to contain the same number of digits,
    zero-padding where necessary.

Fixes #1042.
  • Loading branch information
mvdan committed Nov 14, 2023
1 parent 86a0bc9 commit bb3e036
Show file tree
Hide file tree
Showing 2 changed files with 34 additions and 3 deletions.
25 changes: 22 additions & 3 deletions expand/braces.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ package expand

import (
"strconv"
"strings"

"mvdan.cc/sh/v3/syntax"
)
Expand All @@ -25,8 +26,17 @@ func Braces(word *syntax.Word) []*syntax.Word {
}
if br.Sequence {
chars := false
from, err1 := strconv.Atoi(br.Elems[0].Lit())
to, err2 := strconv.Atoi(br.Elems[1].Lit())

fromLit := br.Elems[0].Lit()
toLit := br.Elems[1].Lit()
zeros := extraLeadingZeros(fromLit)
// TODO: use max when we can assume Go 1.21
if z := extraLeadingZeros(toLit); z > zeros {
zeros = z
}

from, err1 := strconv.Atoi(fromLit)
to, err2 := strconv.Atoi(toLit)
if err1 != nil || err2 != nil {
chars = true
from = int(br.Elems[0].Lit()[0])
Expand Down Expand Up @@ -57,7 +67,7 @@ func Braces(word *syntax.Word) []*syntax.Word {
if chars {
lit.Value = string(rune(n))
} else {
lit.Value = strconv.Itoa(n)
lit.Value = strings.Repeat("0", zeros) + strconv.Itoa(n)
}
next.Parts = append([]syntax.WordPart{lit}, next.Parts...)
exp := Braces(&next)
Expand All @@ -83,3 +93,12 @@ func Braces(word *syntax.Word) []*syntax.Word {
}
return []*syntax.Word{{Parts: left}}
}

func extraLeadingZeros(s string) int {
for i, r := range s {
if r != '0' {
return i
}
}
return 0 // "0" has no extra leading zeros
}
12 changes: 12 additions & 0 deletions expand/braces_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,18 @@ var braceTests = []struct {
litWord("a{4..1..1}"),
litWords("a4", "a3", "a2", "a1"),
},
{
litWord("{1..005}"),
litWords("001", "002", "003", "004", "005"),
},
{
litWord("{0001..05..2}"),
litWords("0001", "0003", "0005"),
},
{
litWord("{0..1}"),
litWords("0", "1"),
},
{
litWord("a{d..k..3}"),
litWords("ad", "ag", "aj"),
Expand Down

0 comments on commit bb3e036

Please sign in to comment.