Bash学习 - 第8章:Command Line Editing,第4-5节:Bindable Readline Commands

本文为 Bash Reference Manual第8章:Command Line Editing ,第4节:Bindable Readline Commands 和 第5节:Readline vi Mode 的读书笔记。

💡 由于 8.5 Readline vi Mode 内容极少,因此也包含在本篇笔记中。

本节介绍可能绑定到按键序列的 Readline 命令。您可以通过执行 bind -P 列出您的按键绑定,或者为了更简洁的格式,适合 inputrc 文件的,可以使用 bind -p。(参见 Bash 内建命令。)没有附带按键序列的命令默认是不绑定的。

在以下描述中,point 指当前光标位置,mark 指通过 set-mark 命令保存的光标位置。point 和 mark 之间的文本称为区域。Readline 有一个活动区域的概念:当区域处于活动状态时,Readline 重新显示会使用 active-region-start-color 变量的值高亮显示该区域。enable-active-region 变量用于开启或关闭此功能。有几个命令会将区域设为活动状态;这些命令将在下文中标出。

💡 本章凡是没有做按键绑定的(即括号内为空),都可以忽略不看。

完整的笔记目录参见Bash学习笔记总目录

8.4.1 Commands For Moving

beginning-of-line (C-a)

移动到当前行的起始位置。在某些键盘上,这也可能绑定到 Home 键。

end-of-line (C-e)

移动到行尾。在某些键盘上,这也可能绑定到 End 键。

forward-char (C-f)

向前移动一个字符。在某些键盘上,这也可能绑定到右箭头键。

backward-char (C-b)

向后移动一个字符。在某些键盘上,这也可能绑定到左箭头键。

forward-word (M-f)

向前移动到下一个单词的结尾。单词由字母和数字组成。

backward-word (M-b)

向后移动到当前或前一个单词的起始位置。单词由字母和数字组成。

shell-forward-word (M-C-f)

向前移动到下一个单词的结尾。单词由未引用的 shell 元字符分隔。

shell-backward-word (M-C-b)

向后移动到当前或前一个单词的起始位置。单词由未引用的 shell 元字符分隔。

💡 M-f/M-b和M-C-f/M-C-b的区别,以bind -v|grep enable-active-region为例,前者会将enable-active-region看作3个单词,后者只看作1个。

previous-screen-line ()

尝试将光标移动到上一物理屏幕行的同一列。如果当前 Readline 行不超过一行物理行,或者光标位置不大于提示符长度加屏幕宽度,这将不会产生预期效果。

next-screen-line ()

尝试将光标移动到下一物理屏幕行的同一列。如果当前 Readline 行不超过一行物理行,或者当前 Readline 行的长度不大于提示符长度加屏幕宽度,这将不会产生预期效果。

clear-display (M-C-l)

清除屏幕,并在可能的情况下清除终端的回滚缓冲区,然后重新绘制当前行,使当前行位于屏幕顶部。

clear-screen (C-l)

清除屏幕,然后重新绘制当前行,使当前行位于屏幕顶部。如果给出数字参数,则刷新当前行而不清除屏幕。

redraw-current-line ()

刷新当前行。默认情况下,此功能未绑定。

8.4.2 Commands For Manipulating The History

accept-line(换行或回车)

无论光标在哪里,都要接受这条线。如果该行非空,则根据 HISTCONTROL 和 HISTIGNORE 变量的设置将其添加到历史列表。如果此行是修改过的历史行,则恢复其原始状态。

previous-history(C-P)

在历史列表中"后退",获取上一个命令。这有时也绑定到某些键盘上的上箭头键。

next-history (C-n)

在历史列表中"前进",获取下一个命令。这有时也会绑定到某些键盘的下箭头键。

beginning-of-history (M-<)

历史起始(M-<)移动到历史的第一行。

end-of-history (M->)

移动到输入历史的末尾,即当前输入的行。

reverse-search-history (C-r)

从当前行开始向后搜索,并根据需要向"上"浏览历史记录。这是一种增量搜索。此命令会将区域设置为匹配的文本并激活该区域。

forward-search-history (C-s)

从当前行开始向前搜索,根据需要往下搜索历史。这是一个渐进式搜索。该命令将区域设置为匹配的文本并激活该区域。

