I want to execute a tmux session using Golang. I'm able to compile and get an exit status 1.
cmd := exec.Command("tmux", "new", "-s", "foo")
err := cmd.Run()
if err != nil {
log.Fatal(err)
}
I want to start a session. At the very least, I want to get a more tangible error. Any docs to refer me to? I couldn't find much on the Tmux manual pages. I think I'm missing a command.
You need to connect tmux to your terminal. Try to add these lines after cmd initialization:
cmd.Stdin = os.Stdin
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
UPDATE: link to the playground
Related
Learning how to implement containers on Golang, using MacOS Terminal,
I'm trying to implement the following code as promoted on Docker:
unc main() {
switch os.Args[1] {
case "run":
run()
default:
panic("Bad Command")
}
}
func run() {
fmt.Printf("Running %v \n", os.Args[2:])
cmd := exec.Command(os.Args[2], os.Args[3:]...)
cmd.Stdin = os.Stdin
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
cmd.SysProcAttr = &syscall.SysProcAttr{
Cloneflags: syscall.CLONE_NEWUTS,
}
cmd.Run()
}
However it seems that syscall.CLONE_NEWUTS works only with Linux.
How could I implement this on Mac ?
I don't have a macos at hand, but if you're running into a similar problem on linx (ubuntu), first check if you are running your go run . as root.
If you are not, you will need an extra flag (syscall.CLONE_NEWUSER) passed into SysProcAttr:
func run() {
fmt.Printf("Running %v \n", os.Args[2:])
cmd := exec.Command(os.Args[2], os.Args[3:]...)
cmd.Stdin = os.Stdin
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
cmd.SysProcAttr = &syscall.SysProcAttr{
Cloneflags: syscall.CLONE_NEWUTS | syscall.CLONE_NEWUSER,
}
cmd.Run()
What I think happens here is that without the syscall.NEWUSER flag, you will try to clone the current process as root, which you do not have permission to do so.
By the way OPs snippet is taken from https://www.youtube.com/watch?v=8fi7uSYlOdc (in which all commands are run as the root user).
thanks for #guites answer it worked with me. but adding the extra flag may be an unneeded workaround.
to solve this without adding the CLONE_NEWUSER flag you need to run your script as root. but buy default go executable run as non-root so you will need to build your script first and then run it with sudo.
go build main.go
sudo ./main
That what worked for me.
I am trying to get output of a interactive child process like python from the parent process. I have tried the following code to change the processes stdin to os.Stdin and stdout to os.Stdout but it isn't working. I can't see the output from the child process on the parent's terminal. Am I missing something or doing it wrong?
func main(){
cmd := exec.Command("python")
cmd.Stdin = os.Stdin
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
err := cmd.Run()
if err != nil{
fmt.Println("Cannot Execute cmd.")
}
}
Run exec.Command("python", "-i").
By default when running python not in a shell it won't enter interactive mode and won't print anything out.
This question already has an answer here:
How can I redirect the stdout and stderr of a command to both the console and a log file while outputting in real time?
(1 answer)
Closed 5 years ago.
I have a small Go tool which basically allows the user to define an command that than will be run using os/exec.
My problem is that I want to show the user the output (stdout/stderr) of the command.
An example could look like this:
The user defines a command that in the end is sh test.sh.
Content of test.sh:
echo "Start"
sleep 7s
echo "Done"
With my current implementation the user can only see the output once the complete command finished. In the example above the user wouldn't see the output Start until the sleep command and the second echo finish.
I currently retrieve the output of the command like this:
cmd := exec.Command(command, args...)
cmd.Dir = dir
// Attach to the standard out to read what the command might print
stdout, err := cmd.StdoutPipe()
if err != nil {
log.Panic(err)
}
// Execute the command
if err := cmd.Start(); err != nil {
log.Panic(err)
}
buf := new(bytes.Buffer)
buf.ReadFrom(stdout)
log.Print(buf.String())
Is it somehow possible to read the stdout/stderr in real-time. Meaning that as soon as the user defined command creates and output it is printed?
Thank you mh-cbon. That pushed me in the right direction.
The code now looks like this and does exactly what I want it to do. I also found that when I use Run() instead of Start() the execution of the program only continues after the command has finished.
cmd := exec.Command(command, args...)
cmd.Dir = dir
var stdBuffer bytes.Buffer
mw := io.MultiWriter(os.Stdout, &stdBuffer)
cmd.Stdout = mw
cmd.Stderr = mw
// Execute the command
if err := cmd.Run(); err != nil {
log.Panic(err)
}
log.Println(stdBuffer.String())
I have a method that can spawn an interactive process, now how do I log everything (including stdin and stdout) after spawning ?
e.g.,
func execute(cmd1 string, slice []string) {
cmd := exec.Command(cmd1, slice...)
// redirect the output to terminal
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
cmd.Stdin = os.Stdin
cmd.Run()
}
..
The interactive program could be :
execute(ftp)
I think I have to dup stdin, stdout and read write in separate thread.
Rather than redirecting it's output to the terminal read it and then you can log/print do whatever you want with it.
stdout, err := cmd.StdoutPipe()
b, _ := ioutil.ReadAll(stdout)
fmt.Println(string(b))
Something like the code above would work though there are many options. I think you'll want to remove all that code you have to redirect to the terminal.
you could store the output in a temporary buffer and write it to several places
outBuf := bytes.Buffer{}
cmd := exec.Command(cmd1, slice...)
cmd.Stdout = &outBuf
cmd.Run()
if outBuf.Len() > 0 {
log.Printf("%s", outBuf.String())
fmt.Fprintf(os.Stdout, "%s", outBuf.String())
}
Im trying the following, to use go to bundle a folder of html files using the CMD web2exe.
cmd := exec.Command("web2exe-win.exe", "html-folder --main index.html --export- to windows-x32 --output-dir")
var out bytes.Buffer
cmd.Stdout = &out
err := cmd.Run()
if err != nil {
fmt.Println(err)
}
fmt.Println(out)
When a program exits non-zero it means that it could not run successfully and typically it has written an error message to STDERR (or STDOUT). You should somehow capture or print the output streams so you can inspect them for error messages. For example:
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
Note also that your command line arguments should be separate array elements (instead of space separated elements in a single string as they are now):
cmd := exec.Command("web2exe-win.exe", "html-folder", "--main", "index.html", "--export-to", "windows-x32", "--output-dir")