Bash

title: 历史.
content: 由于理乍得·斯托曼对于之前一位开发者的进度不满,布莱恩·福克斯从1988年1月10日开始开发Bash。斯托曼和自由软件基金会希望到一个能够运行已有的shell脚本的自由软件。他们把这看作是建成一个基于BSD和GNU的完全自由的操作系统的战略的重要部分。这是他们自己注资的几个项目之一。福克斯作为自由软件基金会的雇员承担这项工作。1989年6月8日,福克斯发布Bash的beta版本,版本号为.99。在福克斯离开于1992年中期到1994年中期的某个时候离开自由软件基金会之前,他一直担任Bash的主要维护者。之后,他的工作被传递给另一个早期贡献者,切特·雷米(Chet Ramey)。  从那时起,在Linux用户当中sh在很大度上成为最流行的shell,并成为许多Linux发行版默认的交互式shell(不过Almquist shell可能是默认的脚本shell)。在苹果公司的 OS X 操作系统上也是如此。Bash 也被移植到 Microsoft Windows(通过Cygwin和MinGW)。通过DJGPP项目,Bash被移植到了DOS。通过许多终端模拟软件,Bash被移植到Novell NetWare和Android。微软在2016年的Build大会上宣布,Windows 10 添加一个Linux子系统,完全支持Bash和其他Ubuntu下的二进制程序。  2014年9月24日,Stephane Chazelas,一位工作于英国,致力于Unix/Linux和网络通信方面的专家,发现Bash的一个安全漏洞。这个漏洞被命名为Shellshock,并被分配编号 CVE-2014-6271、CVE-2014-6277、CVE-2014-7169。这个漏洞非常严重,因为使用Bash的CGI脚本会变得脆弱,使得攻击者可以执行任意的代码。这个漏洞与Bash通过环境变量把函数定义传递给shell子进程的方式有关。
title: 语法与特性.
content: bash的命令语法是Bourne shell命令语法的超集。数量庞大的Bourne shell脚本大多不经修改即可以在bash中执行,只有那些引用了Bourne特殊变量或使用了Bourne的内置命令的脚本才需要修改。bash的命令语法很多来自Korn shell(ksh)和C shell(csh),例如命令行编辑,命令历史,目录栈,$RANDOM和$PPID变量,以及POSIX的命令置换语法:$(...)。作为一个交互式的shell,按下TAB键即可自动补全已部分输入的程序名,文件名,变量名等等。  使用'function'关键字时,Bash的函数声明与Bourne/Korn/POSIX脚本不兼容(Korn shell 有同样的问题)。不过Bash也接受Bourne/Korn/POSIX的函数声明语法。因为许多不同,Bash脚本很少能在Bourne或Korn解释器中运行,除非编写脚本时刻意保持兼容性。然而,随着Linux的普及,这种方式正变得越来越少。不过在POSIX模式下,Bash更加符合POSIX。  bash的语法针对Bourne shell的不足做了很多扩展。其中的一些列举在这里。
title: 花括号扩展.
content: 花括号扩展是一个从C shell借鉴而来的特性,它产生一系列指定的字符串(按照原先从左到右的顺序)。这些字符串不需要是已经存在的文件。 $ echo a{p,c,d,b}e ape ace ade abe ad ae af bd be bf cd ce cf 花括号扩展不应该被用在可移植的shell脚本中,因为Bourne shell产生的结果不同。  echo a{p,c,d,b}e # a{p,c,d,b}e 当花括号扩展和通配符一起使用时,花括号扩展首先被解析,然后正常解析通配符。因此,可以用这种方法获得当前目录的一系列JPEG和PEG文件。 ls *.{jpg,jpeg,png} # 首先扩展为*.jpg *.jpeg *.png,然后解析通配符 echo *.{png,jp{e,}g} # echo显示扩展结果;花括号扩展可以嵌套。  除了列举备选项,还可以用“..”在花括号扩展中指定字符或数字范围。较新的Bash版本接受一个整数作为第三个参数,指定增量。 1 2 3 4 5 6 7 8 9 10 $ echo file{1..4}.txt file1.txt file2.txt file3.txt file4.txt a b c d e 1 4 7 10 a d g j 当花括号扩展和变量扩展一起使用时,变量扩展解析于花括号扩展之后。有时有必要使用内置的codice_1函数 $ start=1; end=10 $ echo {$start..$end} # 由于解析顺序,无法得到想要的结果 $ eval echo {$start..$end} # 首先进行变量扩展的解析 1 2 3 4 5 6 7 8 9 10
title: 使用整数.
content: 与Bourne shell不同的是bash不用另外生成进程即能进行整数运算。bash使用((...))命令和$[...]变量语法来达到这个目的: ((...))命令可以用于条件语句,因为它的退出状态是0或者非0(大多数情况下是1),可以用于是与非的条件判断: ((...))命令支持下列比较操作符:'==', '!=', '<nowiki»</nowiki>', '<nowiki>«/nowiki>', '<nowiki»=</nowiki>',和'<nowiki><=</nowiki>'。  bash不能在自身进程内进行浮点数运算。当前有这个能力的unix shell只有Korn shell和Z shell。
title: 输入输出重定向.
content: bash拥有传统Bourne shell缺乏的I/O重定向语法。bash可以同时重定向标准输出和标准错误,这需要使用下面的语法: 这比等价的Bourne shell语法"command > file 2>&1"来的简单。2.05b版本以后,bash可以用下列语法重定向标准输入至字符串(称为here string):  如果字符串包括空格就需要用引号包裹字符串。  例子: 重定向标准输出至文件,写数据,关闭文件,重置标准输出。  打开及关闭文件  抓取外部命令的输出
title: 进程内的正则表达式.
content: bash 3.0支持进程内的正则表达式,使用下面的语法: 正则表达式语法同regex(7) man page所描述的一致。正则表达式匹配字符串时上述命令的退出状态为0,不匹配为1。正则表达式中用圆括号括起的子表达式可以访问shell变量BASH_REMATCH,如下: 使用这个语法的性能要比生成一个新的进程来运行grep命令优越,因为正则表达式匹配在bash进程内完成。如果正则表达式或者字符串包括空格或者shell 关键字,(诸如'*'或者'?'),就需要用引号包裹。Bash 4 开始的版本已经不需要这么做了。
title: 转义字符.
content: $'string' 形式的字符串会被特殊处理。字符串会被展开成string,并像C语言那样将反斜杠及紧跟的字符进行替换。反斜杠转义序列的转换方式如下:  扩展后的结果将被单引号包裹,就好像美元符号一直就不存在一样。  双引号包裹的字符串前若有一个美元符号($"...")将会使得字符串被翻译成符合当前locale的语言。如果当前locale是C或者POSIX,美元符号会被忽略。如果字符串被翻译并替换,替换后的字符串仍被双引号包裹。
title: 关联数组.
content: Bash 4.0 开始支持关联数组,通过类似AWK的方式,对于多维数组提供了伪支持。 $ declare -A a # 声明一个名为a的伪二位数组 $ i=1; j=2 $ a[$i,$j]=5 # 将键 "$i,$j" 与值 5 对应
title: 移植性.
content: 调用Bash时指定 codice_2 或者在脚本中声明 codice_3,可以使得Bash几乎遵循 POSIX 1003.2 标准。若要保证一个Bash脚本的移植性,至少需要考虑到 Bourne shell,即Bash取代的shell。Bash有一些传统的 Bourne shell 所没有的特性,包括以下这些:
title: 键盘快捷键.
content: Bash默认使用Emacs的快捷键,可以通过 codice_5 让它使用Vi的快捷键
title: 进程管理.
content: Bash有两种执行命令的模式:批处理模式、并发模式。
title: 批处理模式.
content: 要以 批处理模式 执行命令(即按照顺序),必须用codice_6分隔,例子如下:  command1 ; command2  在这个例子中,当codice_7执行完毕,即执行codice_8。
title: 并发模式.
content: 使codice_7后台运行,则单独在结尾处使用codice_10,例子如下: command1 & 要并发执行两个命令,它们必须用codice_10分隔,例子如下:  command1 & command2  在这种情况下,codice_7 在后台执行(通过codice_10),从而立即将控制返回到shell,以执行codice_8。  通过 可以将当前进程挂起(放置后台并暂停运行),可通过 codice_15 命令恢复至前台,也通过codice_16将挂起的进程后台运行。
title: 查看进程状态.
content: 所有进程的情况,我们可以通过codice_17命令查看,包含正在后台运行和停止了的。 $ jobs [1]- Running command1 & [2]+ Stopped command2 上例的输出结果中,中括号包围的数字(如: "[1]" 和 "[2]" )为job的ID号。加号(+)用于指定codice_15和codice_16命令的默认对象job。减号( - )用于指定,若当前的默认对象job退出后,下一个默认对象job是谁。"Running" 和 "Stopped" 表示进程状态。 最后一个字段为命令。 总结:
title: 启动脚本.
content: bash启动的时候会运行各种不同的脚本。  当bash作为一个登录的交互shell被调用,或者作为非交互shell但带有--login参数被调用时,它首先读入并执行文件/etc/profile。然后它会依次寻找~/.bash_profile,~/.bash_login,和~/.profile,读入并执行第一个存在且可读的文件。--noprofile参数可以阻止bash启动时的这种行为。  当一个登录shell退出时,bash读取并执行~/.bash_logout文件,如果此文件存在。  当一个交互的非登录shell启动后,bash读取并执行~/.bashrc文件。这个行为可以用--norc参数阻止。--rcfile file参数强制bash读取并执行指定的file而不是默认的~/.bashrc。  如果用sh来调用bash,bash在启动后进入"posix"模式,它会尽可能模仿sh历史版本的启动行为,以便遵守POSIX标准。用sh名字调用的非交互shell不会去读取其他启动脚本,--rcfile参数无效。  当bash以POSIX模式启动时(例如带有--posix参数)它使用POSIX标准来读取启动文件。在此模式下,交互shells扩展变量ENV,从以此为文件名的文件中读取命令并执行。  bash会探测自己是不是被远程shell守护程序运行(通常是rshd)。如果是,它会读取并执行~/.bashrc中的命令。但是rshd一般不会用rc相关参数调用shell,也不会允许指定这些参数。
title: Bash与Bourne shell和csh启动脚本的比较.
content: Bash的特性是从Bourne shell和csh发展而来,因此一定程度上允许同Bourne shell的启动文件共享,并提供一些csh用户熟悉的启动特性。
title: 设置可继承的环境变量.
content: Bourne shell登陆时使用 codice_26 来设置环境变量,这些环境变量可以被子进程继承。Bash可以以兼容的方式使用codice_26,只需在Bash自有的脚本中显式执行下面这行代码。通过在codice_26 中避免使用Bash特有的语法,就可以和Bourne shell保持兼容性。. ~/.profile
title: 别名和函数.
content: 更通用的函数以及借鉴自csh的“别名(alias)”很大程度上取代了Bourne shell的别名(alias)和函数。然而这两个特性一般不能从登录式shell中继承,在该登录式shell的子shell中,它们必须被重新定义。尽管有个环境变量codice_29可以被用于这个问题,不过 csh 和 Bash 都可以用子shell的启动脚本直接处理。在Bash当中,codice_30 是交互式子shell启动时执行的脚本。如果想要在登录式shell中使用 codice_30 定义的函数,可以在 codice_32 的环境变量后面加上这样一行:. ~/.bashrc
title: 登录与登出时执行的命令.
content: 最初登录时,csh 执行 codice_33,可以执行一些只在登录时执行的操作,例如显示系统负载、硬盘状态、是否收到新邮件、在日志中记录登录时间,等等。Bourne shell 可以在 codice_26 文件中模拟这种行为,但并没有预先定义文件名。可以在 codice_35 文件的环境变量设置和函数定义的后面添加这样一行:. ~/.bash_login 与之类似,csh还有一个文件 codice_36,这个文件只在登录式shell退出时执行。Bash与之对应的文件是 codice_37,并且不需要专门的设置。在 Bourne shell 中,codice_38 这个内置工具可以实现类似的效果。
title: 兼容旧环境的Bash启动脚本示例.
content: 下面这个 codice_35 的框架与 Bourne shell 兼容,并且为 codice_30 和 codice_32 提供类似于 csh 的语义。codice_42 测试指定文件是否存在,如果不存在,跳过 codice_43 后面的部分  [ -r ~/.profile ] &&. ~/.profile # 只使用Bourne shell的语法设置环境变量 if [ -n "$PS1" ] ; then # 判断是否是交互式shell fi # if块的结束标志
title: Bash 启动脚本与操作系统相关的问题.
content: 一些 Unix 和 Linux 版本常在 codice_44 放置 Bash 的系统级启动脚本。Bash在其标准的初始化过程中执行它们,不过其他启动脚本可以按照不同于Bash启动序列文档所述的顺序来读取这些文件。root 用户的文件默认内容,以及新用户被创建时系统提供的默认文件可能有问题。启动 X Window系统 的启动脚本可能使用用户的 Bash 启动脚本尝试在 窗口管理器 启动之前设置用户的环境变量。这些问题常常可以通过使用 codice_45 或者 codice_46 来读取 codice_26 而解决。

Summary: Bash,Unix shell的一种,在1987年由布莱恩·福克斯为了GNU计划而编写。1989年释出第一个正式版本,原先是计划用在GNU操作系统上,但能运行于大多数类Unix系统的操作系统之上,包括Linux与Mac OS X v10.4都将它作为默认shell。

Bash (Unix shell): GNU Bash or simply Bash is a Unix shell and command language written by Brian Fox for the GNU Project as a free software replacement for the Bourne shell. First released in 1989, it has been used widely as the default login shell for most Linux distributions and Apple's macOS Mojave and earlier versions. A version is also available for Windows 10. It is also the default user shell in Solaris 11.