为无前缀g的命令及手册页设置别名的最优方案探讨
Homebrew通常建议,安装grep、sed这类软件包后,若想使用无前缀g的命令(比如直接用grep而非ggrep),需要把/usr/local/opt/[command]/libexec/gnubin加到$PATH的最前面。但我只想给grep、sed、xargs、find这4个GNU工具设置无前缀命令,又不想让$PATH变得过长。
于是我在shell的rc文件里写了一段逻辑,直接在$HOMEBREW_PREFIX目录下给g[command]创建无前缀的软链接;手册页方面,为了输入man grep就能查看GNU grep的手册(不用输man ggrep),我还在/usr/local/share/man/man1目录下给g[command].1创建了对应无前缀的软链接,具体代码如下:
for cmd in ggrep gsed gxargs gfind; do cmd_path=${brew_bin}/${cmd} # 去掉开头的g new_cmd=${cmd#g} new_cmd_path=${brew_bin}/${new_cmd} if [[ -L $cmd_path ]]; then if [[ ! -e $new_cmd_path ]]; then ln -s $cmd_path $new_cmd_path fi fi # 如果以后用到非g前缀的GNU工具,或者不在man1章节的工具,这段逻辑得改 man_dir='/usr/local/share/man/man1' if [ -d $man_dir ]; then old_man_filename="${cmd}.1" new_man_filename="${new_cmd}.1" pushd $man_dir >/dev/null if [ -e $old_man_filename ] && [ ! -e $new_man_filename ]; then echo "Linking $new_man_filename to $old_man_filename" ln -s $old_man_filename $new_man_filename fi popd >/dev/null fi done
现在我有几个疑问:
- 这种方法是不是最优解?
- 目前的方式有点繁琐,而且我不想把自己建的软链接和Homebrew的文件混在一起,有没有更优雅、通用的方案?
- 另外这个方法不适用于
curl,因为它的目录规则和grep、sed这类不一样。
(注:暂不讨论把GNU工具置于系统工具之前的合理性,相关风险我已知晓,还曾向Apple提交过bug,建议脚本里指定/usr/bin/[命令]而非仅命令名)
1. 用独立目录隔离自定义软链接
不要直接在Homebrew的bin目录下创建软链接,而是自建一个专属目录(比如~/.local/gnu/bin)存放无前缀命令的软链接,同时建对应的手册页目录~/.local/gnu/man/man1。这样既避免和Homebrew的文件混叠,也只需要给$PATH添加这一个目录,不会导致路径臃肿。
具体实现代码:
# 创建自定义目录(不存在则新建) mkdir -p ~/.local/gnu/bin ~/.local/gnu/man/man1 # 定义路径变量 gnu_bin="$HOME/.local/gnu/bin" gnu_man="$HOME/.local/gnu/man/man1" brew_bin="$(brew --prefix)/bin" brew_man_dir="$(brew --prefix)/share/man/man1" # 处理带g前缀的GNU工具 for cmd in ggrep gsed gxargs gfind; do cmd_path="${brew_bin}/${cmd}" new_cmd="${cmd#g}" new_cmd_path="${gnu_bin}/${new_cmd}" # 创建命令软链接 if [[ -L "$cmd_path" && ! -e "$new_cmd_path" ]]; then ln -s "$cmd_path" "$new_cmd_path" fi # 创建手册页软链接 old_man="${brew_man_dir}/${cmd}.1" new_man="${gnu_man}/${new_cmd}.1" if [[ -e "$old_man" && ! -e "$new_man" ]]; then ln -s "$old_man" "$new_man" fi done # 将自定义目录加入PATH和MANPATH export PATH="$gnu_bin:$PATH" export MANPATH="$gnu_man:$MANPATH"
2. 适配curl这类特殊工具
Homebrew中GNU版本的curl是curl而非gcurl,它的命令和手册页都在/usr/local/opt/curl目录下。可以直接在自定义目录中为它创建软链接,统一管理逻辑:
# 为curl创建软链接 ln -s "$(brew --prefix)/opt/curl/bin/curl" "$gnu_bin/curl" ln -s "$(brew --prefix)/opt/curl/share/man/man1/curl.1" "$gnu_man/curl.1"
3. 可扩展的通用化优化
如果后续需要添加更多GNU工具,可以把工具列表单独定义,方便扩展维护:
# 带g前缀的工具列表 g_prefix_tools=(ggrep gsed gxargs gfind) # 特殊工具列表(非g前缀) special_tools=(curl) # 处理带g前缀的工具 for cmd in "${g_prefix_tools[@]}"; do # 重复之前的命令和手册页软链接逻辑 done # 处理特殊工具 for cmd in "${special_tools[@]}"; do cmd_path="$(brew --prefix)/opt/${cmd}/bin/${cmd}" new_cmd_path="${gnu_bin}/${cmd}" if [[ -e "$cmd_path" && ! -e "$new_cmd_path" ]]; then ln -s "$cmd_path" "$new_cmd_path" fi old_man="$(brew --prefix)/opt/${cmd}/share/man/man1/${cmd}.1" new_man="${gnu_man}/${cmd}.1" if [[ -e "$old_man" && ! -e "$new_man" ]]; then ln -s "$old_man" "$new_man" fi done
内容的提问来源于stack exchange,提问作者Steve Shulman-Laniel