non-incremental-reverse-search-history (M-p)

从当前行开始,按需向上搜索历史,使用用户提供的字符串进行非增量搜索。搜索字符串可以匹配历史行中的任意位置。

non-incremental-forward-search-history (M-n)

从当前行开始向前搜索,并根据需要使用用户提供的字符串进行非增量搜索,向历史"向下"搜索。搜索字符串可以匹配历史行中的任意位置。

history-search-backward()

在历史中回溯搜索当前行起点与点之间的字符串。搜索字符串必须在历史行开头匹配。这是一个非增量式搜索。默认情况下,该命令是未绑定的,但某些键盘可能会绑定到"Page Down"键。

history-search-forward ()

在历史中向前搜索当前行起点与点之间的字符串。搜索字符串必须在历史行开头匹配。这是一个非增量式搜索。默认情况下,该命令是未绑定的,但在某些键盘上可能会绑定到"翻页"键。

history-substring-search-backward ()

在历史中回溯搜索当前行起点与点之间的字符串。搜索字符串可以匹配历史行中的任意位置。这是一个非增量式搜索。默认情况下,该命令是未绑定的。

history-substring-search-forward ()

在历史中向前搜索当前行起点与点之间的字符串。搜索字符串可以匹配历史行中的任意位置。这是一个非增量式搜索。默认情况下,该命令是未绑定的。

yank-nth-arg (M-C-y)

在点处插入前一个命令的第一个参数(通常是前一行的第二个词)。参数n时插入前一个命令中的n个词(前一个命令中的词以词0开头)。负论元插入前一个命令结尾的第n个词。一旦计算出参数n,就使用历史扩展工具提取第n个词,就像"!n"历史扩展被指定一样。

yank-last-arg (M-. or M-_)

插入前一个命令的最后一个参数(上一个历史条目的最后一个词)。用数值参数,表现完全像 yank-nth-arg。连续调用 yank-last-arg 会返回历史列表,依次插入每行的最后一个字(或由第一个调用参数指定的字)。为这些连续调用提供的任何数值参数决定了历史进程的方向。否定论元则改变历史进程的方向(向前或向前)。这会利用历史扩展功能提取最终词,就像"!$"历史扩展被指定一样。

💡 yank-last-arg非常有用,我常用ESC+.调用。

operate-and-get-next (C-o)

接受当前行返回调用应用程序,就像输入了换行一样,并从历史中取出相对于当前行的下一行以便编辑。如果提供数值参数,则指定历史条目以代替当前行。

fetch-history ()

用数字参数,从历史列表中取出该条目,并将其设为当前行。没有争论,回到历史列表的第一条目。

8.4.3 Commands For Changing Text

end-of-file (usually C-d)

表示文件结束的字符,例如由stty设置。如果该字符在行中没有字符且光标位于行首时读取,Readline 将其解释为输入的结尾并返回 EOF。

bash 复制代码
$ stty -a|grep -oE "eof = [^;]*;"
eof = ^D;

$ cat > out
1
2
3
^D

delete-char (C-d)

删除光标上的字符。如果该函数与tty EOF特征绑定为同一字符,通常为C-d,效果请见上文。这有时也会绑定到某些键盘的Delete键上。

backward-delete-char (Rubout)

删除光标后面(左侧)的字符。数值参数意味着kill字符,将他们保存在剪贴环上,而不是删除。

即Backspace键。

bash 复制代码
$ stty -a|grep -oE " erase = [^;]*;"
 erase = ^?;

forward-backward-delete-char ()

删除光标下方的字符,除非光标位于行末,此时光标后方的字符被删除。默认情况下,这不会绑定在按键上。

quoted-insert (C-q or C-v)

将下一个输入的字符逐字添加到行中。比如插入像C-q这样的按键序列。

self-insert (a, b, A, 1, !, ...)

插入输入的字符。

bracketed-paste-begin ()

该函数旨在绑定到某些终端发送的"括号粘贴"转义序列,默认会赋予此类绑定。它允许 Readline 将粘贴的文本作为一个单元插入,而不把每个字符当作从键盘读取的字符处理。字符插入时仿佛每个字符都绑定为自我插入,而不是执行任何编辑命令。

