This commit is contained in:
louzefeng
2024-07-11 05:50:32 +00:00
parent bf99793fd0
commit d3828a7aee
6071 changed files with 0 additions and 0 deletions

View File

@@ -0,0 +1,338 @@
<audio id="audio" title="28 | 从工作场景出发,寻找炫酷且有效的命令行工具" controls="" preload="none"><source id="mp3" src="https://static001.geekbang.org/resource/audio/4e/e3/4e5e381a96163df2bba03076663bd7e3.mp3"></audio>
你好,我是葛俊。今天,我继续和你分享命令行工具的使用。
在上一篇文章中我与你介绍了命令行环境中的终端、Shell以及远程连接的设置解决了环境配置的问题。今天我们再来看看具体的命令行工具的使用技巧。我会根据常见的工作场景来组织这些工具因为优化工作流程、提高效率才是学习工具的真正目的。
从我的经验来看,开发人员最常见的、使用命令行的场景主要包括两个:
- 日常的操作,比如文件夹跳转、处理和搜索文件夹和文件内容、查看和管理系统信息;
- 开发中常见的工作比如Git的使用、API调试、查看日志和网络状况等。
我会重点与你分享这些场景中有哪些推荐工具以及使用技巧。而至于这些工具如何安装的内容,网络上已经有很多了,我就不再详细描述了。
## 日常操作中的工具和技巧
关于日常操作Linux/Unix系统已经自带了一些工具另外还有些产生已久、为我们所熟悉的工具。不过要更高效地完成工作我们还有更强大的工具可以选择。
### 第一个场景:列举文件夹和文件,查看文件
**列举文件**的默认工具是ls。除此之外一个常用的工具是tree可以列出文件夹的树形结构
<img src="https://static001.geekbang.org/resource/image/5c/3f/5cee9ed0d0fb2beb25961108acdf633f.png" alt="">
另外还有些比tree更方便的工具比如alder和exa。exa尤其好用优点包括
- 默认就有漂亮的颜色显示,并且不同种类文件颜色不同;
- 可以像ls一样显示当前文件夹也可以像tree一样显示树形结构。
<img src="https://static001.geekbang.org/resource/image/d6/3b/d667327bc4bedc74fb665a50d8aa423b.png" alt="">
另外exa还支持对文件状态显示的加强。
比如添加git选项exa会显示文件的git状态在文件名的左边用两个字母来表示文件在工作区和Git暂存区的状态。其中N表示新文件M表示文件修改等。exa的显示和git status命令输出的简单对比如下图所示。
<img src="https://static001.geekbang.org/resource/image/6a/a0/6a9969a87d53e4fc0a073f8918e72ba0.png" alt="">
再比如使用extend选项显示文件的额外信息。
<img src="https://static001.geekbang.org/resource/image/cb/92/cb7d9a0bb21f0b740f6eee812f582392.png" alt="">
再比如使用group-directories-first选项先显示文件夹再显示文件。
<img src="https://static001.geekbang.org/resource/image/47/37/47474d86ceb15eabbf6e6b8a0866a537.png" alt="">
至于**查看文件**Linux默认的工具是cat。相比起来bat是一个更好用的替代品除高亮显示外还可以显示Git的更改状态。
<img src="https://static001.geekbang.org/resource/image/f9/e4/f96d0ab6e8f12728c1d0e9ab2baa10e4.png" alt="">
### 第二个场景:查找并打开文件,进行查看和编辑
一个常用的办法是使用上面提到的工具来列出文件名然后使用grep进行过滤查看或者VIM进行查看和编辑。比如使用命令
```
tree -I &quot;node_modules&quot; -f | grep -C3 index.md
```
可以得到当前文件夹中的所有index.md文件。
命令中tree的参数-I表示排除文件夹node_modulestree的参数-f表示显示文件时包含文件路径方便你拷贝文件的全名grep的参数-C3代表显示搜索结果3行的上下文。
<img src="https://static001.geekbang.org/resource/image/e1/54/e1611236c70cacc9193420afcab76154.png" alt="">
我们也可以使用VIM代替grep进行更复杂的查找和编辑工作。我可以把tree的输出传给VIM然后在VIM中查找index.md使用n跳到下一个搜索结果使用VIM命令gF直接打开文件进行编辑后使用\bd命令关闭这个index.md文件。然后用同样的方式查找并编辑第二、三、四个index.md从而实现对当前文件夹下每一个index.md文件的查看和修改
<img src="https://static001.geekbang.org/resource/image/f4/f5/f409aa3e83ce0412b6275fd4c042eff5.gif" alt="">
事实上,这正是一个**很常见的命令行工作流**把某一个命令的输出传给VIM输出里包含有其他文件的完整路径比如上面例子中index.md的路径然后在VIM里使用gF命令查看并处理这些文件。我推荐你也尝试使用这种工作流。
另外在上面的例子中我使用tree命令来列举文件名。其实很多时候我们**使用find这种专门用来查找文件的命令会更加方便**。不过我今天要介绍的不是find而是它的一个替代品即fd。
<img src="https://static001.geekbang.org/resource/image/35/9d/354fc862f7145dd00f2ebda10500dc9d.png" alt="">
我推荐fd的原因主要有3个
- 语法比find简单
- fd默认会忽略.gitignore文件里指定的文件
- 忽略隐藏文件。
后两点对开发者来说非常方便。比如我在搜索时并不关心node_modules里面的文件也不关心.git文件夹里的文件fd可以自动帮我过滤掉。
另外fd高亮显示速度也很快。至于对查找到的文件进行编辑跟上面提到的方法一样用管道Pipe传给VIM然后使用gF命令即可。
```
fd index.md | vim -
```
另外关于查找文件内容的工具grep我常用的一个替代品是RipGreprg。跟fd类似它也很适合开发者有如下4个特点
- 默认忽略.gitignore文件里指定的文件
- 默认忽略隐藏文件;
- 默认递归搜索所有子目录;
- 可以指定文件类型。
比如使用rg tags就可以方便地查找当前目录下所有包含tags的文件。它的查找速度非常快显示也比grep要漂亮
```
&gt; rg tags
package-lock.json
2467: &quot;common-tags&quot;: {
2469: &quot;resolved&quot;: &quot;https://registry.npmjs.org/common-tags/-/common-tags-1.8.0.tgz&quot;,
5306: &quot;common-tags&quot;: &quot;^1.4.0&quot;,
5446: &quot;common-tags&quot;: &quot;^1.4.0&quot;,
src/pages/2019-05-24-procrastination/index.md
6:tags: ['自我成长', '拖延症']
src/pages/2018-07-21-first-post/index.md
5:tags: ['this', 'that']
```
### 第三个场景:文件夹之间跳转
关于文件夹间的跳转在Bash中有cd和dirs命令在Zsh和Fish中可以使用文件夹名字直接跳转另外Zsh支持`..``...``-`等别名用来分别跳转到父目录、父目录的父目录以及目录历史中上一次记录而不需要写cd。
接下来,我与你介绍**几个新的工具来支持更快的跳转**。
实际上文件夹的跳转,有两种常见的情况:
- 一种是,快速跳转到文件夹跳转历史中的某条记录,即之前曾经去过的某个文件夹;
- 另一种是,快速找到当前文件夹中的某个子文件夹,并跳转过去。
对于第一种情况常用的工具有两个一个是fasd另一个是z它们差别不是特别大。我用的是z具体用法是z会按照访问频率列出最近访问过的文件夹并使用字符串匹配的方式让你实现快速跳转。
比如用z dem<tab>来进行匹配和自动补全找到我想去的demo文件夹回车直接完成跳转。同时我也可以用z dem&lt;回车&gt; 直接跳转。</tab>
<img src="https://static001.geekbang.org/resource/image/65/3e/65630c3d48a262195d63fad17e4e133e.gif" alt="">
对于第二种情况,即快速定位某个子文件夹,我介绍一个**超级酷的工具fzf**。本质上讲fzf是一个对输入进行交互的模糊查询工具。它的使用场景非常多文件夹的跳转只是一个应用。所以我还在再后面文章做更多的详细讨论。
安装好fzf之后你就可以使用Ctrl+T进行文件夹的交互式查询或者使用Alt+C进行文件夹跳转。
比如我想跳转到src/component文件夹中可以输入Alt+Cfzf就会列出当前文件夹下的所有文件夹。比如我输入com没输入其他字符fzf会更新匹配到的文件夹这时可以使用Ctrl+P、Ctrl+N进行上下选择按下回车就可以进入选中的文件夹。
<img src="https://static001.geekbang.org/resource/image/f3/cd/f3892b1c26be577cdf7b3993242830cd.gif" alt="">
<img src="https://static001.geekbang.org/resource/image/af/cd/af4e2d8ac7c21c48aaeb0c9c55dd4bcd.gif" alt="">
### 第四个场景:文件管理
系统自带的文件管理工具有cp、mv、rsync等。这里我再介绍一些更方便的工具。
首先是一个用来**重命名文件的小工具叫作vidir**。顾名思义vidir就是VI来编辑目录的。具体使用方法很简单vidir命令后面接一个文件夹时vidir会打开VIMVIM里面列举该文件夹中所包含的文件和子文件夹然后使用VIM的命令来修改文件和文件夹的名字之后保存退出。这时vidir会自动帮助我们完成对文件和文件夹的重命名。
vidir之所以使用VIM来修改文件是因为VIM功能强大修改非常方便。另外vidir也可以从管道接收文件夹和文件的列表。比如我想把当前文件夹下所有前缀为index的文件都在文件名前添加“new-”。这时我可以使用命令fd | vidir -。
这样fd命令会把当前文件夹下所有文件名传给vidir。然后vidir打开VIM我们在VIM界面中修改文件名即可。如下所示的录屏图片中包括了使用VIM的重复命令.的技巧。
<img src="https://static001.geekbang.org/resource/image/21/2d/21ef569cff63ed639fed4a00968d6d2d.gif" alt="">
另外一组方便进行文件管理的工具是,**命令行的文件管理器**即使用键盘命令在终端界面进行文件夹跳转、查看文件和移动文件等操作。这种命令行界面上的UI叫做TUITerminal UI。十多年前的Borland终端IDE就是这一类工具的翘楚使用熟练之后效率会很高。
TUI的文件管理器我用过3个Midnight Commander (以下简称mc)、Ranger和nnn。
mc是两个窗口的文件管理器。如果你使用过Windows CommanderTotal Commander的话你就会对它的用法很熟悉。重要的命令有使用tab进行两个窗口的切换、使用F4进行编辑、使用F5进行拷贝、使用F9进入菜单、使用F10退出。
我提供了一张录屏图片简单演示了在一台远端服务器上使用mc进行多文件拷贝和编辑并通过菜单修改显示主题的场景。
<img src="https://static001.geekbang.org/resource/image/bb/3a/bb49eec06b2b1293e1d2c0620c81fe3a.gif" alt="">
Ranger和nnn是单窗口的文件管理器。Ranger稍微有一点延迟所以我一般使用nnn。因为是单窗口所以与我们平时在GUI中使用的文件管理器比较相似。
比如在拷贝文件的时候需要先进入文件所在文件夹选择文件然后进入目标文件夹再使用拷贝命令把文件拷贝过去。我在录屏中演示了在nnn中进行文件夹的跳转、创建文件的选择、拷贝使用系统工具打开当前文件查看帮助等功能。
<img src="https://static001.geekbang.org/resource/image/26/48/261bf3fae35b5899ca66aa5e44a39648.gif" alt="">
总的来说这3个工具中我使用最多的是nnn。跟mc相比它最大的好处是快捷键设置跟VIM一致不需要大量使用功能键F1~F12。
## 开发中常见的工作
### Git
命令行中的Git工具除了原生的Git之外常见的还有tig、grv、lazygit和gitin。
我常用的是tig。因为在tig中我可以方便地进行查看改动、产生提交、查看历史blame等操作功能非常强大。比如在查看文件改动时我们可以方便地使用命令1有选择性地把一个文件中改动的一部分添加到一个提交当中实现[第26篇文章](https://time.geekbang.org/column/article/154378)中提到的git add -p的功能。
另外我还可以通过tig快捷地查看一个文件的历史信息。
关于这两个功能的使用,你可以参考下面的录屏图片。
<img src="https://static001.geekbang.org/resource/image/70/d0/7007909425230ece1fac2726d610d0d0.gif" alt="">
### Web 访问
我常用的Web访问工具是HTTPie是curl命令的一个补充。HTTPie的强项在于专门针对HTTP协议所以可以做到格式简单、易用性强两点。
而curl的优势则包括功能强大、支持多种协议和基本所有服务器上都有预装。
关于这两个工具我的建议是curl肯定要学HTTPie如果用得到也值得花时间学习。
### 对JSON进行处理
在命令行对JSON文本进行处理最常见的工具是jq。它能够对JSON进行查询和修改处理功能很强大。
举一个查询的例子我们有这样一个person.json文件列举某个人的详细信息
```
$ cat person.json
{ &quot;id&quot;: { &quot;bioguide&quot;: &quot;E000295&quot;, &quot;thomas&quot;: &quot;02283&quot;, &quot;fec&quot;: [ &quot;S4IA00129&quot; ], &quot;govtrack&quot;: 412667, &quot;opensecrets&quot;: &quot;N00035483&quot;, &quot;lis&quot;: &quot;S376&quot; }, &quot;name&quot;: { &quot;first&quot;: &quot;Joni&quot;, &quot;last&quot;: &quot;Ernst&quot;, &quot;official_full&quot;: &quot;Joni Ernst&quot; }, &quot;bio&quot;: { &quot;gender&quot;: &quot;F&quot;, &quot;birthday&quot;: &quot;1970-07-01&quot; }, &quot;terms&quot;: [ { &quot;type&quot;: &quot;sen&quot;, &quot;start&quot;: &quot;2015-01-06&quot;, &quot;end&quot;: &quot;2021-01-03&quot;, &quot;state&quot;: &quot;IA&quot;, &quot;class&quot;: 2, &quot;state_rank&quot;: &quot;junior&quot;, &quot;party&quot;: &quot;Republican&quot;, &quot;url&quot;: &quot;http://www.ernst.senate.gov&quot;, &quot;address&quot;: &quot;825 B&amp;C Hart Senate Office Building Washington DC 20510&quot;, &quot;office&quot;: &quot;825 B&amp;c Hart Senate Office Building&quot;, &quot;phone&quot;: &quot;202-224-3254&quot; } ] }
```
可以方便地使用cat person.json | jq .”对JSON进行格式化输出
```
$ cat people.json | jq .
{
&quot;id&quot;: {
&quot;bioguide&quot;: &quot;E000295&quot;,
&quot;thomas&quot;: &quot;02283&quot;,
&quot;fec&quot;: [
&quot;S4IA00129&quot;
],
&quot;govtrack&quot;: 412667,
&quot;opensecrets&quot;: &quot;N00035483&quot;,
&quot;lis&quot;: &quot;S376&quot;
},
&quot;name&quot;: {
&quot;first&quot;: &quot;Joni&quot;,
&quot;last&quot;: &quot;Ernst&quot;,
&quot;official_full&quot;: &quot;Joni Ernst&quot;
},
&quot;bio&quot;: {
&quot;gender&quot;: &quot;F&quot;,
&quot;birthday&quot;: &quot;1970-07-01&quot;
},
&quot;terms&quot;: [
{
&quot;type&quot;: &quot;sen&quot;,
&quot;start&quot;: &quot;2015-01-06&quot;,
&quot;end&quot;: &quot;2021-01-03&quot;,
&quot;state&quot;: &quot;IA&quot;,
&quot;class&quot;: 2,
&quot;state_rank&quot;: &quot;junior&quot;,
&quot;party&quot;: &quot;Republican&quot;,
&quot;url&quot;: &quot;http://www.ernst.senate.gov&quot;,
&quot;address&quot;: &quot;825 B&amp;C Hart Senate Office Building Washington DC 20510&quot;,
&quot;office&quot;: &quot;825 B&amp;c Hart Senate Office Building&quot;,
&quot;phone&quot;: &quot;202-224-3254&quot;
}
]
}
```
以及使用jq ".terms[0].office"命令查询他的第一个工作任期的办公室地址。
```
$ cat person.json | jq &quot;.terms[0].office&quot;
&quot;825 B&amp;c Hart Senate Office Building&quot;
```
jq存在的最大问题是它有一套自己的查询处理语言。如果使用jq的频次没那么高的话很难记住每次都要去查帮助才可以。
针对这种情况有人设计了另一种类似的工具直接使用JavaScript作为查询处理语言典型代表是fx和jq.node。这就大大方便了使用JavaScript的开发者因为可以使用已经熟悉了的语法。
比如对于上个案例的JSON文件我可以方便地在fx工具中使用JavaScript的函数filter()进行过滤查询。
```
$ cat person-raw.json| fx 'json =&gt; json.terms.filter(x =&gt; x.type == &quot;top&quot;)'
[
{
&quot;type&quot;: &quot;top&quot;,
&quot;office&quot;: &quot;333 B&amp;c Hart CIrcle Building&quot;,
&quot;phone&quot;: &quot;202-224-3254&quot;
}
]
```
### 查找、关闭进程
通常情况下我们使用kill和pkill来查找和关闭进程。但使用fzf之后我们可以方便地进行交互式的查找目标进程。具体使用方法是输入kill <tab>fzf就会提供一个交互式的界面供你查找目标进程然后回车确认即可。</tab>
在命令行上进行交互式的操作,非常爽,我推荐你一定要试试。
<img src="https://static001.geekbang.org/resource/image/7d/0c/7de54d49ff68186ee6002bc842e95d0c.gif" alt="">
### 查看日志文件
关于查看日志文件的工具我推荐lnav。它比tail -F要方便、强大得多有很多很棒的功能包括
- 支持很多日志格式比如syslog、sudo、uWSGI等并可以根据格式高亮显示
- 支持多个日志同时显示,并用不同颜色区分;
- 支持正则表达式进行过滤等。
<img src="https://static001.geekbang.org/resource/image/52/86/52caa8ef22d6b8b82ce721588a9ac886.png" alt="">
### 命令行本身的实用技巧
关于命令行的使用技巧,有两个非常值得一提:一个是!$,另一个是!!。
**第一个!$**,代表上一个命令行的最后一个参数。比如,如果我上一条命令使用
```
$ vim src/component/README.txt
```
下一步我想为它产生一个备份文件,就可以使用!$
```
## 以下命令即 copy vim src/component/README.txt vim src/component/README.txt.bak
$ cp !$ !$.bak
```
**第二个常用的是!!**表示上一个命令的完整命令。最常用的场景是我先拷贝一个文件发现没有权限需要sudo下一步我就可以用sudo !!来用sudo再次运行拷贝命令。
```
## 因为权限不足,命令失败
$ cp newtool /usr/local/bin/
## 重新使用sudo运行上一条命令。即 sudo wtool /usr/local/bin/
$ sudo !!
```
## 小结
今天,我与你介绍了很多工具。使用工具提高研发效能,最关键的是找到真正常用的工作场景,然后去寻找对应的工具来提高效率。
需要注意的是,只有重复性高的工作,才最适合使用命令行工具;否则,用来适应工具的时间,可能比节省下的时间还要多。这,是命令行的一个基本特点。
最后我把今天与你讨论的Linux/Unix系统自带工具和替代工具整理为了一张表格以方便你复习
<img src="https://static001.geekbang.org/resource/image/46/80/4649bffbfd17cb90d217a25d0382f980.jpg" alt="">
## 思考题
不知道你有没有注意到在录屏中我多次用到了一个叫作tldr的工具。你知道它是什么作用吗
感谢你的收听,欢迎你在评论区给我留言分享你的观点,也欢迎你把这篇文章分享给更多的朋友一起阅读。我们下期再见!