Bash 为何要发明 shopt 命令
在 Bash 中,有两个内置命令用来控制 Bash 的各种可配置行为的开关(打开或关闭),这些开关称之为选项(option)。其中一个命令是 set,set 命令有三种功能:显示所有的变量和函数;修改 Bash 的位置参数;控制 Bash 的第一套选项。可见 set 命令完全违背了“一个命令只干一件事”的 UNIX 哲学。另外一个命令是 shopt,从名字(shell options 的缩写)就可以看出,它的功能是控制 Bash 的另一套选项。那么问题就来了,为啥要用两套选项?
在回答为什么之前,我们先看看两者的不同点:
1. set 命令是 POSIX 规范,shopt 不是
set 命令是 Bash 从 sh 继承来的,而且它和它的大多数选项一起都是在 POSIX 规范中的。而 shopt 是 Bash 在 2.0 版本时新增的,别的 Shell 没有这个命令。
|
$ set -o | wc -l 27 $ shopt | wc -l 47 |
在我电脑上的 Bash 4.4 beta 中,set 一共有 27 个选项,shopt 一共有 47 个选项。
2. set 命令和 shopt 命令分别对应两个不同的环境变量
在 Bash 1.* 时代,用 set 命令开启的选项只能在当前 Shell 进程中生效,没有办法通过环境变量传递给它的子进程 Shell,从 Bash 2.0 开始,新增了一个只读变量 SHELLOPTS,只要把它设置成环境变量,它就能把在当前 Shell 中打开的选项传递给子进程 Shell。
|
$ echo $SHELLOPTS braceexpand:emacs:hashall:histexpand:history:interactive-comments:monitor $ set -o noglob $ echo $SHELLOPTS braceexpand:emacs:hashall:histexpand:history:interactive-comments:monitor:noglob $ echo * * $ export SHELLOPTS $ bash -c 'echo *' * |
上面的例子演示了:在当前 Shell 中打开了 noglob 选项,然后 SHELLOPTS 变量的值会自动同步(所有开启的选项名用冒号 join 成的字符串),但这个变量默认并不是环境变量,需要手动 export 一下,然后子进程 Shell 会获取到这个环境变量的值,解析之后,打开这些继承来的选项。为了演示 Bash 的确有这个解析过程,可以这么玩:
|
$ env SHELLOPTS=foo bash bash: foo: invalid option name |
值得注意的是,虽然 shopt 命令和 SHELLOPTS 变量是同时实现的(Bash 2.0),而且它俩的名字看起来也的确像是有对应关系似的,然而并没有。shopt 命令一直没有一个像 set 命令之于 SHELLOPTS 的东西,直到 Bash 4.1,才有了 BASHOPTS 变量,它的功能和 SHELLOPTS 一样,用来把 shopt 命令打开的选项传递给子进程 Shell,这里就不具体演示了。
3. shopt 也可以控制 set 的选项,反之则不行
shopt 命令有个 -o 选项,这个选项的功能就是用来查看或修改原本用 set 控制的那套选项,比如我们随便选个 set 的选项 noglob:
|
$ shopt -s noglob bash: shopt: noglob: invalid shell option name $ shopt -so noglob $ shopt noglob bash: shopt: noglob: invalid shell option name $ shopt -o noglob noglob on |
不加 -o 控制自己的一套选项,加上 -o 控制 set 控制的那套选项。可见在控制 Bash 的选项这个功能上,shopt 命令完全可以代替 set 命令。
4. 为什么要发明 shopt
在了解了这两个命令之后,我不禁要问:为什么要发明一个新的命令?要知道,清楚的记住哪个选项属于哪个命令是很难的,比如我问你 noglob 和 nullglob 哪个是 set 选项哪个是 shopt 选项,没几个人能记得。为什么不像 zsh 一样让 set 管理所有的选项呢:
|
$ zsh -c 'set -o | wc -l' 176 |
我自己猜测了很久:是不是 set 命令的短选项不够了?但我又看到不是所有的 set 长选项都有对应的短选项。是不是 Bash 作者在当时决定以后把 POSIX 规定的选项放一个地方,把其它 Bash 私有的选项放另一个地方,况且 set 命令已经很复杂了,所以发明了个新命令?然后我又发现很多 set 的选项都不在 POSIX 规范里,比如 onecmd、pipefail、history 和 errtrace 等。由于这些猜测说服不了我的好奇心,于是我在 help-bash 上询问了 Bash 作者,毕竟这是 20 年前的事了,除了他谁还可能知道 http://lists.gnu.org/archive/html/help-bash/2015-10/msg00008.html。
在邮件里,我咨询了两个问题,一个就是“为什么不让 set 控制所有的选项,为什么要发明 shopt”;另外一个是“给 shopt -o 参数是不是意味着 Bash 的实现者鼓励人们用新的 shopt 命令而不是旧的 set 命令来控制 Bash 选项”。
第一个问题的答案比较复杂,总结一下就是:作者的出发点的确是为了让 set 控制“那些在 POSIX 规范里的选项”,以及“那些从 sh 继承来的,但不在 POSIX 规范里的选项(比如上面提到的 onecmd)”,以及“那些为了兼容性,从 ksh 引入的,但不在 POSIX 规范里的选项(比如上面提到的 pipefail)”;让 shopt 控制那些 Bash 私有的选项。但由于历史原因,20 年以后,现在看来,这两个出发点显得都不是那么有说服力:现在的 set 选项里存在着既不是从 sh 继承的,又不是从 ksh 学来的,又不在 POSIX 规范中的选项,比如 history 和 errtrace 等,Bash 作者解释说,history 是他希望 POSIX 规范能采纳(然而目前并没有),所以他先实现在了 Bash 里, errtrace(-E) 选项是因为他为了和 errexit(-e)对应起来,所以实现了,他还说如果再来一次的话,他会把 errtrace 放在 shopt 里。至于 shopt 里放着的选项是不是都是 Bash 私有的,也并不是,ksh 和 zsh 也从这些选项里引入了一些到自己的 set 选项里。除了上面我提到名字的选项,邮件里还讲了另外一些不符合一般规律的选项,很复杂,看了也记不住。总之,两个命令的两套选项显得杂乱无章,毫无规律,是历史原因。读到这里,也许有些好奇心强的朋友还想问:难道把 Bash 的私有选项也放 set 里不行吗,不行吗,不行吗!是行,这只是 Bash 作者在当时做的一个决定,要分开放,没什么特殊的原因,这样说应该说服你了吧。
第二个问题没有回答我,我就不再追问了,我猜答案是肯定的,否则干嘛实现那个功能。
Bash 为何要发明 shopt 命令的更多相关文章
- Shopt命令(删除排除)
有时候我们需要反选某个文件以外的其他文件,就会用到rm -rf!(file)命令,但是有时候这条命令会报错显示 -bash: !: event not found 解决办法:shopt -s extg ...
- git 入门教程之 git bash 竟然不支持 tree 命令
开门见山 git bash 是 Windows 用户安装 git 时默认安装的命令行工具,不仅界面漂亮功能也不错,大多数情况下可以替代 Windows 原生的 cmd 命令行. 然而,git bash ...
- Bash 中同名的内部命令和外部命令
昨天有个人在 bug-bash 上问:为什么 [ --help 没有输出帮助信息.有人回答他了,原因是 coreutils 提供的 [ 命令才接受 --help 选项,Bash 自己的 [ 命令不接受 ...
- 单行bash、shell、perl命令
主题:单行经典bash.shell.perl命令 作者:luomg 摘要: 会陆陆续的写自己工作中的常用有意思的命令,争取你能看完后就能搞定常见操作, 且尽量自少提供基本shell.perl的实现方式 ...
- -bash: start-all.sh: 未找到命令
解决方案:以root权限进入,找到hadoop安装的目录,进入sbin目录下 输入命令#start-all.sh 出现错误:-bash: start-all.sh: 未找到命令 百度了一下:原来需要输 ...
- git bash 使用自带 curl 命令出现乱码解决方法
前言 使用过 git 的小伙伴应该都不会陌生,git 自带一个终端 git bash 类似于 window 自带的 dos git 官网下载:https://git-scm.com/dow ...
- BASH BUILTIN COMMANDS 内建命令
除非另外说明,这一章介绍的内建命令如果接受 - 引导的选项,那么它也接受 -- 作为参数,来指示选项的结束 : [arguments] 没有效果:这个命令除了扩展 arguments 并且作任何指定的 ...
- Bash shell的内建命令:type
type指令是用来观察指令时来自于外部指令还是内建在bash中的指令. type [-tpa] name 选项与参数: :不加任何选项与参数时,type会显示出name是外部指令还是bash内建指 ...
- bash的for循环从命令读取值
bash的for循环可以很方便地从命令读取值,还可以指定分割值 下面的程序可以打印文件的内容,前面加上行号 #!/bin/bash # 打印每一行的内容,前面加行号 filename="/h ...
随机推荐
- mac 安装mysql + 修改root用户密码 + 及报Access denied for user 'root'@'localhost' (using password:YES)解决办法
1.下载MySQL 到mysql的官网http://dev.mysql.com/downloads/mysql/然后在页面中会看到“MySQL Community Server”下方有一个“downl ...
- iptables详解
Netfilter包含有三种表,三种表下共包含有五种链,链下面包含各种规则.即表包含若干链,链包含若干规则. (一)三种表为:filter nat mangle 1.filter:处理与本机有 ...
- Entity Framework Code First反向生成代码
那些年我们生成的代码 早年,笨点的方法通常都是使用DbFirst先生成cs,然后把CS复制出来做些修改 后台基本上就自己使用T4来写,但是一直也没时间完善成通用的版本 MS官方 提供了EntityFr ...
- FFMPEG在嵌入式硬件上应用之 —— 基本环境搭建及编译
前段时间在翻看电脑里面资料时,发现了以前做的在嵌入式硬件上面运行以ffmepg为基础,以嵌入式硬件解码的多媒体播放工作,发现都快忘记完了.今日得闲整理温习了一下ffmpeg在嵌入式上的运用,这里给大家 ...
- ADO.net 连接字符串中的 |DataDirectory| 是什么
|DataDirectory| does not come from config settings; you're mixing up three different things: Configu ...
- STM32电机控制器小心得
首先声明的是本人刚刚大学毕业进入电机控制这个行业,以前在学校也做过类似51的实验,然而在工作中发现那些东西是皮毛的不能再皮毛,我现在在公司也算是一个实习生,主要工作是改各厂家对控制器的功能需求,(其实 ...
- JavaScript 基础回顾——数组
JavaScript是无类型语言,数组元素可以具有任意的数据类型,同一个数组的不同元素可以具有不同类型.数组的元素设置可以包含其他数组,便于模拟创建多维数组. 1.创建数组 在JavaScript中, ...
- Chrome firefox ie等浏览器空格 宽度不一样怎么办
有点强迫症,之前某个页面用了空格 ,但是在chrome firefox 和ie显示的宽度都不一样,无法对齐. 搜索了一下,很多人都转载了那篇设置成宋体的,可是仍然没对齐,要么ie对齐,要么chrome ...
- LeetCode:LRU Cache
题目大意:设计一个用于LRU cache算法的数据结构. 题目链接.关于LRU的基本知识可参考here 分析:为了保持cache的性能,使查找,插入,删除都有较高的性能,我们使用双向链表(std::l ...
- JavaScript事件流原理解析
一.为什么会有这一篇的文章 国庆前几天由于任务比较重,要赶在国庆前把一个进度的任务开发完成,所以也就有点赶,但是却遇到了一个比较奇怪的Bug,导致了任务比预计的延迟了几个小时,对此深表遗憾,所以利用国 ...