7 个你真正会用到的 Bash 历史命令快捷键

使用这些必要的 Bash 快捷键,节省命令行时间。
535 位读者喜欢这篇文章。
Command line prompt

Opensource.com

大多数 Bash 历史命令快捷键指南都会详尽列出所有可用的快捷键。问题在于,我可能只会使用一次某个快捷键,然后就会在尝试所有可能性时感到茫然。之后,我会继续日常工作,并完全忘记它们,只保留在我刚开始使用 Bash 时学到的众所周知的 !! 技巧

因此,大多数快捷键从未被记住。

本文概述了我每天实际使用的快捷键。它基于我的书《Learn Bash the hard way》中的部分内容;(您可以阅读预览以了解更多信息)。

当人们看到我使用这些快捷键时,他们经常问我:“你做了什么!?” 这不需要太多的努力或智力,但要真正学会它们,我建议每天使用一个快捷键,持续一周,然后再学习下一个。花时间掌握它们是值得的,因为长远来看,您节省的时间将非常可观。

1. “最后一个参数”快捷键:!$

如果您只从本文中选择一个快捷键,那就选择这个。它将上一个命令的最后一个参数替换到您的命令行中。

考虑以下场景

$ mv /path/to/wrongfile /some/other/place
mv: cannot stat '/path/to/wrongfile': No such file or directory

啊,我在命令中输入了wrongfile文件名。我应该输入rightfile才对。

您可能会决定重新输入上一个命令,并将 wrongfile 完全替换为 rightfile。但实际上,您可以输入

$ mv /path/to/rightfile !$
mv /path/to/rightfile /some/other/place

命令就会生效。

在 Bash 中,还有其他方法可以使用快捷键实现相同的效果,但重复使用上一个命令的最后一个参数这个技巧是我最常用的。

2. “第 n 个参数”快捷键:!:2

有没有做过类似的事情?

$ tar -cvf afolder afolder.tar
tar: failed to open

和许多其他人一样,我经常把 tar (和 ln) 的参数搞错,次数多到我自己都不想承认。

xkcd comic

当您像这样混淆参数时,您可以运行

$ !:0 !:1 !:3 !:2
tar -cvf afolder.tar afolder

您的声誉将得以保全。

上一个命令的项是零索引的,可以使用 !: 后面的数字进行替换。

显然,您也可以使用它来重用上一个命令中的特定参数,而不是全部参数。

3. “所有参数”快捷键:!:1-$

想象一下,我运行一个像这样的命令

$ grep '(ping|pong)' afile

参数是正确的;但是,我想在一个文件中匹配 pingpong,但我使用的是 grep 而不是 egrep

我开始输入 egrep,但我不希望重新输入其他参数。因此,我可以使用 !:1$ 快捷键来请求上一个命令的所有参数,从第二个参数(记住它们是零索引的)到最后一个参数(用 $ 符号表示)。

$ egrep !:1-$
egrep '(ping|pong)' afile
ping

您不需要选择 1-$;您可以选择一个子集,例如 1-23-9(如果您在上一个命令中有那么多参数)。

4. “倒数第 n 个”快捷键:!-2:$

当我知道如何立即更正上一个命令时,上面的快捷键非常棒,但通常我在原始命令之后运行其他命令,这意味着上一个命令不再是我想要引用的命令。

例如,使用前面 mv 的例子,如果我在犯错后使用 ls 检查文件夹的内容

$ mv /path/to/wrongfile /some/other/place
mv: cannot stat '/path/to/wrongfile': No such file or directory
$ ls /path/to/
rightfile

我就不能再使用 !$ 快捷键了。

在这些情况下,我可以在 ! 之后插入 -n:(其中 n 是要回溯历史记录的命令数),以从较旧的命令中获取最后一个参数

$ mv /path/to/rightfile !-2:$
mv /path/to/rightfile /some/other/place

同样,一旦您学会了它,您可能会惊讶于您需要它的频率。

5. “获取文件夹”快捷键:!$:h

这个快捷键表面上看起来不太有前景,但我每天使用它数十次。

想象一下,我运行一个像这样的命令

$ tar -cvf system.tar /etc/system
 tar: /etc/system: Cannot stat: No such file or directory
 tar: Error exit delayed from previous errors. 

我可能想做的第一件事是进入 /etc 文件夹,看看里面有什么,并找出我做错了什么。

我可以通过以下命令一步到位

$ cd !$:h
cd /etc

这个命令的意思是:“获取上一个命令的最后一个参数 (/etc/system),并删除其最后一个文件名组件,只留下 /etc。”

