从build your own shell记录一些go用法

读取标准输入

bufio.Scanner

逐行读取

1
2
3
4
5
6
7
8
9
func main() {
	scanner := bufio.NewScanner(os.Stdin)

	// 读取一行
	if scanner.Scan() {
		input := scanner.Text() // 字符串,不含换行符
		fmt.Println(input)
	}
}

bufio.Reader

流式读取,最高性能,可指定缓冲区大小

1
2
3
4
5
6
7
8
9
func main(){
    reader := bufio.NewReader(os.Stdin)

    // 含换行符
    line, err := reader.ReadString('\n') // 读取直到遇到\n
    if err == nil {
        fmt.Println(line)
    }
}

slices包

Column1 Column2
slices.Contains(s, v) 判断切片是否包含某个值。
slices.Index(s, v) 返回值在切片中的索引,找不到返回 -1。
slices.Delete(s, i, j) 删除索引 i 到 j 之间的元素。
slices.Replace(s, i, j, v...) 替换指定范围的元素。
slices.Clone(s) 快速创建一个切片的浅拷贝(Shadow Copy)。
slices.Reverse(s) 直接在原切片上反转所有元素。
slices.Sort(s) 对可比较切片进行升序排序。
slices.SortFunc(s, func) 自定义排序规则(比如按年龄排序 (a, b) => a.Age - b.Age)。
slices.BinarySearch(s, v) 在已排序的切片中进行二分查找。
slices.Concat(s1, s2, ...) 将多个切片拼接成一个新切片。在此之前,你必须使用多次 append。
slices.Compact(s) 连续重复元素去重(仅保留一个)。
slices.All(s) 返回一个包含索引和值的迭代器,用于 for i, v := range slices.All(s)
slices.Values(s) 仅返回值的迭代器。
slices.Collect(it) 非常重要。 将一个迭代器转换回切片。
slices.Sorted(it) 将迭代器中的内容收集并排序后返回新切片。

寻找可执行文件

exec.LookPath 的作用是在系统的 PATH 环境变量定义的目录中,寻找一个可执行文件的完整路径。

  • 跨平台路径分割:它会自动处理Linux/macOS的冒号:和Windows的分号;
  • 执行权限检查:它不仅看文件是否存在,还会检查该文件是否真的有执行权限。
  • Windows 后缀处理:在 Windows 上,如果你搜 git,它会自动帮你匹配 git.exe 或 git.bat。
1
2
3
4
5
6
path, err := exec.LookPath("ls")
if err != nil {
    fmt.Println("找不到该命令")
} else {
    fmt.Println("命令的完整路径是:", path) // 输出类似 /usr/bin/ls
}

执行外部命令

只想要结果(简单、阻塞)

1
2
3
4
output, err := exec.Command("date").Output()
if err == nil {
    fmt.Println(string(output))
}

实时交互

1
2
3
4
5
6
7
8
cmd := exec.Command("top")
cmd.Stdout = os.Stdout // 连接标准输出
cmd.Stderr = os.Stderr // 连接错误输出
cmd.Stdin = os.Stdin   // 连接标准输入(允许用户交互)

if err := cmd.Run(); err != nil {
    log.Fatal(err)
}

os包

os.Getwd(): 获取当前工作目录(pwd)。 os.Chdir(dir string): 切换当前工作目录(实现 Shell 的 cd 命令必用) os.UserHomeDir(): 获取当前用户的家目录

参考

  1. Google Gemini
  2. https://app.codecrafters.io/courses/shell/overview