括号粘贴将区域(点与标记之间的字符)设置为插入文本。它会设定活跃区域。

transpose-chars (C-t)

将光标前的字符向前拖拽到光标位置的字符上,同时将光标也向前移动。如果插入点位于行末,则将行的最后两个字符置换。负值参数无效。

transpose-words (M-t)

将光标前的单词拖到插入点后的单词之后,同时将光标也移动到该单词之后。如果光标在行尾,这将交换该行的最后两个单词。

shell-transpose-words (M-C-t)

将光标前的单词拖到光标后的单词之后,同时将光标也移动到该单词之后。如果插入点位于行尾,这将交换该行最后两个单词。单词边界与 shell-forward-word 和 shell-backward-word 相同。

upcase-word (M-u)

将当前(或下一个)单词转换为大写字母。使用负数参数时,将上一个单词转换为大写,但不要移动光标。

💡 所谓使用负数参数,就是先按M--

downcase-word (M-l)

将当前(或下一个)单词转换为小写字母。使用负数参数时,将上一个单词转换为小写,但不要移动光标。

capitalize-word (M-c)

将当前(或下一个)单词首字母大写。使用负数参数时,将前一个单词首字母大写,但不要移动光标。

overwrite-mode ()

切换覆盖模式。使用明确的正数参数时,切换到覆盖模式。使用明确的非正数参数时,切换到插入模式。此命令仅影响 emacs 模式;vi 模式下的覆盖操作方式不同。每次调用 readline() 时都从插入模式开始。

在覆盖模式中,绑定到 self-insert 的字符会替换光标处的文本,而不是将文本向右推。绑定到 backward-delete-char 的字符会将光标前的字符替换为空格。

默认情况下,此命令未绑定,但在某些键盘上可能会绑定到插入键。

8.4.4 Killing And Yanking

💡 kill and yank 类似于 cut and paste

kill-line (C-k)

删除从光标位置到当前行末尾的文本。若带负数参数,则从光标向后删除至行首。

backward-kill-line (C-x Rubout)

从光标向后删除至当前行首。若带负数参数,则从光标向前删除至行尾。

unix-line-discard (C-u)

从光标向后删除至当前行开头。

kill-whole-line ()

删除当前行所有字符,无论光标位置。默认未绑定。

kill-word (M-d)

删除从光标到当前单词末尾的文本,若位于单词间则删除至下个单词末尾。单词边界与forward-word相同。

backward-kill-word (M-DEL)

删除光标后方的单词。单词边界与backward-word相同。

shell-kill-word (M-C-d)

删除光标至当前单词末尾,若位于单词间则删除至下个单词末尾。单词边界与shell-forward-word相同。

shell-backward-kill-word ()

删除光标后方单词。单词边界规则与shell-backward-word相同。

unix-word-rubout (C-w)

删除光标后方(左侧)单词,以空格作为单词边界,并将删除内容保存至剪贴环。

unix-filename-rubout ()

删除光标后方单词,以空格和斜杠字符作为分隔符,并将删除内容保存至剪贴环。

delete-horizontal-space ()

删除光标周围所有空格与制表符。默认未绑定此命令

kill-region ()

删除当前区域内的文本。默认情况下,此命令未绑定。

copy-region-as-kill ()

将区域内的文本复制到剪贴环,以便立即粘贴。默认情况下,此命令未绑定。

copy-backward-word ()

将光标前方的单词复制到剪贴环。单词边界与 backward-word 相同。默认未绑定。

copy-forward-word ()

将光标后方的单词复制到剪贴环。单词边界与 forward-word 相同。默认未绑定。

yank (C-y)

将剪贴环顶部内容粘贴至光标所在缓冲区。

yank-pop (M-y)

轮换剪贴环内容,并粘贴新顶部内容。仅当前次操作为 yank 或 yank-pop 时可用。

8.4.5 Specifying Numeric Arguments

digit-argument (M-0, M-1, ... M--)

将此数字添加至正在累加的参数,或启动新参数。M-- 启动负参数。

universal-argument ()