6. “当前行”快捷键:!#:1

多年来,我偶尔会想,是否可以引用当前行上的参数,直到最终查阅并学习了它。我真希望我早点这么做。我最常使用它来创建备份文件

$ cp /path/to/some/file !#:1.bak
cp /path/to/some/file /path/to/some/file.bak

但一旦熟练掌握,它就可以成为 … 的非常快速的替代方案

7. “搜索和替换”快捷键:!!:gs

这个快捷键会在引用的命令中搜索,并将前两个 / 字符中的内容替换为后两个 / 字符中的内容。

假设我想告诉全世界我的 s 键坏了,输出的是 f 而不是 s

$ echo my f key doef not work
my f key doef not work

然后我意识到我只是不小心按到了 f 键。要将所有 f 替换为 s,我可以输入

$ !!:gs/f /s /
echo my s key does not work
my s key does not work

它不仅适用于单个字符;我也可以替换单词或句子。

$ !!:gs/does/did/
echo my s key did not work
my s key did not work

试用一下

只是为了向您展示如何组合这些快捷键,您能弄清楚这些指令会输出什么吗?

$ ping !#:0:gs/i/o
$ vi /tmp/!:0.txt
$ ls !$:h
$ cd !-2:h
$ touch !$!-3:$ !! !$.txt
$ cat !:1-$

结论

对于日常命令行用户来说,Bash 可以是一个优雅的快捷键来源。虽然有成千上万的技巧和窍门可以学习,但这些是我最喜欢且经常使用的快捷键。

如果您想更深入地了解 Bash 可以教给您的所有内容,请购买我的书《Learn Bash the hard way》或查看我的在线课程《Master the Bash shell》。


本文最初发布在 Ian 的博客 Zwischenzugs.com 上,并已获得许可重复使用。

接下来阅读
标签
Avatar
开源程序员/演讲者/作者/博主/培训师

12 条评论

哇!真有用!谢谢分享。

哇,太棒了。我知道第一个,但另外六个将为我省去很多在心里咒骂的时候!

您的“当前行”示例过于牵强。您的示例是像这样复制到备份:

$ cp /path/to/some/file !#:1.bak

但是,更好的编写方式是使用文件名生成

$ cp /path/to/some/file{,.bak}

但这并不是历史扩展... 我不确定我能否想出一个使用 `!#:1` 的好理由。

我使用 Bash 大约 19 年了,除了 !!$ 之外,我从未使用过这些快捷键。用户最好学习如何使用向上箭头和触发编辑和执行命令的组合键来编辑他们之前的命令行。您将获得 emacs 或 vi 编辑器,它可以非常快速地更改参数。

对我来说,Bash 历史命令快捷键的问题是... 我从来没有需要学习它们。

如果您的 shell 启用了 readline,我发现使用箭头键和修饰键浏览历史记录比键入 !:1(或记住它的含义)容易得多。

示例

Ctrl+R 用于反向搜索
Ctrl+A 移动到行首(Home 键也行)
Ctrl+E 移动到行尾(End 键也行)
Ctrl+K 删除从光标到行尾的文本
Ctrl+U 删除从光标到行首的文本
Alt+F 向前移动一个单词(Ctrl+右箭头也行)
Alt+B 向后移动一个单词(Ctrl+左箭头也行)
等等。

当然,结果可能因人而异。

这些是一些很棒的历史命令替换技巧。我知道其中一些,但不是全部。

```
cp /path/to/some/file !#:1.bak
```

我认为使用大括号扩展会更容易,像这样

```
cp /path/to/some/{file,file.bak}
```

很棒的技巧!:0 非常感谢!!

很棒的文章,但它缺少一个我经常使用的模式,!* 它重复所有
上一个命令中的参数。

一个用例是运行 ls 以确保所有正确的文件都匹配
在运行 rm 之前。例如,要删除所有 pdf 文件
是教程...

ls *[Tt]ut*.pdf
rm !*

关于第 3 项
$ grep '(ping|pong)' afile

您不必输入正确的命令(egrep,而不是 grep),因为如果您在范围中包含 0,则只需输入 'e' 即可

$ e!:0-2
egrep '(ping|pong)' afile
pingpang
pangpong
pingpong

关于第 3 项
$ grep '(ping|pong)' afile

您不必输入正确的命令(egrep,而不是错误输入的 grep),因为如果您在范围中包含 0,则只需输入 'e' 即可

$ e!:0-2
egrep '(ping|pong)' afile
pingpang
pangpong
pingpong

© . All rights reserved.