Shell编程实例——bash入门

1、为什么是bash

为什么本书要介绍 bash,而不是别的 shell ?因为 bash无处不在。它未必是最时髦的,可以说也不是最炫或最厉害的(就算不是,也差不多了)​,更不是唯一一个作为开源软件发布的 shell,但 bash 的大名尽人皆知。

究其原因,和历史发展有关。第一批 shell 算得上相当不错的编程工具,但不便于日常使用。C shell 中加入了大量的用户便利功能(例如,可以重复用户输入过的命令)​,但作为编程语言,它又太诡异了。接下来的 ksh(20 世纪80 年代初期)也没少为用户提供方便,同时还改善了编程语言,看上去已经走在了被广泛接纳的康庄大道上。但ksh 并非开源软件,作为一款专有软件,它很难被纳入 Linux 这种自由操作系统。​(ksh 在 2000 年修改了其许可证,后来又在 2005 年再次改动。​)

到了 20 世纪 80 年代后期,Unix 社区认为标准化是一种不错的做法,同时成立了 POSIX 工作组(由 IEEE 负责组织)​。POSIX 实现了 Unix 库和实用工具的标准化,其中也包括 shell。标准 shell 主要基于 1988 年版的 ksh,另外还包括部分 C shell 特性以及一些用于弥补不足的新功能。GNU 项目旨在创建一款彻头彻尾的 POSIX 系统,这个系统自然需要一个 POSIX shell,bash 最初正是该项目的一部分。

bash 提供了 shell 程序员所需要的编程特性和命令行用户喜爱的各种便利。它一开始打算作为 ksh 的替代品,但随着自由软件运动变得愈发重要,Linux 越来越流行,bash的风头很快就盖过了 ksh。

bash 也因此成了我们已知的所有 Linux 发行版以及macOS(包括早期的 OS X 版本)的默认 shell(Linux 发行版的数量有数百种之多,可能会有一些没有默认使用bash)​。包括 BSD Unix 和 Solaris 在内的其他 Unix 操作系统也可以使用 bash。如果碰到操作系统中没有 bash 的罕见情况,安装起来也很容易。通过 Cygwin 以及新的Linux 子系统(Ubuntu)​,bash 甚至可用于 Windows。bash 既是一门强大的编程语言,也是一种优秀的用户界面。它让你在获得复杂编程特性的同时,能够保持键盘输入的便捷性。

学习 bash 准没错。最常见的默认 shell 就是古老的Bourne shell 和 bash,后者基本上兼容前者。任何现代的主流 Unix 或类 Unix 操作系统肯定安装了其一。但正如前面所说,万一没有的话,你也可以自己动手安装。当然,还有其他种类的 shell。秉承自由软件的精神,所有shell 的创建者及维护人员都彼此分享观点。要是读过bash 的变动日志,你就会发现很多地方提到,为了符合其他 shell 的行为而引入或调整了某项特性。不过多数用户并不在意。有什么功能,他们就用什么功能,并乐在其中。要是感兴趣,你可以研究一下其他 shell。不错的选择还有很多,也许你会找到更喜欢的,尽管可能不如bash 这样普及。

2、bash shell

bash 是一种 shell,也就是命令解释器。bash(或者说任何 shell)的主要目的是让用户可以同计算机操作系统交互,以便完成想做的任务。这通常涉及运行程序,因此shell 会接受你输入的命令,判断要用到的程序,然后执行命令来启动程序。你还会碰到一些需要执行一系列操作的任务,这些操作要么是重复性的,要么非常复杂。shell编程(通常称为 shell 脚本编程)允许你对此类任务进行自动化,以实现易用性、可靠性以及可重现性。

如果你刚接触 bash,我们在本书开始部分为你准备了一些基础知识。如果你一直在使用 Unix 或 Linux,大概对bash 也不会陌生,不过也许你还不知道自己用的就是 它。bash 其实就是一种用于执行命令的语言,你输入的命令(如 ls、cd、grep、cat)从某种意义上来说就是bash 命令。这些命令有些是 bash 内建的,有些是独立的程序。就目前而言,这种差异并不重要。

接下来我们介绍 bash 的几个上手实例。多数系统预装了bash,只有少数没有。即便是系统自带 bash,也应该知道如何获取及安装 bash,每次新版本的发布都会带来新的特性。

3、提示符揭秘

