[译]macOS Bash升级

作者: 爱柚子的陈同学 | 来源:发表于2019-01-21 01:01 被阅读2次

许多macOS用户不知道自己使用的是过时已久的Bash shell版本。强烈建议升级到最新版本。

macOS默认Bash版本

执行以下命令,查看macOS的Bash版本是否过时:

$ bash --version
 GNU bash,版本3.2.57(1)-release(x86_64-apple-darwin18)
版权所有(C)2007 Free Software Foundation,Inc。

正如所见,这是GNU Bash 3.2版本,可以追溯到2007年!这个版本的Bash内置在所有版本的macOS,即使是最新版本。

Apple在其操作系统中内置如此旧版本的Bash的原因与许可协议有关。从4.0版本(3.2的后续版本)开始,Bash使用了GNU通用公共许可证v3(GPLv3),但Apple并不(想要)支持。你可以在这里找到一些相关讨论。GNU Bash3.2版本是Apple可接受的许可协议的最后一个版本,因此始终内置该版本。
这意味着整个世界(例如Linux)都会使用新版本Bash,而macOS用户却使用十年前的旧版本。在撰写本文时,GNU Bash的最新版本是5.0(见此处),已于2019年1月发布。在本文中,我将说明如何将系统默认shell升级到最新版本的Bash。

为什么升级?

如果Bash 3.2可以正常使用,为什么还要升级更新的版本呢?对我个人而言,主要原因是自动参数补全。该功能支持Bash特定命令的自动参数补全。您可以输入部分内容,然后按Tab键,自动补全命令,文件名或变量。(或者当有多个可选项时,双击Tab键来获取可补全信息的列表)。这是Bash的默认内置补全功能。

不仅于此,它还支持依赖上下文场景判断的命令补全。例如输入 cmd -[tab][tab] ,然后查看适合该命令的所有选项列表。或者输入 cmd host rm [tab][tab] 然后查看相关配置文件中指定的所有“host”的列表。

可编程完成逻辑(由命令的创建者)在完成规范中定义,通常以完成脚本的形式。必须在shell中提供这些完成脚本以启用命令的完成功能。

自动参数补全逻辑(由命令的开发者)在自动完成规范中定义,一般称为 completion scripts 。必须在shell中提供这些源文件才能生效。

问题是Bash的自动命令补全功能自版本3.2以来已经被广泛应用,大多数命令都支持这个新功能。但在Bash 3.2上无法使用,如果继续使用默认的 macOS shell ,则会错过许多命令的补全功能。

通过升级到更新版本的Bash,您就可以使用这些非常有用的自动补全脚本。我写了一篇文章,名为 Programmable Completion for Bash on macOS ,它解释了在升级到更新的Bash版本后,充分利用macOS上的自动命令补全功能所需的全部内容。

如何升级?

升级macOS的默认shell到最新版本Bash,需要做三件事:

  1. 安装最新版本Bash
  2. 设置“白名单”,将新Bash作为登录shell
  3. 设置新Bash为默认shell

每个步骤都非常简单。

注意:以下步骤并未更改旧版Bash,而是安装新版并将其设置为默认。两个版本将并存,只是我们忽略旧版。

安装

推荐使用 Homebrew:

brew install bash

验证安装结果, 检查系统中并存的2个版本:

$ which -a bash
/usr/local/bin/bash
/bin/bash

第一个是新版,第二个是旧版:

$ /usr/local/bin/bash --version
GNU bash, version 5.0.0(1)-release (x86_64-apple-darwin18.2.0)
Copyright (C) 2019 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software; you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.

$ /bin/bash --version
GNU bash, version 3.2.57(1)-release (x86_64-apple-darwin18)
Copyright (C) 2007 Free Software Foundation, Inc.

PATH变量中,新版本(/usr/local/bin)的目录优先于旧版本(/bin),所以现在再检测Bash版本时就显示已是新版:

$ bash --version
 GNU bash,版本5.0.0(1)-release(x86_64-apple-darwin18.2.0)
