Golang中如何在Windows终端获取提示字符串
Golang中如何在Windows终端获取提示字符串 我正在使用Go语言模拟一个Windows终端。 我希望它能与真实的Windows终端窗口完全一致,就像我在执行一个.bat文件一样。但我目前遇到的问题是,如何从cmd进程中获取并打印提示符字符串。 以下是我当前的代码:
package minion_core
import (
"bufio"
"fmt"
"os/exec"
"strings"
"syscall"
"time"
)
var TestMode = true
func Test() {
// Start a new command提示符 process
cmd := exec.Command("cmd.exe")
cmd.SysProcAttr = &syscall.SysProcAttr{HideWindow: true}
// Create pipes for standard input and output
stdin, err := cmd.StdinPipe()
if err != nil {
fmt.Println("Error creating stdin pipe:", err)
return
}
stdout, err := cmd.StdoutPipe()
if err != nil {
fmt.Println("Error creating stdout pipe:", err)
return
}
// Start the command
if err := cmd.Start(); err != nil {
fmt.Println("Error starting command:", err)
return
}
// Create a scanner to read the output
scanner := bufio.NewScanner(stdout)
// Variable to hold command output
var output strings.Builder
// Start a goroutine to read the command output
go func() {
for scanner.Scan() {
fmt.Println("⚡ " + scanner.Text() + "\n")
}
}()
// Function to execute commands
executeCommand := func(command string) {
_, err := stdin.Write([]byte(command + "\n"))
if err != nil {
fmt.Println("Error writing to stdin:", err)
}
// Wait a moment to ensure the output is captured
time.Sleep(1 * time.Second)
// Print the current output after executing the command
fmt.Println("Command output:\n", output.String())
// Clear the output for the next command
output.Reset()
}
// Execute several commands
executeCommand("echo Hello, World!")
executeCommand("dir")
executeCommand("nslookup")
executeCommand("google.com")
executeCommand("exit")
executeCommand("cd ..")
executeCommand("cd ..")
executeCommand("exit") // Exit the command prompt (optional)
// Close the stdin pipe
stdin.Close()
// Wait for the command to finish
if err := cmd.Wait(); err != nil {
fmt.Println("Error waiting for command:", err)
return
}
}
如你所见,我以一秒的间隔逐个执行命令。但我不知道如何打印cmd的实际提示符,而不是那个闪电符号。 如果你知道如何处理这个问题,请帮助我。
更多关于Golang中如何在Windows终端获取提示字符串的实战教程也可以访问 https://www.itying.com/category-94-b0.html
1 回复
更多关于Golang中如何在Windows终端获取提示字符串的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
在Windows终端中获取提示字符串需要处理cmd.exe的特殊输出行为。以下是修改后的代码,可以正确捕获和显示提示符:
package main
import (
"bufio"
"bytes"
"fmt"
"io"
"os/exec"
"strings"
"syscall"
"time"
)
func main() {
cmd := exec.Command("cmd.exe")
cmd.SysProcAttr = &syscall.SysProcAttr{HideWindow: true}
stdin, err := cmd.StdinPipe()
if err != nil {
fmt.Println("Error creating stdin pipe:", err)
return
}
stdout, err := cmd.StdoutPipe()
if err != nil {
fmt.Println("Error creating stdout pipe:", err)
return
}
if err := cmd.Start(); err != nil {
fmt.Println("Error starting command:", err)
return
}
// 使用带缓冲的读取器
reader := bufio.NewReader(stdout)
// 读取初始提示符
go func() {
for {
line, err := reader.ReadString('\n')
if err != nil {
if err == io.EOF {
break
}
fmt.Println("Read error:", err)
break
}
// 清理输出并显示
line = strings.TrimSpace(line)
if line != "" {
fmt.Println(line)
}
}
}()
// 给cmd.exe时间初始化
time.Sleep(100 * time.Millisecond)
// 发送命令并等待提示符重新出现
commands := []string{
"echo Hello, World!",
"dir",
"cd ..",
"exit",
}
for _, command := range commands {
// 发送命令
fmt.Printf("> %s\n", command)
stdin.Write([]byte(command + "\r\n"))
// 等待命令执行完成(提示符重新出现)
time.Sleep(500 * time.Millisecond)
}
// 关闭输入流
stdin.Close()
// 等待进程结束
cmd.Wait()
}
更高级的实现,使用pty来更好地模拟终端:
package main
import (
"fmt"
"io"
"os"
"os/exec"
"syscall"
"unsafe"
"golang.org/x/term"
)
// Windows控制台API常量
const (
ENABLE_VIRTUAL_TERMINAL_PROCESSING = 0x0004
STD_OUTPUT_HANDLE = -11
)
var (
kernel32 = syscall.NewLazyDLL("kernel32.dll")
procGetStdHandle = kernel32.NewProc("GetStdHandle")
procGetConsoleMode = kernel32.NewProc("GetConsoleMode")
procSetConsoleMode = kernel32.NewProc("SetConsoleMode")
)
func enableVTMode() error {
h, _, _ := procGetStdHandle.Call(uintptr(STD_OUTPUT_HANDLE))
var mode uint32
procGetConsoleMode.Call(h, uintptr(unsafe.Pointer(&mode)))
mode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING
ret, _, err := procSetConsoleMode.Call(h, uintptr(mode))
if ret == 0 {
return err
}
return nil
}
func main() {
// 启用VT模式以获得更好的终端支持
enableVTMode()
cmd := exec.Command("cmd.exe")
cmd.SysProcAttr = &syscall.SysProcAttr{
HideWindow: false,
CreationFlags: syscall.CREATE_NEW_CONSOLE,
}
stdin, _ := cmd.StdinPipe()
stdout, _ := cmd.StdoutPipe()
stderr, _ := cmd.StderrPipe()
cmd.Start()
// 合并stdout和stderr的读取
go io.Copy(os.Stdout, stdout)
go io.Copy(os.Stderr, stderr)
// 从标准输入读取并转发到cmd
go func() {
scanner := bufio.NewScanner(os.Stdin)
for scanner.Scan() {
stdin.Write([]byte(scanner.Text() + "\r\n"))
}
}()
cmd.Wait()
}
使用conpty的替代方案(Windows 10+):
package main
import (
"context"
"fmt"
"io"
"os"
"os/exec"
"time"
"github.com/ActiveState/termtest/conpty"
)
func main() {
cpty, err := conpty.New(80, 25)
if err != nil {
panic(err)
}
defer cpty.Close()
// 启动cmd.exe
cmd := exec.Command("cmd.exe")
pid, err := cpty.Spawn(cmd.Path, cmd.Args, &cmd.SysProcAttr)
if err != nil {
panic(err)
}
fmt.Printf("Spawned process with PID: %d\n", pid)
// 读取输出
go func() {
buf := make([]byte, 1024)
for {
n, err := cpty.Read(buf)
if err != nil {
break
}
fmt.Print(string(buf[:n]))
}
}()
// 发送命令
commands := []string{
"echo Prompt test",
"cd /",
"dir",
"exit",
}
for _, cmd := range commands {
cpty.Write([]byte(cmd + "\r\n"))
time.Sleep(500 * time.Millisecond)
}
// 等待进程结束
process, _ := os.FindProcess(int(pid))
process.Wait()
}
最简单的解决方案,直接使用cmd的/K参数保持提示符:
package main
import (
"bufio"
"fmt"
"io"
"os/exec"
"strings"
"syscall"
)
func main() {
cmd := exec.Command("cmd.exe", "/K", "prompt $P$G")
cmd.SysProcAttr = &syscall.SysProcAttr{HideWindow: true}
stdin, _ := cmd.StdinPipe()
stdout, _ := cmd.StdoutPipe()
cmd.Start()
// 读取输出
go func() {
reader := bufio.NewReader(stdout)
for {
line, err := reader.ReadString('\r')
if err != nil {
break
}
// 清理并显示输出
line = strings.TrimRight(line, "\r\n")
if strings.Contains(line, "Microsoft") ||
strings.Contains(line, "Copyright") ||
strings.Contains(line, "Administrator:") {
continue
}
fmt.Println(line)
}
}()
// 发送命令
commands := []string{
"cd /",
"echo Testing prompt",
"dir",
"exit",
}
for _, c := range commands {
stdin.Write([]byte(c + "\r\n"))
}
stdin.Close()
cmd.Wait()
}
这些示例展示了不同的方法来获取和显示Windows终端的提示字符串。第一种方法是最直接的,通过适当的延迟和输出处理来确保提示符能够正确显示。

