Files
liyp 4365e80075 sshtools: 非交互 SSH 工具集(golink / goscp)
golink: 一条命令在远端执行,退出码原样透传,从不提示、不分配终端。
goscp:  用 SCP 协议上传,-files 一个参数同时接受文件和目录。

- 纯 Go,唯一依赖 golang.org/x/crypto,可离线交叉编译到六个桌面平台
- internal/sshx 统一建连、认证(password + keyboard-interactive)与主机密钥策略
- smoketest/ 自带迷你 sshd,57 项端到端测试(golink 38 + goscp 19)
2026-10-19 10:22:53 +08:00

54 lines
1.7 KiB
Go

// Package cli holds small command-line helpers shared by the sshtools binaries.
package cli
import "strings"
// Split reorders a raw argument list so that Go's flag package can parse it
// even when flags follow positional arguments, as in:
//
// golink user@host -p secret -port 22 -command uptime
//
// flag.Parse stops at the first non-flag argument, so that raw order would
// otherwise leave every flag unset and silently do the wrong thing. Split walks
// the arguments once and collects flags (together with the value of any flag
// named in takesValue) into flags, and everything else into positional.
//
// The caller is expected to concatenate the results:
//
// flags, positional := cli.Split(os.Args[1:], valueFlags)
// fs.Parse(append(flags, positional...))
//
// A literal "--" ends flag processing; everything after it is positional.
func Split(args []string, takesValue map[string]bool) (flags, positional []string) {
for i := 0; i < len(args); i++ {
arg := args[i]
if arg == "--" {
positional = append(positional, args[i+1:]...)
break
}
if !isFlag(arg) {
positional = append(positional, arg)
continue
}
flags = append(flags, arg)
name := strings.TrimLeft(arg, "-")
if strings.ContainsRune(name, '=') {
continue // -port=22 carries its value inline
}
if takesValue[name] && i+1 < len(args) {
i++
flags = append(flags, args[i])
}
}
return flags, positional
}
// isFlag reports whether arg looks like a flag rather than a positional value.
// A bare "-" and negative numbers are treated as positional.
func isFlag(arg string) bool {
if len(arg) < 2 || arg[0] != '-' {
return false
}
return arg[1] < '0' || arg[1] > '9'
}