Bash (简体中文)
Bash (Bourne-again Shell) 是一个来自 GNU的命令行解释器/编程语言。它的名字是向它的前身——很早以前的 Bourne shell 致敬。Bash可以运行在大部分类 UNIX 操作系统中,包括 GNU/Linux。
Bash是Arch Linux的默认命令行解释器。
调用
Bash 的运行方式会取决于 Bash 被调用的方式。下面是一些不同模式的描述。
如果 Bash 以TTY中的login
、SSH 守护进程、或者其它类似的方式派生出来,我们称之为登录 (login) shell。你可以使用命令行选项 -l
或 --login
来使用这种模式。
如果 Bash 的标准输入输出和标准错误输出都连接到终端(比如说,一个终端模拟器),并且在启动的时候既没有使用 -c
选项和非选项参数(比如说,bash script
),我们称之为交互 (interactive) shell。所有的交互式 shell 都会执行/etc/bash.bashrc
和 ~/.bashrc
文件中的配置,而登录shell还会执行/etc/profile
和 ~/.bash_profile
中的配置。
/bin/sh
(过去是 Bourne shell 的执行文件名) 是 /bin/bash
的符号链接。如果 Bash 通过 sh
方式调用,它会尽量模拟历史上 sh
的启动行为,包括 POSIX 兼容能力。通过在Bash启动时使用 --posix
命令行参数或者在启动后执行 ‘set -o posix
’ 来使Bash在增强的POSIX标准下运行。
配置文件
Bash会在启动时按照不同的启动方式执行一系列启动文件。关于更详尽的描述,您可以参考GNU Bash 指南中/usr/share/doc/bash/bashref.html
(Bash启动文件)这一节。
文件 | 描述 | 登录 shell
(见下) |
交互 shell
非登录 |
---|---|---|---|
/etc/profile
|
加载全部储存在 /etc/profile.d/*.sh 和 /etc/bash.bashrc 中的配置。
|
是 | 否 |
~/.bash_profile
|
针对每个用户,紧接 /etc/profile 执行。如果这个文件不存在,会顺序检查 ~/.bash_login 和 ~/.profile 文件。框架文件 /etc/skel/.bash_profile 同时会引用 ~/.bashrc 。
|
是 | 否 |
~/.bash_logout
|
针对每个用户,退出登录 shell 后。 | 是 | 否 |
/etc/bash.bash_logout
|
取决于 -DSYS_BASH_LOGOUT="/etc/bash.bash_logout" 编译标记。退出登录 shell 后。
|
是 | 否 |
/etc/bash.bashrc
|
取决于编译标志 -DSYS_BASHRC="/etc/bash.bashrc" 。加载 /usr/share/bash-completion/bash_completion 配置。
|
否 | 是 |
~/.bashrc
|
针对每个用户,在 /etc/bash.bashrc 后加载。
|
否 | 是 |
- 如果以
--login
调用,登录 shell 可能不是交互式的。 - 如果可以交互,非登录 shell 不会 加载
~/.bash_profile
。它会继承调用他们的父进程(可能是一个登录 shell)的环境参数。更多信息,请参考GregsWiki:ProcessManagement#On processes, environments and inheritance。
Shell 与环境变量
Bash的行为和通过它启动的程序会被许多环境变量影响。环境变量用于储存有用的值,比如命令搜索路径,或者默认浏览器。当一个新的 shell 或者脚本被启动时,这个 shell 会继承它的父进程的环境变量,从而这个 shell 会带有内部 shell 变量[1]。
这些内部 shell 变量可以以此导出以变成环境变量:
VARIABLE=content export VARIABLE
或者
export VARIABLE=content
环境变量依照惯例放置在~/.profile
或者/etc/profile
中,这样其他兼容 Bourne shell 的 shell 也可以使用。
关于更详尽的内容,您可以参考Environment variables (简体中文)。
命令行
Bash 的命令行由一个叫做 Readline 的分离库来管理。Readline 提供了emacs 和 vi 风格的快捷键用于操作命令行,比如说,以单词为基准前后移动、删除等。管理输入历史也是 Readline 的职责。它还允许你创造宏。
Tab 键补全
Tab 键补全,提供在按下 tab
键后自动补全命令的功能(这个功能默认启用)。
Tab 按下的次数
可能最多需要按三次 tab 才能显示所有的补全选项。如果希望减少这个数值,请参考 更快的补全操作。
常用命令的选项补全
通常来讲,Bash 中按下 tab 只会补全命令、文件名和变量。安装 bash-completion 包,并加载 /usr/share/bash-completion/bash_completion
文件中的配置(这个文件应该已经在Arch的/etc/bash.bashrc中加载了),可以提供更多针对常见命令的选项的 tab 补全。安装这个包后,常规的补全(比如说 $ ls file.*<tab><tab>
)可能会表现得不同。但是,您可以通过{ic|$ compopt -o bashdefault program}}命令来重新启用。(更多细节,请参考 [2] and [3]。)
自定义命令补全
complete
功能可能与 bash-completion 冲突。通常来讲,Bash 中按下 tab 只会补全命令后的文件名。通过complete -c
命令,Bash 可以规定某些命令后的补全形式为命令,比如:
~/.bashrc
complete -c man which
或通过-cf
命令,规定补全形式为命令和文件,比如:
complete -cf sudo
更多补全形式,请参考Bash的手册页。
历史
历史补全
您可以绑定上下键来在 Bash 的历史中查找(请参考 Readline (简体中文)#历史 and Readline 启动文件语法):
~/.bashrc
bind '"\e[A": history-search-backward' bind '"\e[B": history-search-forward'
或者所有 Readline 程序:
~/.inputrc
"\e[A": history-search-backward "\e[B": history-search-forward
更近的历史记录
HISTCONTROL
变量可以避免历史记录记录特定的命令,比如不记录重复的命令
~/.bashrc
export HISTCONTROL=ignoredups
将其设置为 erasedups
可以让 Bash 的历史记录对一条命令只保留一个历史记录(与顺序无关)。更多选项,请参考Bash的手册页。
禁用历史记录
临时禁用历史记录:
$ set +o history
现在输入的命令将不会存入$HISTFILE
。
比如说,你现在可以执行 printf secret | sha256sum
来生成密码文件的散列值,或是隐藏您使用GPG的历史,如执行gpg -eaF secret-pubkey.asc
命令。这些秘密不会被写入磁盘。
开启历史记录:
$ set -o history
HISTCONTROL
变量包含了 ignorespace
,以空格开头的命令将不会记入历史。这样可以更加方便地控制历史记录。更多细节,请参考bash(1) § Shell Variables。禁用所有的 Bash 历史:
~/.bashrc or /etc/profile
export HISTSIZE=0
为了保险(这会永远清除所有的历史记录):
$ wipe -i -l2 -x4 -p4 "$HISTFILE" $ ln -sv /dev/null "$HISTFILE"
模仿 Zsh 的帮助功能
Zsh 可以在光标指向命令的时候按 Alt+h
来调用这个命令的手册。
相同的行为可以通过这个 Readline (简体中文) 绑定在 Bash 中开启:
~/.bashrc
run-help() { help "$READLINE_LINE" 2>/dev/null || man "$READLINE_LINE"; } bind -m vi-insert -x '"\eh": run-help' bind -m emacs -x '"\eh": run-help'
这个操作假设你使用(默认的)Emacs 编辑模式。
别名
别名(alias)是可以让您用另一个字符串来替换一个字符串的命令。这个命令常常被用来缩短系统命令,或者用来将默认参数加入到常用命令中。
推荐将针对用户的别名保存在~/.bashrc
, 而将系统级的别名(这些会影响所有用户)存放在/etc/bash.bashrc
。别名的示例,请参考 [4]。
关于函数,请参考 函数。
提示与技巧
自定义提示符
参见 自定义提示符。
找不到命令
pkgfile 提供了一个"找不到命令"的钩子,可以在输入未知命令后自动查找官方的软件包。
你需要加载这个钩子来启用它,如下:
~/.bashrc
source /usr/share/doc/pkgfile/command-not-found.bash
现在,运行一个不可用的命令将会显示如下信息:
$ abiword
abiword may be found in the following packages: extra/abiword 3.0.1-2 /usr/bin/abiword
另一个"找不到命令"的钩子由 command-not-foundAUR 包提供,它看起来像这个样子:
$ abiword
The command 'abiword' is provided by the following packages: abiword (2.8.6-7) from extra [ abiword ] abiword (2.8.6-7) from staging [ abiword ] abiword (2.8.6-7) from testing [ abiword ]
在终端内禁用Ctrl+Z
你可以相这样包装你的命令,来关闭 Ctrl+Z
功能(暂停/关闭程序)。通过在这个脚本中包装命令
#!/bin/bash trap "" 20 adom
这时如果你在玩 adomAUR 要按 Shift+Z
组合键时不小心按下了 Ctrl+Z
组合键,你的游戏就不会停止运行了,因为我们已经禁用了Ctrl+Z
。
登出后清空屏幕
当登出虚拟终端时,清空屏幕:
~/.bash_logout
clear reset
输入路径自动添加"cd"
Bash 可以自动在输入的一个路径前添加 cd
。比如说:
$ /etc
bash: /etc: Is a directory
但是如果在 .bashrc
文件里添加一行:
~/.bashrc
... shopt -s autocd ...
你会得到:
[user@host ~]$ /etc cd /etc [user@host etc]$
自动跳转
autojump-gitAUR 允许在用户访问最多的路径中搜索文件系统。
安装完后,加载 /etc/profile.d/autojump.bash
来启动这项功能。
防止覆盖文件
在当前的会话中,防止 shell 输出重定向覆盖一个已有的文件:
$ set -o noclobber
这和set -C
命令是一样的。
如果想让该用户一直生效:
~/.bashrc
... set -o noclobber
在设定 noclobber
的情况下强制覆盖文件:
$ echo "output" >| file.txt
错误排除
修正窗口大小调整时的换行
如果您调整了终端模拟器的大小,Bash 可能并没有得到大小重调的信号,你键入的文本就不会正确的换行,并且与已输入内容重叠。启用 checkwinsize
选项可以在每一个命令后检查窗口的大小,并按需更新 LINES
和 COLUMNS
的值来调整。
~/.bashrc
shopt -s checkwinsize
设置 ignoreeof 后 shell 仍然退出
如果您设置了 ignoreeof
选项,但是如果重复按下 ctrl-D
shell 仍然会退出。因为这个选项只允许忽略 10 次连续的EOF记号(即 Ctrl+D
)。
如果需要将这个次数调的更高,需要使用 IGNOREEOF 变量。
比如:
export IGNOREEOF=100
分析代码以检查错误
包 shellcheck 可以分析bash脚本(以及其他脚本),显示可能存在的问题,并对优化代码质量提出意见。
shellcheck.net 网站也提供了基于此程序的相同功能。
更多信息 (英语)
- Wikipedia:Bash (Unix shell)
-
Bash 参考手册,或是
/usr/share/doc/bash/bashref.html
- Readline 启动文件语法
- The Bourne-Again Shell - 开源软件架构 第三章
- PS1 生成器 - 生成你的 .bashrc/PS1 脚本,这样就可以在命令行中使用鼠标拖拽了。
- 有用的 .bashrc 命令
教程
- Greg's Wiki
- GregsWiki:BashGuide
- GregsWiki:BashFAQ
- Bash Hackers Wiki
- Bash Hackers Wiki: List of Bash online tutorials
- Quote Tutorial