所有的命令行 shell 都采用某种形式的提示符来告诉用户shell 已经准备好接受输入了。提示符的具体形式取决于很多因素,其中包括操作系统的类型和版本、shell 的类型和版本、发行版以及其他人所做的配置。在 Bourne 系列的 shell 中,提示符结尾的 $ 通常表明你是以普通用户身份登录的,而结尾的 # 表明你是 root。root 账户是系统的管理员,等同于 Windows 系统中的 System 账户(该账户的权限比 Administrator 还要高)​。在典型的 Unix或 Linux 系统中,root 无所不能,可以执行任何操作。

默认提示符经常还会显示你当前所处的目录路径,不过多是缩写形式,~表示所在的是主目录。有些默认提示符也会加上用户名和你所登录的主机名。要是还不清楚,当你同时用不同的用户名登入 5 台主机时,就会明白了。

下面是一个典型的 Linux 命令行提示符,它表明用户 jp 所登录的主机名为 adams,当前位于用户主目录中。结尾的$ 说明 jp 是一个普通用户,并非 root:

jp@adams:~$

在有些 Unix 或 Linux 系统中,可以使用 su 和 sudo 命令分享 root 的权限。如果系统中运行了某种强制性访问控制(mandatory access control,MAC)系统,如 NSA的 SELinux,root 甚至有可能不再是全能的了。

4、显示当前位置

使用内建命令 pwd,或设置一个更有帮助的提示符​。例如:

bash-4.3$ pwd
/tmp

bash-4.3$ export PS1='[\u@\h \w]$ '
[jp@solaris8 /tmp]$

pwd 是 print working directory(打印工作目录)的缩写,该命令接受两个选项。-L 显示当前的逻辑路径,这也是默认选项。-P 显示当前的物理路径,如果跟随符号链接,结果可能和逻辑路径不同。与此类似,cd 命令也提供了 -P 和 -L 选项:

bash-4.3$ pwd
/tmp/dir2

bash-4.3$ pwd -L
/tmp/dir2

bash-4.3$ pwd -P
/tmp/dir1

5、查找并运行命令

可以试试 type、which、apropos、locate、slocate、find 和 ls 命令。

bash 会在环境变量 PATH 中保留一个用于查找命令的目录列表。内建命令 type 会在环境(包括别名、关键字、函数、内建命令、$PATH 中的目录以及命令散列表)中搜索匹配其参数的可执行文件并显示匹配结果的类型和位置。该命令有多个选项,其中值得注意的是 -a,它会打印出所有的匹配结果,而不是只找出第一个匹配。which 命令与type 类似,但它只搜索 $PATH(以及 csh 别名)​。在不同的系统中,which 的形式各异(通常在 BSD 中是一个csh 脚本,但在 Linux 中是一个二进制文件)​,不过一般有 -a 选项。如果已知命令名,想知道其确切位置或想看看其是否存在于系统中,可以借助这两个命令。例如:

$ type which
which is hashed (/usr/bin/which)

$ type ls
ls is aliased to `ls -F -h'

$ type -a ls
ls is aliased to `ls -F -h'
ls is /bin/ls

$ which which
/usr/bin/which

几乎所有的命令都自带某种形式的用法帮助。通常采用的是称为手册页(manpage)的在线文档,其中 man 是manual(手册)的简写。可以使用 man 命令访问这些手册页,man ls 会显示 ls 命令的相关文档。很多程序还有内建的帮助机制,通过 -h 或 --help 这样的“帮助”选项就能使用。尤其是在其他操作系统中的一些程序,如果不提供命令参数,就会直接显示帮助信息。部分 Unix 命令也会这么做,不过大多数没有这种功能。这是因为 Unix命令还要组合起来形成管道,后面我们会讲到。但如果你不知道或忘记了命令名,该怎么办呢?apropos 命令可以根据所提供的正则表达式参数搜索手册页名称及描述。在 你忘记所需要的命令名时,该命令尤其管用。它和 man -k 的效果一样:

$ apropos music
cms (4) - Creative Music System device driver

$ man -k music
cms (4) - Creative Music System device driver

locate 和 slocate 通过查询系统数据库文件(通常由调度程序 cron 运行的作业负责编译和更新)来查找文件或命令,几乎立刻就能得到结果。实际数据库文件的位置、索引内容、检查频率都因系统而异。具体细节可以查阅系统的手册页。slocate(secure locate)存储了权限信息(除文件名和路径之外)​,以免列出用户没有权限访问的程序。在多数 Linux 系统中,locate 是指向 slocate 的符号链接;在其他系统中,两者可能是不同的程序,也可能根本就没有 slocate。以下就是一个示例:

