
Go 程序访问 os.Args 时需注意:os.Args[0] 是程序名,用户输入的首个参数实际位于 os.Args[1];若未传参却直接访问 os.Args[1],将触发 panic("index out of range")。正确做法是检查 len(os.Args)
go 程序访问 `os.args` 时需注意:`os.args[0]` 是程序名,用户输入的首个参数实际位于 `os.args[1]`;若未传参却直接访问 `os.args[1]`,将触发 panic("index out of range")。正确做法是检查 `len(os.args)
在 Go CLI 程序中,os.Args 是一个字符串切片,其结构固定为:[program_name, arg1, arg2, ...]。这意味着即使用户未传入任何参数,os.Args 至少包含一个元素(即执行文件名),因此 len(os.Args) 永远 ≥ 1。原代码中 if len(os.Args) == 0 的判断逻辑永远为假,导致后续无条件执行 filename := os.Args[1] —— 当用户仅运行 ./gohex 而未提供文件名时,os.Args 长度为 1,索引 1 已越界,引发运行时 panic。
✅ 正确的防御性写法是:检查参数总数是否至少为 2(即 program_name + filename):
package main
import (
"encoding/hex"
"fmt"
"io/ioutil"
"log"
"os"
)
func main() {
// ✅ 正确检查:用户必须提供至少一个参数(即 os.Args[1] 存在)
if len(os.Args) ")
}
filename := os.Args[1]
data, err := ioutil.ReadFile(filename)
if err != nil {
log.Fatalf("failed to read %s: %v", filename, err)
}
fmt.Println(hex.Dump(data))
}
? 关键注意事项:
- os.Args[0] 是可执行文件路径(如 ./gohex 或 gohex),不可忽略也不应校验为空;
- 使用
- log.Fatal 会自动调用 os.Exit(1),比手动 fmt.Println + os.Exit(1) 更简洁且带时间戳(调试友好);
- ⚠️ ioutil.ReadFile 已被弃用(Go 1.16+),生产环境推荐升级为 os.ReadFile:
data, err := os.ReadFile(filename) // 替代 ioutil.ReadFile
? 进阶建议: 对于复杂 CLI,推荐使用成熟库如 github.com/spf13/cobra 或标准库 flag 包,它们内置参数解析、帮助生成与类型校验,从根本上规避手动索引风险。但对轻量脚本,掌握 len(os.Args) 边界检查仍是必备基础技能。











