Skip to content
main
Switch branches/tags
Code

Latest commit

 

Git stats

Files

Permalink
Failed to load latest commit information.
Type
Name
Latest commit message
Commit time
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Bash Brace Expansion in Go

Go implementation of Brace Expansion mechanism to generate arbitrary strings.

Implementing: 3.5.1 Brace Expansion

PkgGoDev license GitHub last commit Mentioned in Awesome Go

tests Go Report Card Coverage Status

benchmarks

Usage

go get github.com/mkungla/bexp/v3

Get string slice

package main

import (
  "fmt"

  "github.com/mkungla/bexp/v3"
)

func main() {
  var v []string
  v = bexp.Parse("file-{a,b,c}.jpg")
  fmt.Println(v)
  // [file-a.jpg file-b.jpg file-c.jpg]

  v = bexp.Parse("-v{,,}")
  fmt.Println(v)
  // [-v -v -v]

  v = bexp.Parse("file{0..2}.jpg")
  fmt.Println(v)
  // [file0.jpg file1.jpg file2.jpg]

  v = bexp.Parse("file{2..0}.jpg")
  fmt.Println(v)
  // [file2.jpg file1.jpg file0.jpg]

  v = bexp.Parse("file{0..4..2}.jpg")
  fmt.Println(v)
  // [file0.jpg file2.jpg file4.jpg]

  v = bexp.Parse("file-{a..e..2}.jpg")
  fmt.Println(v)
  // [file-a.jpg file-c.jpg file-e.jpg]

  v = bexp.Parse("file{00..10..5}.jpg")
  fmt.Println(v)
  // [file00.jpg file05.jpg file10.jpg]

  v = bexp.Parse("{{A..C},{a..c}}")
  fmt.Println(v)
  // [A B C a b c]

  v = bexp.Parse("ppp{,config,oe{,conf}}")
  fmt.Println(v)
  // [ppp pppconfig pppoe pppoeconf]

  v = bexp.Parse("data/{P1/{10..19},P2/{20..29},P3/{30..39}}")
  fmt.Println(v)
  // [data/P1/10 data/P1/11 data/P1/12 data/P1/13 data/P1/14 data/P1/15 data/P1/16 data/P1/17 data/P1/18 data/P1/19 data/P2/20 data/P2/21 data/P2/22 data/P2/23 data/P2/24 data/P2/25 data/P2/26 data/P2/27 data/P2/28 data/P2/29 data/P3/30 data/P3/31 data/P3/32 data/P3/33 data/P3/34 data/P3/35 data/P3/36 data/P3/37 data/P3/38 data/P3/39]
}

Generating directory tree

package main

import (
  "log"

  "github.com/mkungla/bexp/v3"
)

func main() {
  const (
    rootdir = "/tmp/bexp"
    treeexp = rootdir + "/{dir1,dir2,dir3/{subdir1,subdir2}}"
  )
  if err := bexp.MkdirAll(treeexp, 0750); err != nil {
    log.Fatal(err)
  }

  // Will produce directory tree
  // /tmp/bexp
  // /tmp/bexp/dir1
  // /tmp/bexp/dir2
  // /tmp/bexp/dir3
  // /tmp/bexp/dir3/subdir1
  // /tmp/bexp/dir3/subdir2
}

Expand URLS

The example shows how to create Openstreetmap tiles
around the desired latitude and longitude coordinates.

package main

import (
  "fmt"
  "log"
  "math"

  "github.com/mkungla/bexp/v3"
)

func getCenterTile(lat, long float64, zoom int) (z, x, y int) {
  n := math.Exp2(float64(zoom))
  x = int(math.Floor((long + 180.0) / 360.0 * n))
  if float64(x) >= n {
    x = int(n - 1)
  }
  y = int(math.Floor((1.0 - math.Log(
    math.Tan(lat*math.Pi/180.0)+
      1.0/math.Cos(lat*math.Pi/180.0))/
    math.Pi) / 2.0 * n))
  return x, y, zoom
}