$ locate apropos
/usr/bin/apropos
/usr/share/man/de/man1/apropos.1.gz
/usr/share/man/es/man1/apropos.1.gz
/usr/share/man/it/man1/apropos.1.gz
/usr/share/man/ja/man1/apropos.1.gz
/usr/share/man/man1/apropos.1.gz

6、获取文件的相关信息

使用 ls、stat、file 或 find 命令:

$ touch /tmp/sample_file

$ ls /tmp/sample_file
/tmp/sample_file

$ ls -l /tmp/sample_file
-rw-r--r-- 1 jp         jp            0 Dec 18 15:03 /tmp/sample_file
$ stat /tmp/sample_file
File: "/tmp/sample_file"
Size: 0           Blocks: 0        IO Block: 4096   Regular File
Device: 303h/771d Inode:  2310201    Links: 1
Access: (0644/-rw-r--r--) Uid: (  501/      jp)   Gid: ( 501/        jp)
Access: Sun Dec 18 15:03:35 2005
Modify: Sun Dec 18 15:03:35 2005
Change: Sun Dec 18 15:03:42 2005

$ file /tmp/sample_file
/tmp/sample_file: empty

$ file -b /tmp/sample_file
empty

$ echo '#!/bin/bash -' > /tmp/sample_file

$ file /tmp/sample_file
/tmp/sample_file: Bourne-Again shell script text executable

$ file -b /tmp/sample_file
Bourne-Again shell script text executable

ls 命令只显示文件名,-l 选项可以提供每个文件更详细的信息。ls 的选项很多,可以查询手册页了解其所支持的选项,其中有用的选项包括以下几个。

  • -a:不隐藏以 .(点号)开头的文件。
  • -A:和 -a 相似,但不显示两个常见的目录 . 和 …,因为每个目录中都有这两项。
  • -F:文件名结尾以下列类型标识符之一显示文件类型。
    • 斜线(/)表示该文件是目录
    • 星号(*)表示该文件是可执行文件
    • 等号(=)表示套接字
    • 竖线(|)表示 FIFO(first in, first out)缓冲
  • -l:使用长列表格式。
  • -L:显示链接目标文件的信息,而非符号链接本身。
  • -Q:引用名(quote name)​(GNU 扩展,仅部分系统支持)​。
  • -r:逆序排列。
  • -R:递归显示子目录。
  • -S:按照文件大小排序。
  • -1:使用短格式,每行只显示一个文件。

stat、file 和 find 命令都拥有众多控制输出格式的选项,你可以查询手册页了解它们所支持的选项。例如,下列这些选项可以生成类似于 ls -l 的输出:

$ ls -l /tmp/sample_file
-rw-r--r--  1 jp         jp                14 Dec 18 15:04 /tmp/sample_file

$ stat -c'%A %h %U %G %s %y %n' /tmp/sample_file
-rw-r--r-- 1 jp jp 14 Sun Dec 18 15:04:12 2005 /tmp/sample_file

$ find /tmp/ -name sample_file -printf '%m %n %u %g %t %p'
644 1 jp jp Sun Dec 18 15:04:12 2005 /tmp/sample_file

注意,并非所有操作系统及其各版本都有这些工具。例如,Solaris 就默认不包含 stat。

另外值得指出的是,目录其实就是一种操作系统会特别处理的文件,因此本节展示的这些命令也完全能够应用于目录,只不过有时可能需要修改命令才能得到想要的结果。例如,可以用 ls -d 列出目录本身的信息(不加该选项的 ls列出的是目录的内容)​。

7、显示当前目录下的所有隐藏(点号)文件

你只想查看目录下的隐藏(点号)文件,然后编辑其中一个已经忘记名字的文件,或者删除一些废弃文件。ls -a 可以显示出包括隐藏文件在内的所有文件,但这种输出往往包含了过多干扰项,而 ls -a .* 的结果也比你想象或需要的更多。

使用 ls -d 配合筛选条件。例如:

ls -d .*
ls -d .b*
ls -d .[!.]*
ls -d .*/

因为每个正常的目录中都包含 . 和 …,所以就没必要再显示了。你可以用 ls -A 列出目录中除这两个文件外的其余所有文件。对于可以利用通配符(也就是模式)列出文件的命令,下面给出了能够将 . 和 … 排除在外的通配符写法:

$ grep -l 'PATH' ~/.[!.]*
/home/jp/.bash_history
/home/jp/.bash_profile
$

