Bash

出自 ArchWiki

BashBourne-Again SHell)是 命令行 shell/编程语言,由 GNU 项目 开发。其名称暗示了它的前身,早已弃用的 Bourne shell。Bash 可以运行在大多数 类 Unix 操作系统上,包括 GNU/Linux

BashArch Linux 上的默认命令行 shell。

调用

Bash 的行为会根据其调用方式而改变。以下是一些不同模式的描述。

如果 Bash 由 TTY 中的 loginSSH 守护进程或类似方式生成,则它被认为是登录 shell。此模式也可以使用 -l/--login 命令行选项启用。

当 Bash 的标准输入、输出和错误连接到终端(例如,在终端模拟器中运行时),并且它不是使用 -c 选项或非选项参数(例如,bash 脚本)启动时,Bash 被认为是交互式 shell。所有交互式 shell 都会读取 /etc/bash.bashrc~/.bashrc,而交互式登录 shell 还会读取 /etc/profile~/.bash_profile

注意: 在 Arch 中,/bin/sh(曾经是 Bourne shell 可执行文件)符号链接到 bash。如果 Bash 以名称 sh 调用,它会尝试模仿历史版本的 sh 的启动行为,包括 POSIX 兼容性。

配置文件

Bash 将尝试执行一组启动文件,具体取决于其调用方式。有关完整描述,请参阅 GNU Bash 手册的 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#关于进程、环境和继承

Shell 和环境变量

Bash 的行为以及它运行的程序可以通过许多环境变量来影响。环境变量用于存储有用的值,例如命令搜索目录或要使用的浏览器。当启动新的 shell 或脚本时,它会继承其父进程的变量,从而以一组内部 shell 变量开始[1]

Bash 中的这些 shell 变量可以导出以成为环境变量

VARIABLE=content
export VARIABLE

或使用快捷方式

export VARIABLE=content

环境变量通常放置在 ~/.profile/etc/profile 中,以便其他 Bourne 兼容的 shell 可以使用它们。

有关更多通用信息,请参阅 环境变量

命令行

Bash 命令行由名为 Readline 的独立库管理。Readline 提供了 emacsvi 风格的快捷键,用于与命令行交互,例如在单词基础上前后移动、删除单词等。管理输入命令的 历史记录 也是 Readline 的责任。最后但并非最不重要的一点是,它允许您创建

Tab 补全

Tab 补全 是通过按 Tab 键自动完成键入命令的选项(默认启用)。

单次 Tab 补全

可能需要最多按三次 Tab 键才能显示命令的所有可能补全。要减少所需的 Tab 按键次数,请参阅 Readline#更快的补全

常用程序和选项

默认情况下,Bash 仅对命令、文件名和变量进行 tab 补全。软件包 bash-completion 通过为常用命令及其选项添加更专业的 tab 补全来扩展此功能,可以通过读取 /usr/share/bash-completion/bash_completion 来启用(这已经在 Arch 的 /etc/bash.bashrc 中读取)。使用 bash-completion,正常的补全(例如 ls file.* Tab Tab)行为会有所不同;但是,可以使用 compopt -o bashdefault 程序 重新启用它们(有关更多详细信息,请参阅 [2][3])。

自定义每个命令的补全

注意: 使用 complete 内置命令可能会导致与 bash-completion 冲突。

默认情况下,Bash 仅对命令后的文件名进行 tab 补全。您可以使用 complete -c 将其更改为补全命令名称

~/.bashrc
complete -c man which

或使用 -cf 补全命令名称和文件名

complete -cf sudo

有关更多补全选项,请参阅 bash(1) § 可编程补全

历史记录

历史记录补全