此为指定参数的另一种方式。若该命令后跟一个或多个数字(可选带前导负号),则这些数字定义参数。若命令后跟数字,再次执行通用参数将结束数字参数,否则该命令将被忽略。特殊情况:若该命令后紧跟非数字非负号的字符,则下条命令的参数计数将乘以四。参数计数初始值为一,首次执行此函数使计数变为四,第二次变为十六,依此类推。默认情况下此功能未绑定快捷键。

8.4.6 Letting Readline Type For You

complete (TAB)

尝试对光标前方的文本执行补全操作。实际执行的补全操作取决于具体应用程序。Bash 首先检查命令词是否存在可编程补全(参见可编程补全),否则依次将文本视为变量(若以'$'开头)、用户名(若以'~'开头)、主机名(若以'@'开头)或命令(包括别名、函数和内置命令)。若上述均未匹配,则回退至文件名补全。

possible-completions (M-?)

列出光标前文本的可能补全项。显示补全项时,Readline依次采用以下值设定显示列数:completion-display-width 环境变量值、COLUMNS 环境变量值或屏幕宽度。

bash 复制代码
$ cd /usr/include
$ ls c<此处按(M-?)键>
complex.h  cpio.h     cpuidle.h  crypt.h    ctype.h
$ ls c

insert-completions (M-*)

将光标前文本的所有补全项(即可能补全功能所生成的补全项)插入,各补全项间以空格分隔。

bash 复制代码
$ ls c<此处按(M-*)键>
complex.h  cpio.h     cpuidle.h  crypt.h    ctype.h
$ ls complex.h cpio.h cpuidle.h crypt.h ctype.h

menu-complete ()

类似于complete命令,但会将待补全的单词替换为补全候选列表中的某个匹配项。重复执行menu-complete将遍历补全候选列表,依次插入每个匹配项。当遍历至补全候选列表末尾时,menu-complete会发出提示音(具体音效取决于bell-style设置)并恢复原始文本。传入参数n可在匹配项列表中向前移动n个位置;负参数则向后移动。本命令默认未绑定,建议绑定至TAB键。

menu-complete-backward ()

与menu-complete功能相同,但向后遍历可能的补全项列表,效果等同于menu-complete接收负参数。本命令默认未绑定。

export-completions ()

对光标前方的单词执行上述补全操作,并将可能的补全结果列表按以下格式写入Readline的输出流,每行单独输出信息:

  • 匹配项数量 N;
  • 待补全的单词;
  • S:E,其中S和E分别是该单词在Readline行缓冲区中的起始偏移量和结束偏移量;然后
  • 每行输出一个匹配项

若无匹配项,首行将显示"0",且本命令在S:E之后不输出任何内容。若仅存在单一匹配项,则输出包含该项的单行。若存在多个匹配项,则在S:E后的首行输出匹配项的公共前缀(可能为空),随后各行输出具体匹配项。此时N将包含首行公共前缀。

用户或应用程序需能处理空行情况。其设计意图是让用户或应用程序在读取包含S:E的行之后,继续读取N行以获取匹配列表。该命令默认未绑定。

delete-char-or-list ()

删除光标下的字符(除非位于行首或行尾,类似 delete-char)。在行尾时,其行为与 possible-completions 完全相同。此命令默认未绑定。

complete-filename (M-/)

对光标前文本尝试文件名补全。

possible-filename-completions (C-x /)

将光标前文本视为文件名,列出其可能的补全项。

complete-username (M-~)

将光标前文本视为用户名,尝试进行补全。

possible-username-completions (C-x ~)

将光标前文本视为用户名,列出其可能的补全项。

complete-variable (M-$)

尝试对光标前文本进行补全,将其视为 shell 变量。

possible-variable-completions (C-x $)

列出光标前文本的可能补全项,将其视为 shell 变量。

complete-hostname (M-@)

尝试对光标前文本进行补全,将其视为主机名。

possible-hostname-completions (C-x @)

列出光标前文本的可能补全项,将其视为主机名。

complete-command (M-!)

尝试补全光标前文本,将其视为命令名称。命令补全按以下顺序匹配文本:别名、保留字、shell函数、shell内置命令,最后是可执行文件名。

possible-command-completions (C-x !)

列出光标前文本的可能补全项,将其视为命令名称。

dynamic-complete-history (M-TAB)

尝试对光标前文本进行补全,将文本与历史记录条目进行比对以查找可能的补全匹配项。