8、使用shell引用

将字符串放进单引号中,除非字符串中包含需要 shell 进行插值的元素。

shell 会对非引用文本以及双引号中的文本执行扩展和替换操作。思考以下示例:

$ echo A coffee is $5?!
A coffee is ?!

$ echo "A coffee is $5?!"
-bash: !": event not found

$ echo 'A coffee is $5?!'
A coffee is $5?!

第一个例子要对 $5 进行变量扩展,但因为该变量并不存在,所以扩展结果为空。第二个例子要遵循同样的规则,但我们没有看到任何命令输出,这是因为对 ! 进行历史替换时失败了,原因是其不匹配任何历史记录。第三个例子的结果符合我们的预期。

要想将 shell 扩展与字符串字面量混合在一起,可以利用shell 转义字符或修改引用方式。惊叹号是一种特殊情况,放在其之前的反斜线转义字符不会被删除。可以通过单引号或尾部空格解决这个问题,如下所示:

$ echo 'A coffee is $5 for' "$USER" '?!'
A coffee is $5 for jp ?!

$ echo "A coffee is \$5 for $USER?\!"
A coffee is $5 for jp?\!

$ echo "A coffee is \$5 for $USER?! "
A coffee is $5 for jp?!

另外,你无法在一对单引号中再嵌入另一个单引号,使用反斜线也不行,因为单引号内不会执行任何插值操作。解决方法有两种:使用双引号以及转义字符,或者在单引号对之外转义单引号。

# 我们会得到一个示意继续输入的提示符,因为目前的引号并不对称
$ echo '$USER won't pay $5 for coffee.'
> ^C

# 错误
$ echo "$USER won't pay $5 for coffee."
jp won't pay for coffee.

# 有效
$ echo "$USER won't pay \$5 for coffee."
jp won't pay $5 for coffee.

# 同样有效
$ echo 'I won'\''t pay $5 for coffee.'
I won't pay $5 for coffee.

9、使用或替换内建命令与外部命令

你想用自己编写的函数或外部命令替换内建命令,还想知道脚本究竟执行的是哪种命令(例如,是 /bin/echo 还是内建的 echo)​。又或者你创建了一个新命令,但可能和已有的外部或内建命令冲突。

用 type 和 which 命令查看指定命令是否存在,并确定其是内建命令还是外部命令:

$ type cd
cd is a shell builtin

$ type awk
awk is /usr/bin/awk

$ which cd
/usr/bin/which: no cd in (/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/ \
local/sbin:/usr/bin/X11:/usr/X11R6/bin:/root/bin)

$ which awk
/usr/bin/awk

顾名思义,内建命令就是内建在 shell 自身中的命令,外部命令则是由 shell 运行的外部文件。外部文件可以是二进制文件,也可以是 shell 脚本。理解内外部命令之间的差异很重要。首先,当你使用特定 shell 的某个版本时,内建命令总是可用的,但外部程序就未必已经安装在系统中了。其次,如果你自己的某个程序和内建命令同名,结果会让人很困惑,因为内建命令总是会优先执行(参见19.4 节)​。可以用 enable 命令来关闭或启用内建命令,不过强烈建议不要这么做,除非你有十足把握知道自己在做什么。enable -a 可以列出所有的内建命令及其当前状态(启用或禁用)​。

内建命令的问题在于你无法使用 -h 或 --help 选项获得使用帮助,即便有手册页,通常也只是简单地指向 bash 手册页而已。这时候就用得上内建命令 help 了。help 会显示 shell 内建命令的帮助信息。

help: help [-dms] [pattern ...]
    Display information about builtin commands.

    Displays brief summaries of builtin commands.  If PATTERN is
    specified, gives detailed help on all commands matching PATTERN,
    otherwise the list of help topics is printed.

    Options:
      -d        output short description for each topic
      -m        display usage in pseudo-manpage format
      -s        output only a short usage synopsis for each topic matching
     PATTERN

    Arguments:
      PATTERN   Pattern specifying a help topic

    Exit Status:
    Returns success unless PATTERN is not found or an invalid option is given.

需要重新定义某个内建命令时,可以用 builtin 命令来避免出现循环现象。例如,我们可以定义一个 shell 函数来改变 cd 命令的工作方式。

cd () {
    builtin cd "$@"
    echo "$OLDPWD --> $PWD"
}

