shell script

说到 shell script,bash 绝对是 shell 界的王,几乎所有 linux 系统都使用 bash 作为默认 shell。因此其拥有最高的兼容性。

当然,bash 毕竟也是老编程语言,随着时代变化,其设计缺陷与难用部分也开始显现。至少我是非常不愿意[1]使用 bash 编写程序的。有许多脚本语言可以用来替代 bash,例如我已经用 python 写脚本很久了。还有许多与 bash 竞争的 shell 本身也自带了一门脚本语言,例如 fish,nu 等,甚至 just 也能算一个 bash 的竞争者。这些脚本需要专门的解释器运行,我也会放在后面介绍。

除此之外,还有人既想写出人类可读的代码,又想借用 bash 超高的兼容性,因此便开发了能够编译为 bash 的高阶语言,例如 pnut,amber。

Shebang

放在脚本开头,以指示此脚本使用的解释器。因此如果写了 #!/bin/bash,则表示脚本是一个 bash 脚本,可以直接 ./filename 执行。

不过为了最佳的兼容性(NixOS 太怪胎了),可以写成 #!/usr/bin/env bash。

bash

bash 的兼容性有多强呢?你可以在几乎所有 linux,手机,各种终端设备,windows(通过 WSL 或 msys2),macos(默认 zsh,兼容) 上执行 bash 脚本。基本上这个时代没有几个设备是不用 bash 的。

在 Windows 上使用 bash

  1. 使用 scoop 安装 git:scoop install git
  2. 进入 scoop/shims (默认位置在 C:\Users\<username>\scoop\shims)
  3. 编辑系统环境变量,把 C:\Users\<username>\scoop\shims 放到 C:\WINDOWS\System32 之前。(要让 scoop 的 bash 比 WSL 的 bash 优先级更高[2])

这样你就可以在 Win+R 的运行或者任意 cmd 里使用 sh 打开 bash 了,并且不会开一个新窗口。

随笔

此处不会涉及 bash 系统教学,只会零碎记一些知识点。系统学习可以看 external 1.。

关于 ble.sh:经常会有文章(例如 atuin 的 installation)会推荐 ble.sh,但是我尝试以后发现,不好用!只要你快速输入内容并且穿插多按几次 tab,你就能被 ble.sh 的 bug 坑到;而且 ble.sh 的启动很慢。因此我只能忍受没有补全提示的 bash —— windows 上还是这样将就着用吧。

fish

一般来说三大 shell 指的是 bash, fish, zsh。而 fish 不兼容 bash,语法自成一系,在 shell 中算是比较特立独行的。fish 使用 rust 重写过一次,搭上了语言原神的顺风车,性能与安全性无需担忧。fish 是不兼容 windows 的,而在 msys2 里用 fish 又总感觉挺不爽的,我只好在 windows 上用其他 shell。

fish 的语法在我看来算是对传统 shell 的反叛,但是没有叛彻底,还保留了很大一部分 bash 特点,导致 fish 写脚本也十分难写,文档也垃圾,作为一门脚本语言来说 fish 是失败的。

但我还是离不开 fish,唯一原因是 补全太好用了,爆杀一切其他 shell。fishshell 可以自动检测 path,甚至会自动从 man 生成补全 (ref),一旦用过就再也离不开了。我一般开启 bind \t forward-word,配置文件只此一行足矣(加载其他软件的命令和 alias 不算),fish 的默认配置已经足够好用,没有必要再去搞什么 oh-my-fish。

zsh

zsh 是 bash 统治下的顺从者,其几乎全兼容 bash。zsh 是 macos 的 default shell,因此用户也非常多。

我曾经尝鲜过一段时间 zsh(入坑作:external 2.),但是补全实在是太垃圾,立刻扔掉了。

经常会有人推荐 Oh My Zsh,但是这玩意有严重的性能问题(ref),已经在群里问过 N 次了。新人不如尝试一下 zinit。

nushell

nushell 可以说是彻底的反叛者,它自己搓了一套偏函数式的 nu 语言,并重载了许多 posix 指令(以便更好地展示执行结果)。nushell 也使用 rust 实现,性能与安全性无需担忧。nushell 是跨平台的,因此成为我在 windows 上的一个选择。

自己搓语言的基本上都有很高的学习成本,nushell 也不例外。nu 语言有对 rust 的借鉴和反叛。

不过 nushell 最劝退我的还是 rust 的一个 bug,导致其无法在我的 RAMDisk 上工作。 后来更新后支持了。

其他缺点详见 fuckxxx。

主要特性

shell 配置

nushell 只有 winget 安装方法(winget install nushell),没有 scoop 安装。

安装好后,在 nushell 中执行下面的语句:

nushell
config env --default | save ($nu.default-config-dir | path join 'env.nu')
config nu --default | save ($nu.default-config-dir | path join 'config.nu')

即可在配置文件夹生成默认配置。然后就是编辑配置即可,官方建议单独开一个 custom.nu 写自己的配置,然后 source 到主配置(config.nu)中。

nushell
source ($nu.default-config-dir | path join 'custom.nu')

在 windows 上使用,还可以用 ContextMenuManager 给目录添加一个右键菜单,更加方便地打开 nushell。

类型系统

nushell 的类型系统可以说是尚未起步的。没有联合类型算什么 type system。

其他经验

powershell

一般的 windows 都自带 powershell 1.0。但是有的命令在老版本 powershell 上会执行失败,可以用 scoop install pwsh 安装最新版本的 powershell。

powershell 非常邪恶,详情请看 fuckxxx#powershell

xonsh

我一看到 xonsh 就把它加到了我的 👍 list 里。它不自创脚本语言,而是使用 python 作为其解释器。在 python 爆火的当下,xonsh 可能是一个不错的选择,它完全避开了高昂的学习成本和 bash 脚本的难用,还能借 python 优秀的跨平台能力为所欲为。

虽然我还没开始用 xonsh,不过将来我一定会去试一试的。

amber

amber 是总论提到的编译到 bash 语言的一个高阶语言;它使用 rust 实现,并且有较为完善的文档和 tutorial。我也为这个项目发过 PR,不过是依赖相关,跟代码逻辑没什么关系。

这个项目的代码我只能说真是一坨屎山。在用几乎最新的 rust 和 cargo 情况下,没有修 clippy issue 也就算了,连 rustfmt 都没过就有点过分了吧。。。屎山也就算了,我跑 cargo test 也跑不了,正常使用也用不了,这什么垃圾玩意。。

Makefile

谁说 Makefile 就不是一种 shell script 了?

一般把 Makefile 理解成一堆 bash 函数即可。然后 make 命令行提供了函数间依赖关系,和单独执行某一个函数的功能,还有杂七杂八基本用不到的功能。反正只要把 Makefile 理解成 bash 执行器即可。

杂

external

  1. bash 脚本教程
  2. Linux Zsh 使用 oh-my-zsh 打造高效便捷的 shell 环境
  3. Why doesn't set -e (or set -o errexit, or trap ERR) do what I expected?
  4. Online book: Effective Shell (about bash)

  1. 尝试写个大脚本,未果,几欲去世。数组做输入值和返回值各种妖魔鬼怪乱飞 ("${arr[@]}")。我的评价是还是写点阳间语言吧,就算是 fish 都比 bash 好看多了。python 也很泛用的,而且比起 lua 更好写。 ↩︎

  2. scoop Main 的一次更新把 bash.exe 从 shims 里去掉了并且说了不会加上,所以要么用 sh 代替 bash,要么把 C:\Users\<username>\scoop\apps\git\current\bin 也加入 PATH。 ↩︎