dabbrev-expand ()

尝试对光标前文本进行菜单补全,将文本与历史记录列表中的行进行比对以寻找可能的补全匹配项。

complete-into-braces (M-{)

执行文件名补全,并将可能的补全项列表用大括号括起后插入,以便在shell中使用(参见大括号展开)。

bash 复制代码
$ ls c*
complex.h  cpio.h  cpuidle.h  crypt.h  ctype.h

$ ls c<此处按(M-{)键>
$ ls c{omplex.h,p{io.h,uidle.h},rypt.h,type.h}
$ echo c{omplex.h,p{io.h,uidle.h},rypt.h,type.h}
complex.h cpio.h cpuidle.h crypt.h ctype.h

8.4.7 Keyboard Macros

start-kbd-macro (C-x ())

开始保存当前键盘宏中输入的字符。

end-kbd-macro (C-x ))

停止保存当前键盘宏中输入的字符并保存定义。

call-last-kbd-macro (C-x e)

重新执行最后定义的键盘宏,使宏中的字符如同在键盘上输入般生效。

print-last-kbd-macro ()

以适合输入配置文件的格式打印最后定义的键盘宏。

8.4.8 Some Miscellaneous Commands

re-read-init-file (C-x C-r)

读取输入配置文件的内容,并整合其中发现的任何键绑定或变量赋值。

abort (C-g)

中止当前编辑命令并触发终端蜂鸣器(受bell-style设置影响)。

do-lowercase-version (M-A, M-B, M-x, ...)

若元化字符 x 为大写,则执行绑定至对应小写元化字符的命令。若 x 本身已是小写,则行为未定义。

prefix-meta (ESC)

对下一个输入字符进行元操作。输入'ESC f'等同于输入M-f。

undo (C-_ or C-x C-u)

逐行增量撤销,每行操作独立保存。

revert-line (M-r)

撤销本行所有修改。相当于重复执行撤销命令直至恢复初始状态。

tilde-expand (M-&)

对当前单词执行波浪号扩展。

set-mark (C-@)

将标记设置为光标位置。若提供数字参数,则将标记设置至该位置。

exchange-point-and-mark (C-x C-x)

交换光标点与标记位置。将当前光标位置设为保存位置,并将标记设为原光标位置。

character-search (C-])

读取一个字符,并将光标移至该字符的下一个出现位置。负参数表示搜索前一个出现位置。

character-search-backward (M-C-])

读取字符并将光标移至该字符的前一个出现位置。负参数表示搜索后续出现位置。

skip-csi-sequence ()

