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.