macOS 使用 GNU 命令
macOS 的自带命令行工具是 BSD 版本的,要想在 Mac 上开发可以完美运行在 GNU/Linux 上的 Shell 脚本,就必须依赖 Linux 服务器,或者本地 Linux VM / Docker 去测试脚本,甚是麻烦。如果将命令行工具从 BSD 版本替换为 GNU 版本,把 Mac 当做 Linux 来用(不包括内核部分),将会意义非凡。本文将会介绍替换的原理与方法。
安装 GNU 工具
所需的 GNU 工具可通过 Homebrew
安装,常用工具的安装如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
$ brew install coreutils
$ brew install findutils
$ brew install gnu-sed
$ brew install gnu-indent
$ brew install gnu-tar
$ brew install gnu-which
$ brew install gnutls
$ brew install grep
$ brew install gzip
$ brew install screen
$ brew install watch
$ brew install wdiff --with-gettext
$ brew install wget
$ brew install less
$ brew install unzip
如需要搜索所有 GNU 工具列表,可以通过以下命令获得:
1
$ brew search gnu
覆盖系统自带命令
Homebrew
安装的命令工具默认放置在 /usr/local/opt/
,而系统自带 BSD 工具的路径为 /usr/bin/
。当安装的 GNU 命令与系统自带命令重复时,用前缀 g
可以指定使用 GNU 版本,如:
1
2
3
$ gsed # 使用 GNU 版本的 sed (gnu-sed)
$ sed # 使用 BSD 版的 sed
如果想省去 g
前缀,在环境变量 PATH
中把 GNU 工具的执行路径放置于 /usr/bin
之前即可(在安装命令工具的时候,输出日志就有指示)。原理是在系统扫描可执行路径时,会使用第一个符合条件的值:
1
export PATH="/usr/local/opt/<PACKAGE>/libexec/gnubin:$PATH"
上述 PACKAGE
为工具包名称。对应上文「安装 GNU 命令工具」里提及的工具,在文件 ~/.zshrc
(若使用 Bash
,则为 ~/.bash_profile
)添加以下指令以实现对系统默认工具的覆盖:
1
2
3
4
5
6
7
8
9
export PATH="/usr/local/opt/coreutils/libexec/gnubin:$PATH"
export PATH="/usr/local/opt/gnu-sed/libexec/gnubin:$PATH"
export PATH="/usr/local/opt/binutils/bin:$PATH"
export PATH="/usr/local/opt/ed/libexec/gnubin:$PATH"
export PATH="/usr/local/opt/findutils/libexec/gnubin:$PATH"
export PATH="/usr/local/opt/gnu-indent/libexec/gnubin:$PATH"
export PATH="/usr/local/opt/gnu-tar/libexec/gnubin:$PATH"
export PATH="/usr/local/opt/gnu-which/libexec/gnubin:$PATH"
export PATH="/usr/local/opt/grep/libexec/gnubin:$PATH"
刷新使其生效:
1
$ source ~/.zshrc
在 BSD 与 GNU 之间切换
如果你因为临时业务需求,或者觉得花大价钱买来的 Mac 不用太浪费,想换回 BSD 环境时,那么可以暂时屏蔽相关的 GNU 的执行路径:
1
# export PATH="/usr/local/opt/<PACKAGE>/libexec/gnubin:$PATH"
聪明的你也许发现了,上述例子要手动屏蔽的内容多达 9 行,而且之后恢复 GNU 还得一条条去掉注释符号 #
,是时候要想个办法偷懒了。可考考虑在 ~/.zshrc
(或 ~/.bash_profile
) 添加自定义函数进行切换:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
gnu_utils=(
PACKAGE
# the other utils ...
)
gnu() {
for _util in "${gnu_utils[@]}"; do
export PATH="/usr/local/opt/$_util/libexec/gnubin:$PATH"
done
[[ $1 == "--quiet" ]] || echo "Switched to GNU utils!"
}
bsd() {
for _util in "${gnu_utils[@]}"; do
export PATH="$(echo $PATH | sed "s/\/usr\/local\/opt\/$_util\/libexec\/gnubin://g")"
done
echo "Switched to BSD utils!"
}
gnu --quiet
添加完成后运行 exec zsh
或重启终端使函数生效。上述命令:gnu()
把 GNU 工具的执行路径插入环境变量 PATH
,而 bsd()
负责从 PATH
里面清除 GNU 的执行路径。因为需要在终端启动时默认使用 GNU,在上段代码结尾调用了 gnu
。
以后切换命令工具的版本时,在终端直接指定期望的工具名称即可:
切换到 GNU 工具:
1 2
$ gnu Switched to GNU utils!
切换到 BSD 工具:
1 2
$ bsd Switched to BSD utils!
现在,Mac 可以当作是换皮 Linux 来写脚本了,性价比再加一分。
Comments powered by Disqus.