读取足够字符以消耗多键序列(如Home/End键定义的序列)。CSI序列以控制序列指示符(CSI)开头,通常为ESC [。若该序列绑定为"\e[",则产生CSI序列的按键将失效(除非显式绑定至Readline命令),避免向编辑缓冲区插入异常字符。默认未绑定,但通常绑定至ESC [。

insert-comment (M-#)

若未提供数字参数,则在当前行开头插入注释开始变量的值。若提供数字参数,则该命令作为切换操作:若行首字符与注释开始变量的值不匹配,则插入该值;否则从行首删除注释开始变量中的字符。无论哪种情况,该行均被视为已输入换行符。默认的comment-begin值会使当前行成为shell注释行。若数值参数导致注释字符被移除,则该行将被shell执行。

dump-functions ()

将所有函数及其键绑定打印至Readline输出流。若提供数字参数,输出将采用可直接纳入输入配置文件的格式。此命令默认未绑定。

dump-variables ()

将所有可设置变量及其值打印至Readline输出流。若提供数字参数,输出将采用可直接纳入输入配置文件的格式。该命令默认未绑定。

dump-macros ()

将所有绑定到宏的Readline键序列及其输出字符串打印到Readline输出流。若提供数字参数,则输出将按可纳入inputrc文件的格式呈现。该命令默认未绑定。

execute-named-command (M-x)

从输入中读取可绑定Readline命令名称,并执行其绑定的函数,如同输入中出现了该命令绑定的键序列。若该函数接收数字参数,则将该参数传递给执行的函数。

spell-correct-word (C-x s)

对当前单词执行拼写校正,将其视为目录或文件名,操作方式与cdspell shell选项相同。单词边界与shell-forward-word使用的边界一致。

glob-complete-word (M-g)

将光标前单词视为路径名扩展模式(隐含附加星号),据此生成匹配文件名的补全候选列表。

glob-expand-word (C-x *)

将光标前单词视为路径名扩展模式,插入匹配文件名列表并替换原单词。若提供数字参数,则在路径名扩展前附加'*'。

glob-list-expansions (C-x g)

显示glob-expand-word本应生成的扩展列表,并重新显示当前行。若提供数字参数,则在路径名扩展前附加'*'。

下例解释"在路径名扩展前附加'*'":

bash 复制代码
$ ls /etc/passwd*
/etc/passwd  /etc/passwd-
$ ls /etc/passwd<C-x g>
passwd
# 带数字参数后,相当于ls /etc/passwd*
$ ls /etc/passwd<M-1><C-x g>
passwd   passwd-

shell-expand-line (M-C-e)

通过执行shell单词扩展来扩展当前行。此操作包含别名和历史扩展、$'string'$"string"引号处理、波浪号扩展、参数和变量扩展、算术扩展、命令和进程替换、单词分割以及引号移除。显式参数可抑制命令和进程替换。

history-expand-line (M-^)

对当前行执行历史扩展。

magic-space ()

对当前行执行历史扩展并插入空格(参见历史扩展)。

alias-expand-line ()

对当前行执行别名扩展(参见别名)。

history-and-alias-expand-line ()

对当前行执行历史扩展和别名扩展。

insert-last-argument (M-. 或 M-_)

yank-last-arg 的同义命令。

edit-and-execute-command (C-x C-e)

在当前命令行调用编辑器,并将结果作为shell命令执行。Bash将按顺序尝试调用VISUAL、EDITOR和emacs作为编辑器。

bash 复制代码
$ echo $VISUAL $EDITOR

$ C-x C-e
-bash: emacs: command not found
$ EDITOR=vi
$ C-x C-e
# 进入vi编辑器

display-shell-version (C-x C-v)

显示当前Bash实例的版本信息。

bash 复制代码
$ C-x C-v
GNU bash, version 5.1.8(1)-release (x86_64-redhat-linux-gnu)

8.5 Readline vi Mode

虽然Readline库不具备完整的vi编辑功能,但其提供的功能足以实现对行内容的简单编辑。Readline的vi模式行为符合POSIX标准中sh描述的规范。

可通过'set -o emacs'和'set -o vi'命令(参见内置命令set)在emacs与vi编辑模式间交互切换,Readline默认启用emacs模式

在 vi 模式下输入行时,系统默认处于'插入'模式,如同已输入'i'键。按下 ESC 键可切换至'命令'模式,此时可使用标准 vi 移动键编辑行内文本,通过'k'键回溯历史行,'j'键前进至后续行,等等。

💡 熟悉vi的话,vi的行编辑确实也挺好用的。一些按键绑定如C-r仍可用,不过有些就有冲突了,如C-p在emacs模式下为上一条命令,在vi模式下则为自动补全,但可以用向上键代替。

相关推荐
AI情绪识别开源2 天前
检信AI学业生涯智选系统技术方案概述
emacs
Masimaro5 天前
《elisp 每日一练》—— Minor Mode 回顾与综合练习
emacs
aluluka6 天前
《elisp 每日一练》——状态栏显示管理与modeline 动态更新
emacs·lisp·elisp
aluluka7 天前
《elisp 每日一练》——minor mode 快捷键管理
emacs·lisp·elisp
Masimaro7 天前
《elisp 每日一练》——状态栏显示管理与modeline 动态更新
emacs
橘色的喵8 天前
Claude Code 状态栏脚本:一行显示模型、上下文占用、git 分支和当前目录
linux·git·bash·claude
zhangzeyuaaa8 天前
AI Agent 执行引擎选型指南:PowerShell / Bash 和 Python,边界与最佳实践
人工智能·python·bash
Masimaro9 天前
《elisp 每日一练》——minor mode 开关变量的管理
emacs
Masimaro10 天前
《elisp 每日一练》—— Minor Mode 变量生成机制与状态控制
emacs
典典分享指南10 天前
用结构化数据管理产品知识库
scala·bash·batch·actionscript