You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用Golang CLI编写脚本批量远程SSH执行命令?

Golang CLI批量SSH执行命令脚本

下面是一个完整的实现,支持从指定文件读取ip username:password格式的登录信息,批量登录远程服务器并执行指定Shell命令,同时支持并发处理提升效率。

前置依赖

首先需要安装SSH相关的依赖包:

go get golang.org/x/crypto/ssh

完整代码

package main

import (
	"bufio"
	"flag"
	"fmt"
	"log"
	"os"
	"strings"
	"sync"
	"time"

	"golang.org/x/crypto/ssh"
)

func main() {
	// 解析命令行参数
	cmdFlag := flag.String("cmd", "", "需要执行的Shell命令(必填)")
	fileFlag := flag.String("file", "logins.txt", "包含SSH登录信息的文件路径,默认logins.txt")
	concurrencyFlag := flag.Int("concurrency", 10, "并发执行的goroutine数量")
	flag.Parse()

	if *cmdFlag == "" {
		log.Fatal("必须通过 -cmd 指定要执行的Shell命令")
	}

	// 读取登录文件
	file, err := os.Open(*fileFlag)
	if err != nil {
		log.Fatalf("打开文件失败: %v", err)
	}
	defer file.Close()

	var logins []string
	scanner := bufio.NewScanner(file)
	for scanner.Scan() {
		line := strings.TrimSpace(scanner.Text())
		if line == "" {
			continue
		}
		logins = append(logins, line)
	}

	if err := scanner.Err(); err != nil {
		log.Fatalf("读取文件失败: %v", err)
	}

	// 并发执行任务
	sem := make(chan struct{}, *concurrencyFlag)
	var wg sync.WaitGroup

	for _, login := range logins {
		wg.Add(1)
		sem <- struct{}{}

		go func(loginStr string) {
			defer wg.Done()
			defer func() { <-sem }()

			// 解析登录信息:分割IP和用户名密码
			parts := strings.SplitN(loginStr, " ", 2)
			if len(parts) != 2 {
				log.Printf("无效的登录格式: %s", loginStr)
				return
			}
			ip := parts[0]
			userPass := parts[1]

			// 分割用户名和密码
			upParts := strings.SplitN(userPass, ":", 2)
			if len(upParts) != 2 {
				log.Printf("无效的用户名密码格式: %s", userPass)
				return
			}
			username := upParts[0]
			password := upParts[1]

			// 配置SSH客户端
			config := &ssh.ClientConfig{
				User: username,
				Auth: []ssh.AuthMethod{
					ssh.Password(password),
				},
				HostKeyCallback: ssh.InsecureIgnoreHostKey(), // 生产环境请替换为安全的HostKey验证
				Timeout:         5 * time.Second,
			}

			// 建立SSH连接
			client, err := ssh.Dial("tcp", fmt.Sprintf("%s:22", ip), config)
			if err != nil {
				log.Printf("连接服务器 %s 失败: %v", ip, err)
				return
			}
			defer client.Close()

			// 创建会话并执行命令
			session, err := client.NewSession()
			if err != nil {
				log.Printf("服务器 %s 创建会话失败: %v", ip, err)
				return
			}
			defer session.Close()

			// 捕获命令输出
			output, err := session.CombinedOutput(*cmdFlag)
			if err != nil {
				log.Printf("服务器 %s 执行命令失败: %v\n输出: %s", ip, err, string(output))
				return
			}

			fmt.Printf("=== 服务器 %s 执行结果 ===\n%s\n", ip, string(output))
		}(login)
	}

	wg.Wait()
	log.Println("所有任务执行完成")
}

代码说明

  1. 命令行参数解析:

    • -cmd:必填参数,指定要在远程服务器执行的Shell命令
    • -file:可选参数,指定登录信息文件路径,默认使用当前目录的logins.txt
    • -concurrency:可选参数,指定并发执行的goroutine数量,默认10(可根据服务器性能调整)
  2. 登录信息解析:

    • 逐行读取文件内容,跳过空行
    • 将每行按空格分割为IP和username:password部分,再按冒号分割出用户名和密码
  3. SSH连接与命令执行:

    • 创建SSH客户端配置,设置密码认证、连接超时
    • 建立TCP连接到远程服务器的22端口
    • 创建SSH会话,通过CombinedOutput执行命令并同时捕获标准输出和错误输出
  4. 并发控制:

    • 使用信号量(sem通道)限制并发数,避免同时发起过多连接导致资源耗尽
    • 使用sync.WaitGroup等待所有goroutine执行完成

使用示例

  1. 准备logins.txt文件,每行格式如下:
192.168.1.10 root:123456
192.168.1.11 admin:abcdef
...
  1. 编译并运行脚本:
go build -o ssh-exec
./ssh-exec -cmd "uptime && df -h" -file ./logins.txt -concurrency 15

注意事项

  • 安全问题:ssh.InsecureIgnoreHostKey()会跳过主机密钥验证,生产环境中请替换为ssh.FixedHostKey或使用已知主机文件验证,避免中间人攻击;同时建议使用SSH密钥认证替代密码明文存储
  • 并发调整:并发数不要设置过高,否则可能触发远程服务器的连接限制
  • 错误处理:脚本会打印每个服务器的连接/执行错误,方便排查问题
  • 超时设置:已设置5秒连接超时,可根据网络情况调整Timeout值

内容的提问来源于stack exchange,提问作者Jamal Gains

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.12 11:15:57