4

I'm trying to execute a command that asks for several inputs for example if you try to copy a file from local device to the remote device we use scp test.txt user@domain:~/ then it asks us for the password. What I want is I want to write a go code where I provide the password in the code itself for example pass:='Secret Password'. Similarly, I have CLI command where it asks us for several things such as IP, name, etc so I need to write a code where I just declare all the values in the code itself and when I run the code it doesn't ask anything just take all the inputs from code and run CLI command in case of copying file to remote it should not ask me for password when I run my go binary it should directly copy my file to remote decide.

func main() {
    cmd := exec.Command("scp", "text.txt", "user@domain:~/")        
    stdin, err := cmd.StdinPipe()
    if err = cmd.Start(); err != nil {
        log.Fatalf("failed to start command: %s", err)
    }
    io.WriteString(stdin, "password\n")
    if err = cmd.Wait(); err != nil {
    log.Fatalf("command failed: %s", err)
    }
}

If I use this code it is stuck on user@domain's password:

And no file is copied to the remote device.

3
  • try specifying password as part of your url as user:password@domain:~/, for other commands try specifying them as parameters. Commented Jan 29, 2019 at 10:27
  • Above command is just for example of interactive command. I have CLI that asks several questions such as Enter Your Name or What is your IP Commented Jan 30, 2019 at 11:46
  • You likely need to spawn a PTY and attach the child process to it. Commented Oct 3, 2021 at 19:09

3 Answers 3

2
+50

Solution 1

You can bypass this with printf command

cmd := "printf 'John Doe\nNew York\n35' | myInteractiveCmd"
out, err := exec.Command("bash", "-c", cmd).Output()

Solution 2

You can use io.Pipe(). Pipe creates a synchronous in-memory pipe and you can write your answers into io.Writer and your cmd will read from io.Reader.

r, w := io.Pipe()
cmd := exec.Command("myInteractiveCmd")
cmd.Stdin = r
go func() {
    fmt.Fprintf(w, "John Doe\n")
    fmt.Fprintf(w, "New York\n")
    fmt.Fprintf(w, "35\n")
    w.Close()
}()
cmd.Start()
cmd.Wait()

Testing info To test this I wrote cmd which asks for name, city, age and writes the result in file.

reader := bufio.NewReader(os.Stdin)

fmt.Print("Name: ")
name, _ := reader.ReadString('\n')
name = strings.Trim(name, "\n")
...
Sign up to request clarification or add additional context in comments.

Comments

0

One way to go about this is to use command-line flags:

package main

import (
    "flag"
    "fmt"
    "math"
)

func main() {
    var (
        name = flag.String("name", "John", "Enter your name.")
        ip   = flag.Int("ip", 12345, "What is your ip?")
    )
    flag.Parse()
    fmt.Println("name:", *name)
    fmt.Println("ip:", *ip)
}

Now you can run the program with name and ip flags:

go run main.go -name="some random name" -ip=12345678910`
some random name
ip: 12345678910

This channel is a good resource—he used to work for the Go team and made tons of videos on developing command-line programs in the language. Good luck!

Comments

0

I come across this question when trying to run the linux make menuconfig through golang os/exec.

To accomplish what you are trying to achieve try to set the cmd.Stdin to os.Stdin. Here is a working example:

package main

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

type cmdWithEnv struct {
    pwd     string
    command string
    cmdArgs []string
    envs    []string
}

func runCommand(s cmdWithEnv) error {
    cmd := exec.Command(s.command, s.cmdArgs...)
    if len(s.pwd) != 0 {
        cmd.Dir = s.pwd
    }

    env := os.Environ()
    env = append(env, s.envs...)
    cmd.Env = env

    fmt.Printf("%v\n", cmd)
    cmd.Stdout = os.Stdout
    cmd.Stderr = os.Stderr
    cmd.Stdin = os.Stdin // setting this allowed me to interact with ncurses interface from `make menuconfig`

    err := cmd.Start()
    if err != nil {
        return err
    }

    if err := cmd.Wait(); err != nil {
        return err
    }
    return nil
}

func buildPackage() {
    makeKernelConfig := cmdWithEnv{
        pwd:     "linux",
        command: "make",
        cmdArgs: []string{"-j12", "menuconfig"},
        envs:    []string{"CROSS_COMPILE=ccache arm-linux-gnueabihf-", "ARCH=arm"},
    }

    runCommand(makeKernelConfig)
}

func main() {
    buildPackage()
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.