func main() {
  x, y, z := getCenterTile(51.03, 13.78, 5)
  pattern := fmt.Sprintf(
    "https://tile.openstreetmap.org/%d/{%d..%d}/{%d..%d}.png",
    z, x-2, x+2, y-2, y+2,
  )
  tiles := bexp.Parse(pattern)
  fmt.Println("pattern: ", pattern)
  for _, tile := range tiles {
    fmt.Println(tile)
  }
  // Output:
  // pattern: https://tile.openstreetmap.org/5/{15..19}/{8..12}.png
  // https://tile.openstreetmap.org/5/15/8.png
  // https://tile.openstreetmap.org/5/15/9.png
  // https://tile.openstreetmap.org/5/15/10.png
  // https://tile.openstreetmap.org/5/15/11.png
  // https://tile.openstreetmap.org/5/15/12.png
  // https://tile.openstreetmap.org/5/16/8.png
  // https://tile.openstreetmap.org/5/16/9.png
  // https://tile.openstreetmap.org/5/16/10.png
  // https://tile.openstreetmap.org/5/16/11.png
  // https://tile.openstreetmap.org/5/16/12.png
  // https://tile.openstreetmap.org/5/17/8.png
  // https://tile.openstreetmap.org/5/17/9.png
  // https://tile.openstreetmap.org/5/17/10.png
  // https://tile.openstreetmap.org/5/17/11.png
  // https://tile.openstreetmap.org/5/17/12.png
  // https://tile.openstreetmap.org/5/18/8.png
  // https://tile.openstreetmap.org/5/18/9.png
  // https://tile.openstreetmap.org/5/18/10.png
  // https://tile.openstreetmap.org/5/18/11.png
  // https://tile.openstreetmap.org/5/18/12.png
  // https://tile.openstreetmap.org/5/19/8.png
  // https://tile.openstreetmap.org/5/19/9.png
  // https://tile.openstreetmap.org/5/19/10.png
  // https://tile.openstreetmap.org/5/19/11.png
  // https://tile.openstreetmap.org/5/19/12.png
}

Need error checking?

package main

import (
  "errors"
  "fmt"

  "github.com/mkungla/bexp/v3"
)

func main() {
  empty, err := bexp.ParseValid("")
  fmt.Printf("%q - %t\n", empty[0], errors.Is(err, bexp.ErrEmptyResult))

  abc, err := bexp.ParseValid("abc")
  fmt.Printf("%q - %t\n", abc[0], errors.Is(err, bexp.ErrUnchangedBraceExpansion))

  // Output:
  // "" - true
  // "abc" - true
}

With os.Expand

os.Expand

package main

import (
  "fmt"
  "os"

  "github.com/mkungla/bexp/v3"
)

func main() {
  const treeExp = "$MY_ROOT_DIR/dir{1..3}/{subdir1,subdir2}"
  mapper := func(varName string) string {
    switch varName {
    case "MY_ROOT_DIR":
      return "/my_root"
    }
    return ""
  }
  str := os.Expand(treeExp, mapper)
  fmt.Println("str := os.Expand(treeExp, mapper)")
  fmt.Println(str)

  fmt.Println("v := bexp.Parse(str)")
  v := bexp.Parse(str)
  for _, p := range v {
    fmt.Println(p)
  }

  // Output:
  // str := os.Expand(treeExp, mapper)
  // /my_root/dir{1..3}/{subdir1,subdir2}
  // v := bexp.Parse(str)
  // /my_root/dir1/subdir1
  // /my_root/dir1/subdir2
  // /my_root/dir2/subdir1
  // /my_root/dir2/subdir2
  // /my_root/dir3/subdir1
  // /my_root/dir3/subdir2
}

With os.ExpandEnv

os.ExpandEnv

package main

import (
  "fmt"
  "os"

  "github.com/mkungla/bexp/v3"
)

func main() {
  const treeExp = "$MY_ROOT_DIR/dir{1..3}/{subdir1,subdir2}"
  os.Setenv("MY_ROOT_DIR", "/my_root")
  
  str := os.ExpandEnv(treeExp)
  fmt.Println("str := os.ExpandEnv(treeExp)")
  fmt.Println(str)
  
  fmt.Println("v := bexp.Parse(str)")
  v := bexp.Parse(str)
  for _, p := range v {
    fmt.Println(p)
  }
  
  // Output:
  // str := os.ExpandEnv(treeExp)
  // /my_root/dir{1..3}/{subdir1,subdir2}
  // v := bexp.Parse(str)
  // /my_root/dir1/subdir1
  // /my_root/dir1/subdir2
  // /my_root/dir2/subdir1
  // /my_root/dir2/subdir2
  // /my_root/dir3/subdir1
  // /my_root/dir3/subdir2
}

Inspired by and other similar libraries

following package were inspiration to create this package, The motivation of this package is to improve performance and reduce memory allocations compared to other solutions. Also to add some commonly used API's when working with brace expansion strings

About

Go implementation of Brace Expansion mechanism to generate arbitrary strings.

Topics

Resources

License

Stars

Watchers

Forks

Languages