...

现在已经设置好了默认新版。

设置白名单

UNIX包含一个安全功能,该功能将可用作登录shell的shell(即登录到系统后使用的shell)限制为“受信任”shell列表。这些shell列在/etc/shells文件。

要将新安装的 Bash shell 设置成默认shell,它必须能够作为登录shell。将其添加到/etc/shells文件。以root用户身份编辑此文件:

$ sudo vim /etc/shells

添加/usr/local/bin/bashshell,如下:

/bin/bash
/bin/csh
/bin/ksh
/bin/sh
/bin/tcsh
/bin/zsh
/usr/local/bin/bash

设置默认Shell

现在如果打开一个新终端窗口,仍然会使用Bash 3.2。这是因为/bin/bash仍然是默认shell。修改成新shell,执行以下命令:

$ chsh -s /usr/local/bin/bash

现在默认shell已设置为新版本Bash。关闭重启终端窗口,启用新版本。继续验证:

$ echo $BASH_VERSION
5.0.0(1)-release

chsh命令仅修改当前用户的默认shell。如果想修改root用户,执行以下操作:

$ sudo chsh -s /usr/local/bin/bash

这样当使用 sudo su ,以root用户身份打开shell时,也将使用新版Bash。

注意事项

脚本中的用法

如上所述,我们没有修改Bash的默认版本,而是安装了新版并将其设置为默认。Bash的两个版本并存:

  • /bin/bash:旧版
  • /usr/local/bin/bash:新版

在shell脚本中,我们经常在开头写一行Shebang,如下:

#!/bin/bash
echo $BASH_VERSION

注意,这一行Shebang明确指定了旧版本Bash。运行时就会调用旧版本的Bash执行(脚本输出显示,例如3.2.57(1)-release)。

大多数情况下,这可能没问题。如果想明确使用新版本Bash,修改shebang如下:

#!/usr/local/bin/bash
echo $BASH_VERSION

现在输出类似5.0.0(1)-release。但要注意,该方案不可移植,可能无法在其他系统上运行。因为其他系统可能没有位于/usr/local/bin/bash的shell(而/bin/bash基本是标准)。

要两全其美,修改shebang如下:

#!/usr/bin/env bash
echo $BASH_VERSION

这是shebang的推荐格式。原理是检查PATH并使用第一个找到的bash可执行文件作为脚本的解释器。如果新版的目录先于旧版(是默认版本),则将使用新版,并且脚本的输出类似5.0.0(1)-release

为什么不使用Symlink符号链接?

与其并存两个版本的Bash,为什么不能彻底删除旧版,替换成新版?例如:

$ sudo rm /bin/bash
$ sudo ln /usr/local/bin/bash /bin/bash

这样即使是Shebang标记成#!/bin/bash的脚本,也会被新版Bash执行,Why not?

当然可以,但是必须绕过macOS的安全设置系统完整性保护(SIP)维基百科)。该功能禁止对特定文件夹进行写操作,即使是root用户也不行(所以也称“rootless”)。这些文件夹列在这里,其中就包括了/bin

解决方案是禁用SIP,修改/bin,再启用SIP。启用和禁用SIP的方法在此。启动计算机到Recovery模式,然后使用 csrutil disablecsrutil enable 命令。

至于是彻底使用新版替换旧版,还是并存2个版本,自行判断吧。

参考:https://apple.stackexchange.com/a/292760

Q:系统终端窗口没有切换成新版Bash?
A:两种可能:

  1. 杀终端进程并重启。
  2. 系统终端窗口菜单栏,“偏好设置”>“通用”>“Shell的打开方式”,确保选中“默认登录shell”。如果选中其他选项并设置为/bin/bash,就会强制使用旧版。

原文:https://itnext.io/upgrading-bash-on-macos-7138bd1066ba

相关文章

网友评论

    本文标题:[译]macOS Bash升级

    本文链接:https://www.haomeiwen.com/subject/ydkqjqtx.html