Skip to content

Commit

Permalink
Added Commandf and Sprintf
Browse files Browse the repository at this point in the history
  • Loading branch information
keegancsmith committed Jan 18, 2016
1 parent 61d047e commit 22f98c7
Show file tree
Hide file tree
Showing 3 changed files with 79 additions and 2 deletions.
44 changes: 44 additions & 0 deletions command.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package shell

import (
"fmt"
"io"
"os/exec"
)

// Commandf runs a shell command based on the format string
func Commandf(format string, a ...interface{}) *exec.Cmd {
shellCmd := Sprintf(format, a...)
return exec.Command("/bin/sh", "-c", shellCmd)
}

// Sprintf generates a shell command with the format arguments escaped.
func Sprintf(format string, a ...interface{}) string {
wrapped := make([]interface{}, len(a))
for i, v := range a {
wrapped[i] = escapable{v}
}
return fmt.Sprintf(format, wrapped...)
}

type escapable struct {
x interface{}
}

func (e escapable) Format(f fmt.State, c rune) {
s := "%"
for i := 0; i < 128; i++ {
if f.Flag(i) {
s += string(i)
}
}
if w, ok := f.Width(); ok {
s += fmt.Sprintf("%d", w)
}
if p, ok := f.Precision(); ok {
s += fmt.Sprintf(".%d", p)
}
s += string(c)
formatted := fmt.Sprintf(s, e.x)
io.WriteString(f, ReadableEscapeArg(formatted))
}
33 changes: 33 additions & 0 deletions command_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package shell

import (
"bytes"
"testing"
)

func TestCommandf(t *testing.T) {
out, err := Commandf("echo %s world %s", "hello", "quote!me").Output()
if err != nil {
t.Fatal(err)
}
if string(out) != "hello world quote!me\n" {
t.Fatalf("Unexpected hello world output: %#v", string(out))
}
}

func TestCommandf_Redirect(t *testing.T) {
var stdout, stderr bytes.Buffer
cmd := Commandf("echo %s; echo %s 1>&2", "hello from stdout", "bye from stderr")
cmd.Stdout = &stdout
cmd.Stderr = &stderr
err := cmd.Run()
if err != nil {
t.Fatal(err)
}
if stdout.String() != "hello from stdout\n" {
t.Errorf("Unexpected output from stdout: %v", stdout.String())
}
if stderr.String() != "bye from stderr\n" {
t.Errorf("Unexpected output from stderr: %v", stderr.String())
}
}
4 changes: 2 additions & 2 deletions escape.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@ func EscapeArg(arg string) string {
}

// ReadableEscapeArg will not escape strings that do not requiring
// escaping. Note that it is conservative in it's approach, so may escape
// strings which do not require it.
// escaping. Note that it is conservative, so may escape strings which do not
// require it.
func ReadableEscapeArg(arg string) string {
if readableRe.MatchString(arg) {
return arg
Expand Down

0 comments on commit 22f98c7

Please sign in to comment.