要想避开优先级更高的函数或内建命令,而强制使用外部命令,可以利用 enable -n 关闭 shell 内建命令或用command 忽略 shell 函数。例如,输入 enable -n test,然后执行 test,此时运行的就不再是内建命令,而是$PATH 中的 test。也可以用 command ls 来执行原生的 ls命令,而非可能存在的自定义 ls 函数。

10、确定是否处于交互模式

你手边有一些代码,希望仅在处于(或不处于)交互模式时运行。

使用下例中的 case 语句。

#!/usr/bin/env bash
# 文件名: interactive

case "$-" in
    *i*) # 在交互式shell中运行的代码位于此处
     ;;
    *) # 在非交互式shell中运行的代码位于此处
     ;;
esac

变量 $- 中保存了一个字符串,其中列出了当前所有的shell 选项。如果 shell 处于交互模式,则其中会包含 i。

你也可以采用如下代码(同样有效,但更推荐使用例中的方法)​:

if [ -n "$PS1" ]; then
    echo This shell is interactive
else
    echo This shell is not interactive
fi

11、将bash安装为默认shell

你所使用的 BSD 系统、Solaris 或其他 Unix 变体并没有将bash 作为默认 shell,每次都需要手动启动 bash,你现在希望将 bash 设置为默认 shell。

先确定已经安装了 bash。在命令行中输入 bash --version。如果获得了版本输出,则说明 bash 已经安装好了:

$ bash --version
GNU bash, version 3.00.16(1)-release (i386-pc-solaris2.10)
Copyright (C) 2004 Free Software Foundation, Inc.
$

如果没有看到版本号,可能是系统路径中缺少了相应的目录。在一些系统中,chsh -l 或 cat /etc/shells 可以给出一份可用的 shell 清单。否则,可以询问系统管理员 bash 的安装位置,或者是否可以安装 bash。

在 Linux 系统中,chsh -l 会提供一份可用的 shell 清单;而在 BSD 中,会打开编辑器并允许修改设置。在 macOS中,-l 并非 chsh 的有效选项,执行 chsh 会打开编辑器并允许修改设置,chpass -s shell 可以修改用户所用的shell。

如果已经安装了 bash,可以用 chsh -s 命令修改默认shell,例如 chsh -s /bin/bash。如果修改失败,可以再试试 chsh、passwd -e、passwd -l、chpass 或者usermod -s /usr/bin/ bash。要是还不行,那就得咨询系统管理员了,可能需要管理员编辑 /etc/passwd 文件。在多数系统中,/etc/passwd 包含如下内容:

cam:pK1Z9BCJbzCrBNrkjRUdUiTtFOh/:501:100:Cameron Newham:/home/cam:/bin/bash
cc:kfDKDjfkeDJKJySFgJFWErrElpe/:502:100:Cheshire Cat:/home/cc:/bin/bash

作为 root,你可以编辑密码文件每行的最后一个字段,将其修改成想要选用的 shell 的完整路径。如果系统中有vipw 命令,则应该使用该命令,确保密码文件的一致性。

有些系统不允许将未出现在 /etc/shells 中的shell 作为登录 shell。如果 bash 不在该文件中,那就只能让系统管理员将其添加进去了。

有些操作系统(尤其是各种 BSD Unix)通常会将 bash 放在 /usr 分区。在这种系统中更改 root shell 时可得三思。如果系统出现引导故障,而你又需要在 /usr 分区挂载前进行处理,那就碰上真正的麻烦了:root 账户没有 shell 可用。因此,最好不要改动 root 账户的默认 shell。至于普通用户的默认 shell,完全可以改成 bash。除非绝对必要,否则使用 root 账户不是什么好做法,这一点不用说你也明白。尽可能使用普通账户。配合 sudo 这类命令,你应该极少会用到 root shell。

如果上面提到的这些方法都无效,还可以使用 exec 将当前的登录 shell 替换成 bash,但胆小的用户还是别这么做了。具体参见 bash FAQ 中的“A7) How can I make bashmy login shell?”一节。

12、持续更新bash

如何让 bash 保持最新状态取决于一开始获取 bash 的方式。理想情况下,bash 通常是作为系统的一部分,随着系统一块更新。如果你用的是已经不被支持的古董系统,可就未必如此了。要是你使用了打包系统,并且原始仓库仍有人维护,那么应该可以从仓库[如 EPEL(ExtraPackages for Enterprise Linux)或 PPA(UbuntuPersonal Package Archive)]中获取更新。

如果是通过源代码安装的,那就只能由你负责更新源代码并重新构建了。

