作者:E4b9a6, 创建:2020-05-10, 字数:7988, 已阅:31, 最后更新:2020-05-10
在Windows下,有着许多优秀的SSH客户端,在Linux上,选择就没有那么广泛了
使用ssh
连接服务器是每一个软件开发者常见的操作,无论是免费的MobaXterm
还是付费的termius
都算得上是非常好用,尤其是termius
,作为商业工具兼顾了易用与美观
termius
收费较高,免费的版本缺失不少功能,与免费的MobaXterm
没有太大差别
后来发现直接使用ssh也非常好用,如在$HOME/.ssh/config
添加如下配置
Host company-develop
HostName 192.168.122.4
Port 22
User chancel
IdentityFile /home/chancel/.ssh/id_rsa
...
然后在命令行输入ssh
+tab
按键,可以看到智能补全
~❯ ssh company-
company-develop ...
使用多了,发现这样也非常便捷
$HOME/.ssh/config
文件是SSH客户端的配置文件,用于设置和管理SSH连接的参数和选项,它可以包含多个主机配置块,每个主机配置块定义了与特定主机的详细连接参数
配置文件中的每个主机配置块由以下几个常见部分组成:
通过修改$HOME/.ssh/config
文件,可以方便地设置和管理SSH连接的参数,不用每次连接时都手动输入命令行选项
此外,配置文件还可以提供更高级的功能,如通过别名快速连接主机、设置跳板主机、配置连接超时等,这些参数可以参考man ssh_config
获得
编辑~/.ssh/config
文件
Host chancel-pc # 别名,用于连接时驶入
HostName 192.168.10.1 # 连接IP
User ycs # 用户名
Port 10086 # SSH 端口
ServerAliveInterval 60 # 每60秒发送一次心跳避免SSH连接中断
IdentityFile .ssh/id_rsa # 本地证书
然后授权
chmod 600 ~/.ssh/config
测试连接
ssh chancel-pc
如果config
文件中配置的服务器多起来还是非常难管理的,这个时候图形界面的SSH客户端会有优势,能够列表展示所有服务器信息
这个时候我们可以利用一些第三方插件来实现如ssh-config-manager
、sshmenu
、sshrc
考虑到这个需求并不复杂,且ssh的端口、证书、密码属于敏感信息,可以自己实现一个脚本来展现列表形式
这里用golang
来实现,借助golang
优秀的打包机制,可以写一次代码在多个平台上使用
package main
import (
"bufio"
"flag"
"fmt"
"os"
"os/exec"
"strings"
)
// Function to parse SSH configuration file and return a slice of maps containing the configuration details
func parseSSHConfig(configPath string) ([]map[string]string, error) {
// Open the SSH configuration file
configFile, err := os.Open(configPath)
if err != nil {
fmt.Println(err)
return nil, err
}
defer configFile.Close()
// Initialize variables to store the configuration data
configDicts := []map[string]string{} // Slice of maps to store multiple configurations
currentDict := map[string]string{} // Map to store the current configuration
// Create a scanner to read the configuration file line by line
scanner := bufio.NewScanner(configFile)
for scanner.Scan() {
line := strings.TrimSpace(scanner.Text()) // Remove leading and trailing whitespaces
// Skip empty lines and lines starting with "#"
if line == "" || strings.HasPrefix(line, "#") {
continue
}
// If line starts with "Host ", it indicates a new configuration block
if strings.HasPrefix(line, "Host ") {
// If there is any existing configuration, add it to the configDicts slice
if len(currentDict) > 0 {
configDicts = append(configDicts, currentDict)
}
// Create a new map for the current configuration block
currentDict = map[string]string{}
currentDict["Host"] = strings.TrimSpace(strings.TrimPrefix(line, "Host "))
} else {
// Split the line into key-value pairs
parts := strings.SplitN(line, " ", 2)
if len(parts) == 2 {
key := strings.TrimSpace(parts[0])
value := strings.TrimSpace(parts[1])
// Store the key-value pair in the currentDict map
currentDict[key] = value
}
}
}
// Add the last configuration block to the configDicts slice
if len(currentDict) > 0 {
configDicts = append(configDicts, currentDict)
}
// Return the slice of maps containing the configuration details and no error
return configDicts, nil
}
// Function to print the SSH configuration
func printSSHConfig(configs []map[string]string) {
// Printing header
fmt.Println("************************ Hi, Welcome to use Go-SSH Tool *****************************")
fmt.Println()
fmt.Println("+-----+------------------------------+-------------------------+------------------------------------------+")
fmt.Println("| id | Host | username | address |")
fmt.Println("+-----+------------------------------+-------------------------+------------------------------------------+")
// Printing each SSH configuration
for i, config := range configs {
fmt.Printf("| %-3d | %-28s | %-23s | %-40s |\n", i+1, config["Host"], config["User"], config["HostName"])
}
fmt.Println("+-----+------------------------------+-------------------------+------------------------------------------+")
fmt.Println()
fmt.Println("Tips: Press a number between 1 and", len(configs)-1, "to select the host to connect, or \"q\" to quit.")
fmt.Println()
}
func main() {
// Parsing command line arguments
configPath := flag.String("c", "$HOME/.ssh/config", "Path to SSH config file")
flag.Parse()
// Expanding environment variables in the config path
expandedPath := os.ExpandEnv(*configPath)
// Parsing the SSH config file
configs, err := parseSSHConfig(expandedPath)
if err != nil {
fmt.Println("Error:", err)
return
}
// Printing the SSH configuration
printSSHConfig(configs)
// Creating a scanner to read user input
scanner := bufio.NewScanner(os.Stdin)
for {
fmt.Print("# ")
scanner.Scan()
input := scanner.Text()
// Exiting the program if user enters "q"
if input == "q" {
return
}
id := -1
// Parsing the user input to get the selected SSH configuration ID
fmt.Sscanf(input, "%d", &id)
if id >= 1 && id <= len(configs) {
// Getting the selected SSH configuration
sshConfig := configs[id-1]
// Creating arguments for the "ssh" command
var args []string
for key, value := range sshConfig {
// Skipping "Host", "User", and "HostName" keys
if key == "Host" || key == "User" || key == "HostName" {
continue
}
arg := fmt.Sprintf("-o %s=%s", key, value)
args = append(args, arg)
}
// Appending username and host name to the command arguments
cmdArgs := append(args, fmt.Sprintf("%s@%s", sshConfig["User"], sshConfig["HostName"]))
// Creating the "ssh" command
sshCmd := exec.Command("ssh", cmdArgs...)
sshCmd.Stdout = os.Stdout
sshCmd.Stdin = os.Stdin
sshCmd.Stderr = os.Stderr
// Running the "ssh" command
err := sshCmd.Run()
if err != nil {
fmt.Println("Error:", err)
os.Exit(0)
}
} else {
fmt.Println("Error: Invalid input")
}
// Printing the SSH configuration after each iteration
printSSHConfig(configs)
}
}
代码仓库:github仓库 - chancelyg/go-ssh
上面的代码请自行审阅,这个工具可以实现$HOME/.ssh/config
中的ssh服务器以列表的形式呈现出来
你可以使用一个数字选择要连接的主机,然后会自动使用SSH连接到该主机
如下
❯ ./go-ssh
************************ Hi, Welcome to use Go-SSH Tool *****************************
+-----+------------------------------+-------------------------+------------------------------------------+
| id | Host | username | address |
+-----+------------------------------+-------------------------+------------------------------------------+
| 1 | 192.168.122.4 | chancel | 192.168.122.4 |
| 2 | 192.168.4.15 | chancel | 192.168.4.15 |
| 3 | 192.168.11.2 | chancel | 192.168.11.2 |
| 4 | 192.168.11.3 | chancel | 192.168.11.3 |
| 5 | 192.168.11.12 | chancel | 192.168.11.12 |
| 6 | 192.168.4.10 | chancel | 192.168.4.10 |
+-----+------------------------------+-------------------------+------------------------------------------+
Tips: Press a number between 1 and 5 to select the host to connect, or "q" to quit.
#
灵感