您可以绑定向上和向下箭头键以在 Bash 的历史记录中搜索(参见:Readline#历史记录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

删除除最后一个相同命令之外的所有命令

~/.bashrc
export HISTCONTROL=erasedups

避免保存以空格开头的命令

~/.bashrc
export HISTCONTROL=ignorespace

避免保存连续相同的命令和以空格开头的命令

~/.bashrc
export HISTCONTROL=ignoreboth

删除除最后一个相同命令之外的所有命令,以及以空格开头的命令

~/.bashrc
export HISTCONTROL="erasedups:ignorespace"

有关详细信息,请参阅 bash(1) § HISTCONTROL

禁用历史记录

仅临时禁用 bash 历史记录

$ set +o history

现在输入的命令不会记录到 $HISTFILE 中。

例如,现在您可以使用 printf secret | sha256sum 哈希密码,或隐藏 GPG 使用情况,例如 gpg -eaF secret-pubkey.asc,您的密钥不会写入磁盘。

启用历史记录

$ set -o history

禁用所有 bash 历史记录

~/.bashrc or /etc/profile
export HISTSIZE=0

... 只是为了确保,永远销毁您的旧历史文件

$ wipe -i -l2 -x4 -p4 "$HISTFILE"
$ ln -sv /dev/null "$HISTFILE"

模仿 Zsh 的 run-help 功能

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 编辑模式

跨机器共享 bash 历史记录

atuin 将您现有的 shell 历史记录替换为 SQLite 数据库,并记录命令的附加上下文。此外,它还提供通过 Atuin 服务器在机器之间可选的完全加密的历史记录同步。

在同步之前启用 bash 历史记录时间戳 (export HISTTIMEFORMAT="%F %T ")。Atuinblesh-gitAURcmd-wrapped 等工具配合良好,可在多台机器上提供增强的终端体验。

别名

alias 是一个命令,它可以将一个单词替换为另一个字符串。它通常用于缩写系统命令,或为常用命令添加默认参数。

个人别名可以存储在 ~/.bashrc 中,或任何从 ~/.bashrc source 的单独文件中。系统范围的别名(影响所有用户)位于 /etc/bash.bashrc 中。请参阅 [4] 以获取别名示例。

关于函数,请参阅 Bash/函数

技巧与诀窍

提示符自定义

请参阅 Bash/提示符自定义

语法高亮和自动建议

ble.sh (Bash Line Editor),打包为 blesh-gitAUR,是一个用纯 Bash 编写的命令行编辑器,是 GNU Readline 的替代品。它具有许多增强功能,如语法高亮、自动建议、菜单完成、缩写、Vim 编辑模式和 hook 函数。其他有趣的功能包括状态行、历史记录共享、右侧提示符、瞬态提示符和 xterm 标题。

安装后,在交互式会话中 source 它。

~/.bashrc
source /usr/share/blesh/ble.sh

配置在 ~/.blerc 文件和 wiki 中有深入的解释。稳定的 bleshAUR 包也可用。

命令未找到

pkgfile 包含一个 “command not found” hook,当输入无法识别的命令时,它将自动搜索官方仓库。

您需要 source hook 来启用它,例如

~/.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
注意: pkgfile 数据库可能需要更新后才能工作。有关详细信息,请参阅 pkgfile#安装

禁用终端中的 Ctrl+z

您可以通过像这样包装您的命令来禁用 Ctrl+z 功能(暂停/关闭您的应用程序)

#!/bin/bash
trap "" 20
adom

现在,当您在 adomAUR 中意外按下 Ctrl+z 而不是 Shift+z 时,什么都不会发生,因为 Ctrl+z 将被忽略。

退出登录后清除屏幕

要在虚拟终端上退出登录后清除屏幕

~/.bash_logout
clear
reset

当仅输入路径时自动 "cd"

Bash 可以在 shell 中仅输入路径时自动预先添加 cd 。例如

$ /etc
bash: /etc: Is a directory

但是在 .bashrc 文件中添加一行后

~/.bashrc
...
shopt -s autocd
...

你会得到

[user@host ~]$ /etc
cd /etc
[user@host etc]$

Autojump

autojump-gitAUR 是一个 python 脚本,它允许通过在数据库中搜索用户最常访问的路径中的字符串来导航文件系统。

zoxide 是一个替代品,与原始的 autojump 相比,它具有额外的功能和性能改进,并且可以作为 autojump 的直接替代品。

防止文件被覆盖

对于当前会话,要禁止通过 shell 输出重定向覆盖现有的常规文件

$ set -o noclobber

这与 set -C 相同。

要使更改对您的用户持久生效

~/.bashrc
...
set -o noclobber

noclobber 设置时手动覆盖文件

$ echo "output" >| file.txt

使用目录栈进行导航

pushdpopd 可用于将目录推入或弹出堆栈,同时切换到它们。这对于“重放”您的导航历史记录很有用。

[user@host ~] pushd /tmp/dir1
[user@host /tmp/dir1] pushd /var/lib
[user@host /var/lib] popd
[user@host /tmp/dir1] popd
[user@host ~]

请参阅 bash(1) § DIRSTACK

故障排除

窗口大小调整时的行换行

当调整 终端模拟器 的大小时,Bash 可能不会收到调整大小信号。这将导致键入的文本无法正确换行并与提示符重叠。checkwinsize shell 选项在每个命令后检查窗口大小,并在必要时更新 LINESCOLUMNS 的值。

~/.bashrc
shopt -s checkwinsize

即使设置了 ignoreeof,Shell 仍然退出

如果您已设置 ignoreeof 选项,并且发现重复按 ctrl-d 会导致 shell 退出,那是因为此选项仅允许连续调用此键绑定 10 次(或 10 个连续的 EOF 字符,更准确地说),然后才退出 shell。

要允许更高的值,您必须使用 IGNOREEOF 变量。

例如

export IGNOREEOF=100

通过分析脚本检查错误

软件包 shellcheck 分析 bash(和其他 shell)脚本,打印可能的错误,并建议更好的编码。

还有基于此程序的网站 shellcheck.net,用途相同。

另请参阅

教程

社区

示例