go

Cómo ejecutar el comando del sistema en Golang con argumentos desconocidos



(4)

Tengo un montón de comandos de sistemas que son algo similar a agregar nuevo contenido a un archivo. Escribí un script simple para ejecutar comandos del sistema, que funciona bien si hay palabras sueltas como ''ls'', ''date'', etc. Pero si el comando es mayor que eso, el programa muere.

El siguiente es el código

package main import ( "fmt" "os/exec" "sync" ) func exe_cmd(cmd string, wg *sync.WaitGroup) { fmt.Println(cmd) c = cmd.Str out, err := exec.Command(cmd).Output() if err != nil { fmt.Println("error occured") fmt.Printf("%s", err) } fmt.Printf("%s", out) wg.Done() } func main() { wg := new(sync.WaitGroup) wg.Add(3) x := []string{"echo newline >> foo.o", "echo newline >> f1.o", "echo newline >> f2.o"} go exe_cmd(x[0], wg) go exe_cmd(x[1], wg) go exe_cmd(x[2], wg) wg.Wait() }

El siguiente es el error que veo

exec: "echo newline >> foo.o": executable file not found in $PATHexec: "echo newline >> f2.o": executable file not found in $PATHexec: "echo newline >> f1.o": executable file not found in $PATH

Supongo que esto puede deberse a que no se envían los cmd y los argumentos por separado ( http://golang.org/pkg/os/exec/#Command ). Me pregunto cómo subvertir esto, ya que no sé cuántos argumentos habrá en mi comando que deben ser ejecutados.


Encontré una forma relativamente decente de lograr lo mismo.

out, err := exec.Command("sh","-c",cmd).Output()

Funciona para mí hasta ahora. Aún encontrando mejores formas de lograr lo mismo.

Edit1:

Finalmente, una manera más fácil y eficiente (al menos hasta ahora) de hacer sería como esto

func exe_cmd(cmd string, wg *sync.WaitGroup) { fmt.Println("command is ",cmd) // splitting head => g++ parts => rest of the command parts := strings.Fields(cmd) head := parts[0] parts = parts[1:len(parts)] out, err := exec.Command(head,parts...).Output() if err != nil { fmt.Printf("%s", err) } fmt.Printf("%s", out) wg.Done() // Need to signal to waitgroup that this goroutine is done }

Gracias a argumentos variados en go y personas que me lo señalaron :)


Para exec.Command() el primer argumento debe ser la ruta al ejecutable. Luego, los argumentos restantes se suministrarán como argumentos al ejecutable. Utilice strings.Fields() para ayudar a dividir la palabra en una cadena [].

Ejemplo:

package main import ( "fmt" "os/exec" "sync" "strings" ) func exe_cmd(cmd string, wg *sync.WaitGroup) { fmt.Println(cmd) parts := strings.Fields(cmd) out, err := exec.Command(parts[0],parts[1]).Output() if err != nil { fmt.Println("error occured") fmt.Printf("%s", err) } fmt.Printf("%s", out) wg.Done() } func main() { wg := new(sync.WaitGroup) commands := []string{"echo newline >> foo.o", "echo newline >> f1.o", "echo newline >> f2.o"} for _, str := range commands { wg.Add(1) go exe_cmd(str, wg) } wg.Wait() }

Aquí hay un enfoque alternativo que simplemente escribe todos los comandos en un archivo y luego ejecuta ese archivo dentro del contexto del nuevo directorio de salida creado.

Ejemplo 2

package main import ( "os" "os/exec" "fmt" "strings" "path/filepath" ) var ( output_path = filepath.Join("./output") bash_script = filepath.Join( "_script.sh" ) ) func checkError( e error){ if e != nil { panic(e) } } func exe_cmd(cmds []string) { os.RemoveAll(output_path) err := os.MkdirAll( output_path, os.ModePerm|os.ModeDir ) checkError(err) file, err := os.Create( filepath.Join(output_path, bash_script)) checkError(err) defer file.Close() file.WriteString("#!/bin/sh/n") file.WriteString( strings.Join(cmds, "/n")) err = os.Chdir(output_path) checkError(err) out, err := exec.Command("sh", bash_script).Output() checkError(err) fmt.Println(string(out)) } func main() { commands := []string{ "echo newline >> foo.o", "echo newline >> f1.o", "echo newline >> f2.o", } exe_cmd(commands) }


echo no es un comando del sistema. Es un shell incorporado, y por lo tanto no directamente accesible desde el exec


out, _ := exec.Command("sh", "-c", "date +/"%Y-%m-%d %H:%M:%S %Z/"").Output() exec.Command("sh","-c","ls -al -t | grep go >>test.txt").Output() fmt.Printf("%s/n/n",out)

Casos probados de pareja y todos funcionan bien. Esto es un salvavidas si se trata de comandos de shell rápidos en su programa. No probado con casos complejos.