13、获取Linux版的bash

你想要获取 Linux 系统下的 bash,或确认已安装的 bash是否为最新版。

几乎所有的现代 Linux 发行版都包含了 bash。可以用发行版自带的打包工具来确认安装的是否为最新版。要想升级或安装应用程序,你必须是 root 身份、使用 sudo,或知道 root 密码。

有些 Linux 发行版(尤其是 Debian 家族)用 DebianAlmquist shell 或 dash 作为 /bin/sh2,因为这两种 shell更为小巧,而且运行速度比 bash 更快。对于那些假定/bin/sh 指向 bash 的脚本,这种切换会造成很严重的混乱,因为凡是用到 bash 特性的地方全都会失效。

对于 Debian 及其衍生出的系统(如 Ubuntu 和 LinuxMint)​,可以使用图形用户界面工具或命令行工具(如apt-get、aptitude、apt)来确定 bash 的安装情况:

apt-get update && apt-get install bash bash-completion bash-doc
对于包括 Fedora、Community OS(CentOS)​、RedHat Enterprise Linux(RHEL)在内的 Red Hat 发行版,可以使用图形用户界面的 Add/Remove Application 工具。如果只有命令行,则可以使用下列命令:
yum update bash

对于 SUSE,可以使用 YaST 的图形用户界面或终端版本。你也可以使用命令行工具 rpm。

14、获取xBSD版的bash

你想要获取 FreeBSD、NetBSD、OpenBSD 系统下的bash,或者想要确认已安装的 bash 是否为最新版。

根据 Chet Ramey 所维护的 bash 页面:bash-4.3 已经包含在 FreeBSD ports collection、OpenBSD packages collection 以及 NetBSD packages collection 中。

要想知道是否已经安装 bash,可以检查 /etc/shells 文件。要想安装或升级 bash,可以使用 pkg_add 命令。如果你是 BSD 的老用户,可能更喜欢用 ports collection,但这里不打算涉及这方面的内容。

要是不确定特定 BSD 发行版中安装的是哪个版本的bash,可以到 DistroWatch 网站上搜索该发行版并查询相关的软件包表格。

对于 FreeBSD,使用如下命令:

pkg_add -vr bash

对于 NetBSD,浏览 Application Software for NetBSD,找到符合相应发行版本和架构的最新 bash 软件包,然后使用命令:

pkg_add -vu ftp://ftp.netbsd.org/pub/NetBSD/packages/pkgsrc-2005Q3/NetBSD-2.0/ \
i386/All/bash-3.0pl16nb3.tgz

对于 OpenBSD,可以使用 pkg_add -vr 命令。你可能需要将 FTP 路径调整为适应相应的发行版本和架构。另外,也许存在静态编译版本。例如:

pkg_add -vr ftp://ftp.openbsd.org/pub/OpenBSD/3.8/packages/i386/bash-3.0.16p1.tgz

FreeBSD 和 OpenBSD 将 bash 安装在/usr/local/bin/bash 中,而 NetBSD 将 bash 安装在/usr/pkg/bin/bash 中。

15、获取macOS版的bash

你想要获取 macOS 系统下的 bash,或确认已安装的bash 为最新版。

根据 Chet Ramey 所维护的 bash 页面:Mac OS X(现在称作 macOS)的当前版本(从Jaguar/Mac OS X 10.2 开始)使用 bash-3.2 作为/bin/sh。也可以在很多网站上找到 bash-4.3 的OS X 预编译包,但源代码包通常要更新一些。Darwin 版(MacOS X 的核心)的 bash 可以从MacPorts、Homebrew、Fink 处获得。

也可以从源代码构建更新版本的 bash,但仅推荐有经验的用户这么做(参见附录 E)​。

16、获取Unix版的bash

你想要获取 Unix 系统下的 bash,或确认已安装的 bash是否为最新版。

如果在系统或软件包仓库中都找不到,那么可以在 ChetRamey 所维护的 bash 页面下载二进制文件,或从源代码构建​。

17、获取Windows版的bash

你想要获取 Windows 系统下的 bash,或确认已安装的bash 是否为最新版。

使用 Cygwin 或 Windows 上的 Ubuntu,也可以使用虚拟机。又或者干脆不用 bash。

下载 Cygwin 并运行。按照提示选择要安装的包,bash 位于 shell 分类,默认是选中状态。安装好 Cygwin 后,你还得做一番配置。具体可参见用户手册。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值