I have a function func more(... t). I'm wondering if it's possible to use a slice to populate a list of arguments ... .
I'm trying to solve the following program. Basically to mimic a normal shell which receives the command as a string.
Command function requires a "list" of arguments and I don't see how I can convert a string into a such list
import "os/exec"
import "strings"
func main(){
plainCommand := "echo hello world"
sliceA := strings.Fields(plainCommand)
cmd := exec.Command(sliceA)
}
The Go Programming Language Specification
Passing arguments to ... parameters
If f is variadic with final parameter type ...T, then within the
function the argument is equivalent to a parameter of type []T. At
each call of f, the argument passed to the final parameter is a new
slice of type []T whose successive elements are the actual arguments,
which all must be assignable to the type T. The length of the slice is
therefore the number of arguments bound to the final parameter and may
differ for each call site.
Package exec
func Command
func Command(name string, arg ...string) *Cmd
Command returns the Cmd struct to execute the named program with the
given arguments.
The returned Cmd's Args field is constructed from the command name
followed by the elements of arg, so arg should not include the command
name itself. For example, Command("echo", "hello")
For example,
package main
import (
"fmt"
"os/exec"
)
func main() {
name := "echo"
args := []string{"hello", "world"}
cmd := exec.Command(name, args...)
out, err := cmd.Output()
if err != nil {
fmt.Println(err)
}
fmt.Println(string(out))
}
Output:
hello world
A list of command arguments can be retrieved from the flag package Args() function. You can then pass this to a function using the variadic input style (func(input...))
From the Spec:
If f is variadic with final parameter type ...T, then within the function the argument is equivalent to a parameter of type []T. At each call of f, the argument passed to the final parameter is a new slice of type []T whose successive elements are the actual arguments, which all must be assignable to the type T.
Example:
package main
import "fmt"
func echo(strings ...string) {
for _, s := range strings {
fmt.Println(s)
}
}
func main() {
strings := []string{"a", "b", "c"}
echo(strings...) // Treat input to function as variadic
}
See The Go spec for more details.
Playground
func Command
func Command(name string, arg ...string) *Cmd
Command returns the Cmd struct to execute the named program with the given arguments.
So you have to extract the command which is found at sliceA[0] and then pass all the arguments with a variadic but removing the command sliceA[1:]....
import "os/exec"
import "strings"
func main(){
plainCommand := "echo hello world"
sliceA := strings.Fields(plainCommand)
cmd := exec.Command(sliceA[0], sliceA[1:]...)
}
Related
Why the outputs of s and s1 differs although the starting value is same ? Help me understand
package main
import (
"fmt"
"reflect"
)
type Auth struct {
a, b interface{}
}
func main() {
fmt.Println("--------p1,s1--------")
p1 := Auth{}
fmt.Println(p1)
s1 := reflect.ValueOf(p1)
fmt.Println(s1)
fmt.Println("-------s---------")
callFunc(p1)
}
func callFunc(a ...interface{}) {
s := reflect.ValueOf(a)
fmt.Println(s)
}
Ps. Filename is nil.go
On running the code using :go run nil.go
The output is :
The fmt package documents that when printing reflect.Value values, it prints the value wrapped inside them:
Except when printed using the verbs %T and %p, special formatting considerations apply for operands that implement certain interfaces. In order of application:
If the operand is a reflect.Value, the operand is replaced by the concrete value that it holds, and printing continues with the next rule.
[...]
callFunc() has a variadic parameter:
func callFunc(a ...interface{})
This means a is a slice. So when printing reflect.ValueOf(a), you'll get the slice printed. And the fmt package also documents that:
For compound objects, the elements are printed using these rules, recursively, laid out like this:
struct: {field0 field1 ...}
array, slice: [elem0 elem1 ...]
maps: map[key1:value1 key2:value2 ...]
pointer to above: &{}, &[], &map[]
Slices are printed enclosed in square brackets.
Note that if callFunc() would not be variadic:
func callFunc(a interface{}) {
s := reflect.ValueOf(a)
fmt.Println(s)
}
Then output would be the same (try it on the Go Playground):
--------p1,s1--------
{<nil> <nil>}
{<nil> <nil>}
-------s---------
{<nil> <nil>}
Given the following code snippet
package main
import (
"fmt"
)
type Message string
const (
ConnectRepositoryError Message = "failed to connect %s repository"
)
func main() {
fmt.Println(ConnectRepositoryError.M("user"))
}
func (m Message) M(args ...string) string {
return fmt.Sprintf(string(m), args)
}
... why does fmt.Sprintf enclose the specified string (user) in square brackets?
failed to connect [user] repository
I'd expect this output instead:
failed to connect user repository
Because inside Message.M() you call fmt.Sprintf(), to which you pass the format string string(m) and a single argument args being a string slice. And slices are formatted like: the elements separated by space, enclosed in square brackets. And since you pass a single value to M(), it'll be a one-element slice, printed like [user].
Instead you want to pass args as the variadic parameter to fmt.Sprintf(), so use ....
Of course this will be a compile time-error because fmt.Sprintf() expects ...interface{} and ...string does not qualify. You have to change the parameter of M to be ...interface{}:
func (m Message) M(args ...interface{}) string {
return fmt.Sprintf(string(m), args...)
}
With this change output will be (try it on the Go Playground):
failed to connect user repository
The argument list for variable argument functions is a slice. When you print a slice, it is printed as [value value ...].
You should convert the strings to an []interface{}, and use the following syntax to pass all elements of the slice:
func (m Message) M(args ...string) string {
iargs:=make([]interface{},0,len(args))
for _,x:=range args {
iargs=append(iargs, x)
}
return fmt.Sprintf(string(m), iargs...)
}
When I compile the following program
func myPrint(v ...interface{}) {
fmt.Println("Hello", v...)
}
func main() {
myPrint("new", "world")
}
I get a compilation error
too many arguments in call to fmt.Println
I thought v... is going to expand into 2nd, 3rd arguments and the fmt.Println would see three item variadic argument list. I thought it would be equivalent to
fmt.Println("Hello", "new", "world")
Why is it giving an error.
Try this. It prepends Hello to the variadic arguments, then prints them all at once with println.
package main
import "fmt"
func myPrint(v ...interface{}) {
a := append([]interface{}{"Hello"}, v...) // prepend "Hello" to variadics
fmt.Println(a...) // println the whole lot
}
func main() {
myPrint("new", "world")
}
You're mis-using the variadic shorthand in your call to fmt.Println(). What you're actually sending is 2 arguments: a single string, then the slice of type interface{} expanded. The function call will not concatenate that into a single slice.
This design will compile and run with the results you're expecting:
func myPrint(v ...interface{}) {
fmt.Print("Hello ")
fmt.Println(v...)
}
func main() {
myPrint("new", "world")
}
In order to don't repeat my self over and over I wanted to create a function that handles running some commands.
func runCommand(name string, arg ...string) error {
cmd := exec.Command(name, arg)
if err := cmd.Run(); err != nil {
return err
} else {
return nil
}
}
Once I try to run this I get the following error:
cannot use arg (type []string) as type string in argument to exec.Command
I had a look into the implementation of the os.Command and it looks that the function signature is exact what I supply.
Internally a []string should be the same as variadic parameter but for the compiler it seems not.
Is there a way to pass the variadic parameter into the Command?
You expand the []string with another ...
cmd := exec.Command(name, arg...)
From the language spec on Passing arguments to ... parameters
If the final argument is assignable to a slice type []T, it may be
passed unchanged as the value for a ...T parameter if the argument is
followed by .... In this case no new slice is created.
Given the slice s and call
s := []string{"James", "Jasmine"}
Greeting("goodbye:", s...)
within Greeting, who will have the same value as s with the same underlying array.
How to convert interface{} to bytes.Buffer?
Minimal example
package main
import (
"bytes"
"fmt"
)
func ToJson5(any interface{}) string {
if any == nil {
return `''`
}
switch any.(type) {
case bytes.Buffer: // return as is
return any.(bytes.Buffer).String()
// other types works fine
}
return ``
}
func main() {
x := bytes.Buffer{}
fmt.Println(ToJson5(x))
}
The errors was:
main.go:14: cannot call pointer method on any.(bytes.Buffer)
main.go:14: cannot take the address of any.(bytes.Buffer)
When changed to bytes.Buffer{} (that I think less correct), the error was:
main.go:13: bytes.Buffer literal (type bytes.Buffer) is not a type
main.go:14: bytes.Buffer literal is not a type
You can use a Short variable declaration in the Type switch to have the typed value in the case branches:
switch v := any.(type) {
case bytes.Buffer: // return as is
return v.String() // Here v is of type bytes.Buffer
}
Try it on the Go Playground.
Quoting form the spec:
The TypeSwitchGuard may include a short variable declaration. When that form is used, the variable is declared at the beginning of the implicit block in each clause. In clauses with a case listing exactly one type, the variable has that type; otherwise, the variable has the type of the expression in the TypeSwitchGuard.