Ricardo Gerardi 发布的文章

使用别名为你最常用或复杂的 Git 命令创建快捷方式。

这篇出色的文章《改变我使用 Git 工作方式的七个技巧》启发了我写下另一个对我在命令行上使用 Git 的经验有重大影响的 Git 特性:别名。

定义 Git 的别名来替代命令有两大好处。

  • 它简化了有许多选项的长命令,使它们更短,更容易记住。
  • 缩短了经常使用的命令,使你的工作更有效率。

如何定义和使用别名

要定义 Git 的别名,请使用 git config 命令,加上别名和要替换的命令。例如,要为 git push 创建别名 p

$ git config --global alias.p 'push'

你可以通过将别名作为 git 的参数来使用别名,就像其他命令一样:

$ git p

要查看所有的别名,用 git config 列出你的配置:

$ git config --global -l
user.name=ricardo
[email protected]
alias.p=push

你也可以用你喜欢的 shell 来定义别名,比如 Bash 或 Zsh。不过,用 Git 定义别名有几个功能是用 shell 无法实现的。首先,它允许你在不同的 shell 中使用别名,而无需额外配置。此外,它还集成了 Git 的自动更正功能,所以当你输入错误的命令时,Git 可以建议你正确的别名。最后,Git 还会将别名保存在用户配置文件中,你可以通过复制一个文件将别名转移到其他机器上。

无论使用哪种方法,定义别名都能改善你使用 Git 的整体体验。更多关于定义 Git 别名的信息,请看《Git Book》。

8 个有用的 Git 别名

现在你知道如何创建和使用别名了,来看看一些有用的别名。

1、Git 状态

Git 命令行用户经常使用 status 命令来查看已更改或未跟踪的文件。默认情况下,这个命令提供了很多行的冗长输出,你可能不想要或不需要。你可以使用一个别名来处理这两个组件。定义别名 st 来缩短命令,并使用选项 -sb 来输出一个不那么啰嗦的状态和分支信息。

$ git config --global alias.st 'status -sb'

如果你在一个干净的分支上使用这个别名,你的输出就像这样:

$  git st
## master

在一个带有已更改和未跟踪文件的分支上使用它,会产生这样的输出:

$ git st
## master
 M test2
?? test3

2、Git 单行日志

创建一个别名,以单行方式显示你的提交,使输出更紧凑:

$ git config --global alias.ll 'log --oneline'

使用这个别名可以提供所有提交的简短列表:

$ git ll
33559c5 (HEAD -> master) Another commit
17646c1 test1

3、Git 的最近一次提交

这将显示你最近一次提交的详细信息。这是扩展了《Git Book》中 别名 一章的例子:

$ git config --global alias.last 'log -1 HEAD --stat'

用它来查看最后的提交:

$ git last
commit f3dddcbaabb928f84f45131ea5be88dcf0692783 (HEAD -> branch1)
Author: ricardo <[email protected]>
Date:   Tue Nov 3 00:19:52 2020 +0000

    Commit to branch1

 test2 | 1 +
 test3 | 0
 2 files changed, 1 insertion(+)

4、Git 提交

当你对 Git 仓库进行修改时,你会经常使用 git commit。使用 cm 别名使 git commit -m 命令更有效率:

$ git config --global alias.cm 'commit -m'

因为 Git 别名扩展了命令,所以你可以在执行过程中提供额外的参数:

$ git cm "A nice commit message"
[branch1 0baa729] A nice commit message
 1 file changed, 2 insertions(+)

5、Git 远程仓库

git remote -v 命令列出了所有配置的远程仓库。用别名 rv 将其缩短:

$ git config --global alias.rv 'remote -v'

6、Git 差异

git diff 命令可以显示不同提交的文件之间的差异,或者提交和工作树之间的差异。用 d 别名来简化它:

$ git config --global alias.d 'diff'

标准的 git diff 命令对小的改动很好用,但对于比较复杂的改动,外部工具如 vimdiff 就更有用。创建别名 dv 来使用 vimdiff 显示差异,并使用 y 参数跳过确认提示:

$ git config --global alias.dv 'difftool -t vimdiff -y'

使用这个别名来显示两个提交之间的 file1 差异:

$ git dv 33559c5 ca1494d file1

 title=

7、Git 配置列表

gl 别名可以更方便地列出所有用户配置:

$ git config --global alias.gl 'config --global -l'

现在你可以看到所有定义的别名(和其他配置选项):

$ git gl
user.name=ricardo
[email protected]
alias.p=push
alias.st=status -sb
alias.ll=log --oneline
alias.last=log -1 HEAD --stat
alias.cm=commit -m
alias.rv=remote -v
alias.d=diff
alias.dv=difftool -t vimdiff -y
alias.gl=config --global -l
alias.se=!git rev-list --all | xargs git grep -F

8、搜索提交

Git 别名允许你定义更复杂的别名,比如执行外部 shell 命令,可以在别名前加上 ! 字符。你可以用它来执行自定义脚本或更复杂的命令,包括 shell 管道。

例如,定义 se 别名来搜索你的提交:

$ git config --global alias.se '!git rev-list --all | xargs git grep -F'

使用这个别名来搜索提交中的特定字符串:

$ git se test2
0baa729c1d683201d0500b0e2f9c408df8f9a366:file1:test2
ca1494dd06633f08519ec43b57e25c30b1c78b32:file1:test2

自动更正你的别名

使用 Git 别名的一个很酷的好处是它与自动更正功能的原生集成。如果你犯了错误,默认情况下,Git 会建议使用与你输入的命令相似的命令,包括别名。例如,如果你把 status 打成了 ts,而不是 st,Git 会推荐正确的别名:

$ git ts
git: 'ts' is not a git command. See 'git --help'.

The most similar command is
        st

如果你启用了自动更正功能,Git 会自动执行正确的命令:

$ git config --global help.autocorrect 20
$ git ts
WARNING: You called a Git command named 'ts', which does not exist.
Continuing in 2.0 seconds, assuming that you meant 'st'.
## branch1
?? test4

优化 Git 命令

Git 别名是一个很有用的功能,它可以优化常见的重复性命令的执行,从而提高你的效率。Git 允许你定义任意数量的别名,有些用户会定义很多别名。我更喜欢只为最常用的命令定义别名 —— 定义太多别名会让人难以记忆,而且可能需要查找才能使用。

更多关于别名的内容,包括其他有用的内容,请参见 Git 维基的别名页面


via: https://opensource.com/article/20/11/git-aliases

作者:Ricardo Gerardi 选题:lujun9972 译者:wxy 校对:wxy

本文由 LCTT 原创编译,Linux中国 荣誉推出

通过这 5 个插件扩展 Vim 功能来提升你的编码效率。

我用 Vim 已经超过 20 年了,两年前我决定把它作为我的首要文本编辑器。我用 Vim 来编写代码、配置文件、博客文章及其它任意可以用纯文本表达的东西。Vim 有很多超级棒的功能,一旦你适合了它,你的工作会变得非常高效。

在日常编辑工作中,我更倾向于使用 Vim 稳定的原生功能,但开源社区对 Vim 开发了大量的插件,可以扩展 Vim 的功能、改进你的工作流程和提升工作效率。

以下列举 5 个非常好用的可以用于编写任意编程语言的插件。

1、Auto Pairs

Auto Pairs 插件可以帮助你插入和删除成对的文字,如花括号、圆括号或引号。这在编写代码时非常有用,因为很多编程语言都有成对标记的语法,就像圆括号用于函数调用,或引号用于字符串定义。

Auto Pairs 最基本的功能是在你输入一个左括号时会自动补全对应的另一半括号。比如,你输入了一个 [,它会自动帮你补充另一半 ]。相反,如果你用退格键删除开头的一半括号,Auto Pairs 会删除另一半。

如果你设置了自动缩进,当你按下回车键时 Auto Pairs 会在恰当的缩进位置补全另一半括号,这比你找到放置另一半的位置并选择一个正确的括号要省劲多了。

例如下面这段代码:

package main

import "fmt"

func main() {
    x := true
    items := []string{"tv", "pc", "tablet"}

    if x { 
        for _, i := range items
    } 
}

items 后面输入一个左花括号按下回车会产生下面的结果:

package main

import "fmt"

func main() {
    x := true
    items := []string{"tv", "pc", "tablet"}

    if x {
        for _, i := range items  {
            | (cursor here)
        }
    }
}

Auto Pairs 提供了大量其它选项(你可以在 GitHub 上找到),但最基本的功能已经很让人省时间了。

2、NERD Commenter

NERD Commenter 插件给 Vim 增加了代码注释的功能,类似在 IDE integrated development environment 中注释功能。有了这个插件,你可以一键注释单行或多行代码。

NERD Commenter 可以与标准的 Vim filetype 插件配合,所以它能理解一些编程语言并使用合适的方式来注释代码。

最易上手的方法是按 Leader+Space 组合键来切换注释当前行。Vim 默认的 Leader 键是 \

可视化模式 Visual mode 中,你可以选择多行一并注释。NERD Commenter 也可以按计数注释,所以你可以加个数量 n 来注释 n 行。

还有个有用的特性 “Sexy Comment” 可以用 Leader+cs 来触发,它的块注释风格更漂亮一些。例如下面这段代码:

package main

import "fmt"

func main() {
    x := true
    items := []string{"tv", "pc", "tablet"}

    if x {
        for _, i := range items {
            fmt.Println(i)
        }
    }
}

选择 main 函数中的所有行然后按下 Leader+cs 会出来以下注释效果:

package main

import "fmt"

func main() {
/*
 *    x := true
 *    items := []string{"tv", "pc", "tablet"}
 *
 *    if x {
 *        for _, i := range items {
 *            fmt.Println(i)
 *        }
 *    }
 */
}

因为这些行都是在一个块中注释的,你可以用 Leader+Space 组合键一次去掉这里所有的注释。

NERD Commenter 是任何使用 Vim 写代码的开发者都必装的插件。

3、VIM Surround

Vim Surround 插件可以帮你“环绕”现有文本插入成对的符号(如括号或双引号)或标签(如 HTML 或 XML 标签)。它和 Auto Pairs 有点儿类似,但是用于处理已有文本,在编辑文本时更有用。

比如你有以下一个句子:

"Vim plugins are awesome !"

当你的光标处于引起来的句中任何位置时,你可以用 ds" 组合键删除句子两端的双引号。

Vim plugins are awesome !

你也可以用 cs"' 把双端的双引号换成单引号:

'Vim plugins are awesome !'

或者再用 cs'[ 替换成中括号:

[ Vim plugins are awesome ! ]

它对编辑 HTML 或 XML 文本中的 标签 tag 尤其在行。假如你有以下一行 HTML 代码:

<p>Vim plugins are awesome !</p>

当光标在 “awesome” 这个单词的任何位置时,你可以按 ysiw<em> 直接给它加上着重标签(<em>):

<p>Vim plugins are <em>awesome</em> !</p>

注意它聪明地加上了 </em> 闭合标签。

Vim Surround 也可以用 ySS 缩进文本并加上标签。比如你有以下文本:

<p>Vim plugins are <em>awesome</em> !</p>

你可以用 ySS<div class="normal"> 加上 div 标签,注意生成的段落是自动缩进的。

<div class="normal">
        <p>Vim plugins are <em>awesome</em> !</p>
</div>

Vim Surround 有很多其它选项,你可以参照 GitHub 上的说明尝试它们。

4、Vim Gitgutter

Vim Gitgutter 插件对使用 Git 作为版本控制工具的人来说非常有用。它会在 Vim 的行号列旁显示 git diff 的差异标记。假设你有如下已提交过的代码:

  1 package main
  2
  3 import "fmt"
  4
  5 func main() {
  6     x := true
  7     items := []string{"tv", "pc", "tablet"}
  8
  9     if x {
 10         for _, i := range items {
 11             fmt.Println(i)
 12         }
 13     }
 14 }

当你做出一些修改后,Vim Gitgutter 会显示如下标记:

    1 package main
    2
    3 import "fmt"
    4
_   5 func main() {
    6     items := []string{"tv", "pc", "tablet"}
    7
~   8     if len(items) > 0 {
    9         for _, i := range items {
   10             fmt.Println(i)
+  11             fmt.Println("------")
   12         }
   13     }
   14 }

_ 标记表示在第 5 行和第 6 行之间删除了一行。~ 表示第 8 行有修改,+ 表示新增了第 11 行。

另外,Vim Gitgutter 允许你用 [c]c 在多个有修改的块之间跳转,甚至可以用 Leader+hs 来暂存某个变更集。

这个插件提供了对变更的即时视觉反馈,如果你用 Git 的话,有了它简直是如虎添翼。

5、VIM Fugitive

Vim Fugitive 是另一个将 Git 工作流集成到 Vim 中的超棒插件。它对 Git 做了一些封装,可以让你在 Vim 里直接执行 Git 命令并将结果集成在 Vim 界面里。这个插件有超多的特性,更多信息请访问它的 GitHub 项目页面。

这里有一个使用 Vim Fugitive 的基础 Git 工作流示例。设想我们已经对下面的 Go 代码做出修改,你可以用 :Gblame 调用 git blame 来查看每行最后的提交信息:

e9949066 (Ricardo Gerardi   2018-12-05 18:17:19 -0500)│    1 package main
e9949066 (Ricardo Gerardi   2018-12-05 18:17:19 -0500)│    2
e9949066 (Ricardo Gerardi   2018-12-05 18:17:19 -0500)│    3 import "fmt"
e9949066 (Ricardo Gerardi   2018-12-05 18:17:19 -0500)│    4
e9949066 (Ricardo Gerardi   2018-12-05 18:17:19 -0500)│_   5 func main() {
e9949066 (Ricardo Gerardi   2018-12-05 18:17:19 -0500)│    6     items := []string{"tv", "pc", "tablet"}
e9949066 (Ricardo Gerardi   2018-12-05 18:17:19 -0500)│    7
00000000 (Not Committed Yet 2018-12-05 18:55:00 -0500)│~   8     if len(items) > 0 {
e9949066 (Ricardo Gerardi   2018-12-05 18:17:19 -0500)│    9         for _, i := range items {
e9949066 (Ricardo Gerardi   2018-12-05 18:17:19 -0500)│   10             fmt.Println(i)
00000000 (Not Committed Yet 2018-12-05 18:55:00 -0500)│+  11             fmt.Println("------")
e9949066 (Ricardo Gerardi   2018-12-05 18:17:19 -0500)│   12         }
e9949066 (Ricardo Gerardi   2018-12-05 18:17:19 -0500)│   13     }
e9949066 (Ricardo Gerardi   2018-12-05 18:17:19 -0500)│   14 }

可以看到第 8 行和第 11 行显示还未提交。用 :Gstatus 命令检查仓库当前的状态:

  1 # On branch master
  2 # Your branch is up to date with 'origin/master'.
  3 #
  4 # Changes not staged for commit:
  5 #   (use "git add <file>..." to update what will be committed)
  6 #   (use "git checkout -- <file>..." to discard changes in working directory)
  7 #
  8 #       modified:   vim-5plugins/examples/test1.go
  9 #
 10 no changes added to commit (use "git add" and/or "git commit -a")
--------------------------------------------------------------------------------------------------------
    1 package main
    2
    3 import "fmt"
    4
_   5 func main() {
    6     items := []string{"tv", "pc", "tablet"}
    7
~   8     if len(items) > 0 {
    9         for _, i := range items {
   10             fmt.Println(i)
+  11             fmt.Println("------")
   12         }
   13     }
   14 }

Vim Fugitive 在分割的窗口里显示 git status 的输出结果。你可以在该行按下 - 键用该文件的名字暂存这个文件的提交,再按一次 - 可以取消暂存。这个信息会随着你的操作自动更新:

  1 # On branch master
  2 # Your branch is up to date with 'origin/master'.
  3 #
  4 # Changes to be committed:
  5 #   (use "git reset HEAD <file>..." to unstage)
  6 #
  7 #       modified:   vim-5plugins/examples/test1.go
  8 #
--------------------------------------------------------------------------------------------------------
    1 package main
    2
    3 import "fmt"
    4
_   5 func main() {
    6     items := []string{"tv", "pc", "tablet"}
    7
~   8     if len(items) > 0 {
    9         for _, i := range items {
   10             fmt.Println(i)
+  11             fmt.Println("------")
   12         }
   13     }
   14 }

现在你可以用 :Gcommit 来提交修改了。Vim Fugitive 会打开另一个分割窗口让你输入提交信息:

  1 vim-5plugins: Updated test1.go example file
  2 # Please enter the commit message for your changes. Lines starting
  3 # with '#' will be ignored, and an empty message aborts the commit.
  4 #
  5 # On branch master
  6 # Your branch is up to date with 'origin/master'.
  7 #
  8 # Changes to be committed:
  9 #       modified:   vim-5plugins/examples/test1.go
 10 #

:wq 保存文件完成提交:

[master c3bf80f] vim-5plugins: Updated test1.go example file
 1 file changed, 2 insertions(+), 2 deletions(-)
Press ENTER or type command to continue

然后你可以再用 :Gstatus 检查结果并用 :Gpush 把新的提交推送到远程。

  1 # On branch master
  2 # Your branch is ahead of 'origin/master' by 1 commit.
  3 #   (use "git push" to publish your local commits)
  4 #
  5 nothing to commit, working tree clean

Vim Fugitive 的 GitHub 项目主页有很多屏幕录像展示了它的更多功能和工作流,如果你喜欢它并想多学一些,快去看看吧。

接下来?

这些 Vim 插件都是程序开发者的神器!还有另外两类开发者常用的插件:自动完成插件和语法检查插件。它些大都是和具体的编程语言相关的,以后我会在一些文章中介绍它们。

你在写代码时是否用到一些其它 Vim 插件?请在评论区留言分享。


via: https://opensource.com/article/19/1/vim-plugins-developers

作者:Ricardo Gerardi 选题:lujun9972 译者:pityonline 校对:wxy

本文由 LCTT 原创编译,Linux中国 荣誉推出

通过键盘操作的 i3 平铺窗口管理器使用 Linux 桌面。

Linux(和一般的开源软件)最美好的一点是自由 —— 可以在不同的替代方案中进行选择以满足我们的需求。

我使用 Linux 已经很长时间了,但我从来没有对可选用的桌面环境完全满意过。直到去年,Xfce 还是我认为在功能和性能之间的平和最接近满意的一个桌面环境。然后我发现了 i3,这是一个改变了我的生活的惊人的软件。

i3 是一个平铺窗口管理器。窗口管理器的目标是控制窗口系统中窗口的外观和位置。窗口管理器通常用作功能齐全的桌面环境 (如 GONME 或 Xfce ) 的一部分,但也有一些可以用作独立的应用程序。

平铺式窗口管理器会自动排列窗口,以不重叠的方式占据整个屏幕。其他流行的平铺式窗口管理器还有 wmiixmonad

 title=

带有三个的 i3 屏幕截图

为了获得更好的 Linux 桌面体验,以下是我使用和推荐 i3 窗口管理器的五个首要原因。

1、极简艺术

i3 速度很快。它既不冗杂、也不花哨。它的设计简单而高效。作为开发人员,我重视这些功能,因为我可以使用更多的功能以丰富我最喜欢的开发工具,或者使用容器或虚拟机在本地测试内容。

此外, i3 是一个窗口管理器,与功能齐全的桌面环境不同,它并不规定您应该使用的应用程序。您是否想使用 Xfce 的 Thunar 作为文件管理器?GNOME 的 gedit 去编辑文本? i3 并不在乎。选择对您的工作流最有意义的工具,i3 将以相同的方式管理它们。

2、屏幕实际使用面积

作为平铺式窗口管理器,i3 将自动 “平铺”,以不重叠的方式定位窗口,类似于在墙上放置瓷砖。因为您不需要担心窗口定位,i3 一般会更好地利用您的屏幕空间。它还可以让您更快地找到您需要的东西。

对于这种情况有很多有用的例子。例如,系统管理员可以打开多个终端来同时监视或在不同的远程系统上工作;开发人员可以使用他们最喜欢的 IDE 或编辑器和几个终端来测试他们的程序。

此外,i3 具有灵活性。如果您需要为特定窗口提供更多空间,请启用全屏模式或切换到其他布局,如堆叠或选项卡式(标签式)。

3、键盘式工作流程

i3 广泛使用键盘快捷键来控制环境的不同方面。其中包括打开终端和其他程序、调整大小和定位窗口、更改布局,甚至退出 i3。当您开始使用 i3 时,您需要记住其中的一些快捷方式才能使用,随着时间的推移,您会使用更多的快捷方式。

主要好处是,您不需要经常在键盘和鼠标之间切换。通过练习,您将提高工作流程的速度和效率。

例如, 要打开新的终端,请按 <SUPER>+<ENTER>。由于窗口是自动定位的,您可以立即开始键入命令。结合一个很好的终端文本编辑器(如 Vim)和一个以面向键盘的浏览器,形成一个完全由键盘驱动的工作流程。

在 i3 中,您可以为所有内容定义快捷方式。下面是一些示例:

  • 打开终端
  • 打开浏览器
  • 更改布局
  • 调整窗口大小
  • 控制音乐播放器
  • 切换工作区

现在我已经习惯了这个工作形式,我已无法回到了常规的桌面环境。

4、灵活

i3 力求极简,使用很少的系统资源,但这并不意味着它不能变漂亮。i3 是灵活且可通过多种方式进行自定义以改善视觉体验。因为 i3 是一个窗口管理器,所以它没有提供启用自定义的工具,你需要外部工具来实现这一点。一些例子:

  • feh 定义桌面的背景图片。
  • 使用合成器管理器,如 compton 以启用窗口淡入淡出和透明度等效果。
  • dmenurofi 以启用可从键盘快捷方式启动的可自定义菜单。
  • dunst 用于桌面通知。

i3 是可完全配置的,您可以通过更新默认配置文件来控制它的各个方面。从更改所有键盘快捷键,到重新定义工作区的名称,再到修改状态栏,您都可以使 i3 以任何最适合您需要的方式运行。

 title=

i3 与 rofi 菜单和 dunst 桌面通知。

最后,对于更高级的用户,i3 提供了完整的进程间通信(IPC)接口,允许您使用偏好的语言来开发脚本或程序,以实现更多的自定义选项。

5、工作空间

在 i3 中,工作区是对窗口进行分组的一种简单方法。您可以根据您的工作流以不同的方式对它们进行分组。例如,您可以将浏览器放在一个工作区上,终端放在另一个工作区上,将电子邮件客户端放在第三个工作区上等等。您甚至可以更改 i3 的配置,以便始终将特定应用程序分配给它们自己的工作区。

切换工作区既快速又简单。像 i3 中的惯例,使用键盘快捷方式执行此操作。按 <SUPER>+num 切换到工作区 num 。如果您养成了始终将应用程序组的窗口分配到同一个工作区的习惯,则可以在它们之间快速切换,这使得工作区成为非常有用的功能。

此外,还可以使用工作区来控制多监视器环境,其中每个监视器都有个初始工作区。如果切换到该工作区,则切换到该监视器,而无需让手离开键盘。

最后,i3 中还有另一种特殊类型的工作空间:the scratchpad(便笺簿)。它是一个不可见的工作区,通过按快捷方式显示在其他工作区的中间。这是一种访问您经常使用的窗口或程序的方便方式,如电子邮件客户端或音乐播放器。

尝试一下吧

如果您重视简洁和效率,并且不惮于使用键盘,i3 就是您的窗口管理器。有人说是为高级用户准备的,但情况不一定如此。你需要学习一些基本的快捷方式来度过开始的阶段,不久就会越来越自然并且不假思索地使用它们。

这篇文章只是浅浅谈及了 i3 能做的事情。欲了解更多详情,请参阅 i3 的文档


via: https://opensource.com/article/18/8/i3-tiling-window-manager

作者:Ricardo Gerardi 选题:lujun9972 译者:lixinyuxx 校对:wxy

本文由 LCTT 原创编译,Linux中国 荣誉推出

tcpdump 是一款灵活、功能强大的抓包工具,能有效地帮助排查网络故障问题。

以我作为管理员的经验,在网络连接中经常遇到十分难以排查的故障问题。对于这类情况,tcpdump 便能派上用场。

tcpdump 是一个命令行实用工具,允许你抓取和分析经过系统的流量数据包。它通常被用作于网络故障分析工具以及安全工具。

tcpdump 是一款强大的工具,支持多种选项和过滤规则,适用场景十分广泛。由于它是命令行工具,因此适用于在远程服务器或者没有图形界面的设备中收集数据包以便于事后分析。它可以在后台启动,也可以用 cron 等定时工具创建定时任务启用它。

本文中,我们将讨论 tcpdump 最常用的一些功能。

1、在 Linux 中安装 tcpdump

tcpdump 支持多种 Linux 发行版,所以你的系统中很有可能已经安装了它。用下面的命令检查一下是否已经安装了 tcpdump

$ which tcpdump
/usr/sbin/tcpdump

如果还没有安装 tcpdump,你可以用软件包管理器安装它。 例如,在 CentOS 或者 Red Hat Enterprise 系统中,用如下命令安装 tcpdump

$ sudo yum install -y tcpdump

tcpdump 依赖于 libpcap,该库文件用于捕获网络数据包。如果该库文件也没有安装,系统会根据依赖关系自动安装它。

现在你可以开始抓包了。

2、用 tcpdump 抓包

使用 tcpdump 抓包,需要管理员权限,因此下面的示例中绝大多数命令都是以 sudo 开头。

首先,先用 tcpdump -D 命令列出可以抓包的网络接口:

$ sudo tcpdump -D
1.eth0
2.virbr0
3.eth1
4.any (Pseudo-device that captures on all interfaces)
5.lo [Loopback]

如上所示,可以看到我的机器中所有可以抓包的网络接口。其中特殊接口 any 可用于抓取所有活动的网络接口的数据包。

我们就用如下命令先对 any 接口进行抓包:

$ sudo tcpdump -i any
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on any, link-type LINUX_SLL (Linux cooked), capture size 262144 bytes
09:56:18.293641 IP rhel75.localdomain.ssh > 192.168.64.1.56322: Flags [P.], seq 3770820720:3770820916, ack 3503648727, win 309, options [nop,nop,TS val 76577898 ecr 510770929], length 196
09:56:18.293794 IP 192.168.64.1.56322 > rhel75.localdomain.ssh: Flags [.], ack 196, win 391, options [nop,nop,TS val 510771017 ecr 76577898], length 0
09:56:18.295058 IP rhel75.59883 > gateway.domain: 2486+ PTR? 1.64.168.192.in-addr.arpa. (43)
09:56:18.310225 IP gateway.domain > rhel75.59883: 2486 NXDomain* 0/1/0 (102)
09:56:18.312482 IP rhel75.49685 > gateway.domain: 34242+ PTR? 28.64.168.192.in-addr.arpa. (44)
09:56:18.322425 IP gateway.domain > rhel75.49685: 34242 NXDomain* 0/1/0 (103)
09:56:18.323164 IP rhel75.56631 > gateway.domain: 29904+ PTR? 1.122.168.192.in-addr.arpa. (44)
09:56:18.323342 IP rhel75.localdomain.ssh > 192.168.64.1.56322: Flags [P.], seq 196:584, ack 1, win 309, options [nop,nop,TS val 76577928 ecr 510771017], length 388
09:56:18.323563 IP 192.168.64.1.56322 > rhel75.localdomain.ssh: Flags [.], ack 584, win 411, options [nop,nop,TS val 510771047 ecr 76577928], length 0
09:56:18.335569 IP gateway.domain > rhel75.56631: 29904 NXDomain* 0/1/0 (103)
09:56:18.336429 IP rhel75.44007 > gateway.domain: 61677+ PTR? 98.122.168.192.in-addr.arpa. (45)
09:56:18.336655 IP gateway.domain > rhel75.44007: 61677* 1/0/0 PTR rhel75. (65)
09:56:18.337177 IP rhel75.localdomain.ssh > 192.168.64.1.56322: Flags [P.], seq 584:1644, ack 1, win 309, options [nop,nop,TS val 76577942 ecr 510771047], length 1060

---- SKIPPING LONG OUTPUT -----

09:56:19.342939 IP 192.168.64.1.56322 > rhel75.localdomain.ssh: Flags [.], ack 1752016, win 1444, options [nop,nop,TS val 510772067 ecr 76578948], length 0
^C
9003 packets captured
9010 packets received by filter
7 packets dropped by kernel
$

tcpdump 会持续抓包直到收到中断信号。你可以按 Ctrl+C 来停止抓包。正如上面示例所示,tcpdump 抓取了超过 9000 个数据包。在这个示例中,由于我是通过 ssh 连接到服务器,所以 tcpdump 也捕获了所有这类数据包。-c 选项可以用于限制 tcpdump 抓包的数量:

$ sudo tcpdump -i any -c 5
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on any, link-type LINUX_SLL (Linux cooked), capture size 262144 bytes
11:21:30.242740 IP rhel75.localdomain.ssh > 192.168.64.1.56322: Flags [P.], seq 3772575680:3772575876, ack 3503651743, win 309, options [nop,nop,TS val 81689848 ecr 515883153], length 196
11:21:30.242906 IP 192.168.64.1.56322 > rhel75.localdomain.ssh: Flags [.], ack 196, win 1443, options [nop,nop,TS val 515883235 ecr 81689848], length 0
11:21:30.244442 IP rhel75.43634 > gateway.domain: 57680+ PTR? 1.64.168.192.in-addr.arpa. (43)
11:21:30.244829 IP gateway.domain > rhel75.43634: 57680 NXDomain 0/0/0 (43)
11:21:30.247048 IP rhel75.33696 > gateway.domain: 37429+ PTR? 28.64.168.192.in-addr.arpa. (44)
5 packets captured
12 packets received by filter
0 packets dropped by kernel
$

如上所示,tcpdump 在抓取 5 个数据包后自动停止了抓包。这在有些场景中十分有用 —— 比如你只需要抓取少量的数据包用于分析。当我们需要使用过滤规则抓取特定的数据包(如下所示)时,-c 的作用就十分突出了。

在上面示例中,tcpdump 默认是将 IP 地址和端口号解析为对应的接口名以及服务协议名称。而通常在网络故障排查中,使用 IP 地址和端口号更便于分析问题;用 -n 选项显示 IP 地址,-nn 选项显示端口号:

$ sudo tcpdump -i any -c5 -nn
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on any, link-type LINUX_SLL (Linux cooked), capture size 262144 bytes
23:56:24.292206 IP 192.168.64.28.22 > 192.168.64.1.35110: Flags [P.], seq 166198580:166198776, ack 2414541257, win 309, options [nop,nop,TS val 615664 ecr 540031155], length 196
23:56:24.292357 IP 192.168.64.1.35110 > 192.168.64.28.22: Flags [.], ack 196, win 1377, options [nop,nop,TS val 540031229 ecr 615664], length 0
23:56:24.292570 IP 192.168.64.28.22 > 192.168.64.1.35110: Flags [P.], seq 196:568, ack 1, win 309, options [nop,nop,TS val 615664 ecr 540031229], length 372
23:56:24.292655 IP 192.168.64.1.35110 > 192.168.64.28.22: Flags [.], ack 568, win 1400, options [nop,nop,TS val 540031229 ecr 615664], length 0
23:56:24.292752 IP 192.168.64.28.22 > 192.168.64.1.35110: Flags [P.], seq 568:908, ack 1, win 309, options [nop,nop,TS val 615664 ecr 540031229], length 340
5 packets captured
6 packets received by filter
0 packets dropped by kernel

如上所示,抓取的数据包中显示 IP 地址和端口号。这样还可以阻止 tcpdump 发出 DNS 查找,有助于在网络故障排查中减少数据流量。

现在你已经会抓包了,让我们来分析一下这些抓包输出的含义吧。

3、理解抓取的报文

tcpdump 能够抓取并解码多种协议类型的数据报文,如 TCP、UDP、ICMP 等等。虽然这里我们不可能介绍所有的数据报文类型,但可以分析下 TCP 类型的数据报文,来帮助你入门。更多有关 tcpdump 的详细介绍可以参考其 帮助手册tcpdump 抓取的 TCP 报文看起来如下:

08:41:13.729687 IP 192.168.64.28.22 > 192.168.64.1.41916: Flags [P.], seq 196:568, ack 1, win 309, options [nop,nop,TS val 117964079 ecr 816509256], length 372

具体的字段根据不同的报文类型会有不同,但上面这个例子是一般的格式形式。

第一个字段 08:41:13.729687 是该数据报文被抓取的系统本地时间戳。

然后,IP 是网络层协议类型,这里是 IPv4,如果是 IPv6 协议,该字段值是 IP6

192.168.64.28.22 是源 ip 地址和端口号,紧跟其后的是目的 ip 地址和其端口号,这里是 192.168.64.1.41916

在源 IP 和目的 IP 之后,可以看到是 TCP 报文标记段 Flags [P.]。该字段通常取值如下:

标志类型描述
SSYNConnection Start
FFINConnection Finish
PPUSHData push
RRSTConnection reset
.ACKAcknowledgment

该字段也可以是这些值的组合,例如 [S.] 代表 SYN-ACK 数据包。

接下来是该数据包中数据的序列号。对于抓取的第一个数据包,该字段值是一个绝对数字,后续包使用相对数值,以便更容易查询跟踪。例如此处 seq 196:568 代表该数据包包含该数据流的第 196 到 568 字节。

接下来是 ack 值:ack 1。该数据包是数据发送方,ack 值为 1。在数据接收方,该字段代表数据流上的下一个预期字节数据,例如,该数据流中下一个数据包的 ack 值应该是 568。

接下来字段是接收窗口大小 win 309,它表示接收缓冲区中可用的字节数,后跟 TCP 选项如 MSS(最大段大小)或者窗口比例值。更详尽的 TCP 协议内容请参考 Transmission Control Protocol(TCP) Parameters

最后,length 372 代表数据包有效载荷字节长度。这个长度和 seq 序列号中字节数值长度是不一样的。

现在让我们学习如何过滤数据报文以便更容易的分析定位问题。

4、过滤数据包

正如上面所提,tcpdump 可以抓取很多种类型的数据报文,其中很多可能和我们需要查找的问题并没有关系。举个例子,假设你正在定位一个与 web 服务器连接的网络问题,就不必关系 SSH 数据报文,因此在抓包结果中过滤掉 SSH 报文可能更便于你分析问题。

tcpdump 有很多参数选项可以设置数据包过滤规则,例如根据源 IP 以及目的 IP 地址,端口号,协议等等规则来过滤数据包。下面就介绍一些最常用的过滤方法。

协议

在命令中指定协议便可以按照协议类型来筛选数据包。比方说用如下命令只要抓取 ICMP 报文:

$ sudo tcpdump -i any -c5 icmp
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on any, link-type LINUX_SLL (Linux cooked), capture size 262144 bytes

然后再打开一个终端,去 ping 另一台机器:

$ ping opensource.com
PING opensource.com (54.204.39.132) 56(84) bytes of data.
64 bytes from ec2-54-204-39-132.compute-1.amazonaws.com (54.204.39.132): icmp_seq=1 ttl=47 time=39.6 ms

回到运行 tcpdump 命令的终端中,可以看到它筛选出了 ICMP 报文。这里 tcpdump 并没有显示有关 opensource.com 的域名解析数据包:

09:34:20.136766 IP rhel75 > ec2-54-204-39-132.compute-1.amazonaws.com: ICMP echo request, id 20361, seq 1, length 64
09:34:20.176402 IP ec2-54-204-39-132.compute-1.amazonaws.com > rhel75: ICMP echo reply, id 20361, seq 1, length 64
09:34:21.140230 IP rhel75 > ec2-54-204-39-132.compute-1.amazonaws.com: ICMP echo request, id 20361, seq 2, length 64
09:34:21.180020 IP ec2-54-204-39-132.compute-1.amazonaws.com > rhel75: ICMP echo reply, id 20361, seq 2, length 64
09:34:22.141777 IP rhel75 > ec2-54-204-39-132.compute-1.amazonaws.com: ICMP echo request, id 20361, seq 3, length 64
5 packets captured
5 packets received by filter
0 packets dropped by kernel

主机

host 参数只抓取和特定主机相关的数据包:

$ sudo tcpdump -i any -c5 -nn host 54.204.39.132
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on any, link-type LINUX_SLL (Linux cooked), capture size 262144 bytes
09:54:20.042023 IP 192.168.122.98.39326 > 54.204.39.132.80: Flags [S], seq 1375157070, win 29200, options [mss 1460,sackOK,TS val 122350391 ecr 0,nop,wscale 7], length 0
09:54:20.088127 IP 54.204.39.132.80 > 192.168.122.98.39326: Flags [S.], seq 1935542841, ack 1375157071, win 28960, options [mss 1460,sackOK,TS val 522713542 ecr 122350391,nop,wscale 9], length 0
09:54:20.088204 IP 192.168.122.98.39326 > 54.204.39.132.80: Flags [.], ack 1, win 229, options [nop,nop,TS val 122350437 ecr 522713542], length 0
09:54:20.088734 IP 192.168.122.98.39326 > 54.204.39.132.80: Flags [P.], seq 1:113, ack 1, win 229, options [nop,nop,TS val 122350438 ecr 522713542], length 112: HTTP: GET / HTTP/1.1
09:54:20.129733 IP 54.204.39.132.80 > 192.168.122.98.39326: Flags [.], ack 113, win 57, options [nop,nop,TS val 522713552 ecr 122350438], length 0
5 packets captured
5 packets received by filter
0 packets dropped by kernel

如上所示,只抓取和显示与 54.204.39.132 有关的数据包。

端口号

tcpdump 可以根据服务类型或者端口号来筛选数据包。例如,抓取和 HTTP 服务相关的数据包:

$ sudo tcpdump -i any -c5 -nn port 80
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on any, link-type LINUX_SLL (Linux cooked), capture size 262144 bytes
09:58:28.790548 IP 192.168.122.98.39330 > 54.204.39.132.80: Flags [S], seq 1745665159, win 29200, options [mss 1460,sackOK,TS val 122599140 ecr 0,nop,wscale 7], length 0
09:58:28.834026 IP 54.204.39.132.80 > 192.168.122.98.39330: Flags [S.], seq 4063583040, ack 1745665160, win 28960, options [mss 1460,sackOK,TS val 522775728 ecr 122599140,nop,wscale 9], length 0
09:58:28.834093 IP 192.168.122.98.39330 > 54.204.39.132.80: Flags [.], ack 1, win 229, options [nop,nop,TS val 122599183 ecr 522775728], length 0
09:58:28.834588 IP 192.168.122.98.39330 > 54.204.39.132.80: Flags [P.], seq 1:113, ack 1, win 229, options [nop,nop,TS val 122599184 ecr 522775728], length 112: HTTP: GET / HTTP/1.1
09:58:28.878445 IP 54.204.39.132.80 > 192.168.122.98.39330: Flags [.], ack 113, win 57, options [nop,nop,TS val 522775739 ecr 122599184], length 0
5 packets captured
5 packets received by filter
0 packets dropped by kernel

IP 地址/主机名

同样,你也可以根据源 IP 地址或者目的 IP 地址或者主机名来筛选数据包。例如抓取源 IP 地址为 192.168.122.98 的数据包:

$ sudo tcpdump -i any -c5 -nn src 192.168.122.98
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on any, link-type LINUX_SLL (Linux cooked), capture size 262144 bytes
10:02:15.220824 IP 192.168.122.98.39436 > 192.168.122.1.53: 59332+ A? opensource.com. (32)
10:02:15.220862 IP 192.168.122.98.39436 > 192.168.122.1.53: 20749+ AAAA? opensource.com. (32)
10:02:15.364062 IP 192.168.122.98.39334 > 54.204.39.132.80: Flags [S], seq 1108640533, win 29200, options [mss 1460,sackOK,TS val 122825713 ecr 0,nop,wscale 7], length 0
10:02:15.409229 IP 192.168.122.98.39334 > 54.204.39.132.80: Flags [.], ack 669337581, win 229, options [nop,nop,TS val 122825758 ecr 522832372], length 0
10:02:15.409667 IP 192.168.122.98.39334 > 54.204.39.132.80: Flags [P.], seq 0:112, ack 1, win 229, options [nop,nop,TS val 122825759 ecr 522832372], length 112: HTTP: GET / HTTP/1.1
5 packets captured
5 packets received by filter
0 packets dropped by kernel

注意此处示例中抓取了来自源 IP 地址 192.168.122.98 的 53 端口以及 80 端口的数据包,它们的应答包没有显示出来因为那些包的源 IP 地址已经变了。

相对的,使用 dst 就是按目的 IP/主机名来筛选数据包。

$ sudo tcpdump -i any -c5 -nn dst 192.168.122.98
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on any, link-type LINUX_SLL (Linux cooked), capture size 262144 bytes
10:05:03.572931 IP 192.168.122.1.53 > 192.168.122.98.47049: 2248 1/0/0 A 54.204.39.132 (48)
10:05:03.572944 IP 192.168.122.1.53 > 192.168.122.98.47049: 33770 0/0/0 (32)
10:05:03.621833 IP 54.204.39.132.80 > 192.168.122.98.39338: Flags [S.], seq 3474204576, ack 3256851264, win 28960, options [mss 1460,sackOK,TS val 522874425 ecr 122993922,nop,wscale 9], length 0
10:05:03.667767 IP 54.204.39.132.80 > 192.168.122.98.39338: Flags [.], ack 113, win 57, options [nop,nop,TS val 522874436 ecr 122993972], length 0
10:05:03.672221 IP 54.204.39.132.80 > 192.168.122.98.39338: Flags [P.], seq 1:643, ack 113, win 57, options [nop,nop,TS val 522874437 ecr 122993972], length 642: HTTP: HTTP/1.1 302 Found
5 packets captured
5 packets received by filter
0 packets dropped by kernel

多条件筛选

当然,可以使用多条件组合来筛选数据包,使用 and 以及 or 逻辑操作符来创建过滤规则。例如,筛选来自源 IP 地址 192.168.122.98 的 HTTP 数据包:

$ sudo tcpdump -i any -c5 -nn src 192.168.122.98 and port 80
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on any, link-type LINUX_SLL (Linux cooked), capture size 262144 bytes
10:08:00.472696 IP 192.168.122.98.39342 > 54.204.39.132.80: Flags [S], seq 2712685325, win 29200, options [mss 1460,sackOK,TS val 123170822 ecr 0,nop,wscale 7], length 0
10:08:00.516118 IP 192.168.122.98.39342 > 54.204.39.132.80: Flags [.], ack 268723504, win 229, options [nop,nop,TS val 123170865 ecr 522918648], length 0
10:08:00.516583 IP 192.168.122.98.39342 > 54.204.39.132.80: Flags [P.], seq 0:112, ack 1, win 229, options [nop,nop,TS val 123170866 ecr 522918648], length 112: HTTP: GET / HTTP/1.1
10:08:00.567044 IP 192.168.122.98.39342 > 54.204.39.132.80: Flags [.], ack 643, win 239, options [nop,nop,TS val 123170916 ecr 522918661], length 0
10:08:00.788153 IP 192.168.122.98.39342 > 54.204.39.132.80: Flags [F.], seq 112, ack 643, win 239, options [nop,nop,TS val 123171137 ecr 522918661], length 0
5 packets captured
5 packets received by filter
0 packets dropped by kernel

你也可以使用括号来创建更为复杂的过滤规则,但在 shell 中请用引号包含你的过滤规则以防止被识别为 shell 表达式:

$ sudo tcpdump -i any -c5 -nn "port 80 and (src 192.168.122.98 or src 54.204.39.132)"
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on any, link-type LINUX_SLL (Linux cooked), capture size 262144 bytes
10:10:37.602214 IP 192.168.122.98.39346 > 54.204.39.132.80: Flags [S], seq 871108679, win 29200, options [mss 1460,sackOK,TS val 123327951 ecr 0,nop,wscale 7], length 0
10:10:37.650651 IP 54.204.39.132.80 > 192.168.122.98.39346: Flags [S.], seq 854753193, ack 871108680, win 28960, options [mss 1460,sackOK,TS val 522957932 ecr 123327951,nop,wscale 9], length 0
10:10:37.650708 IP 192.168.122.98.39346 > 54.204.39.132.80: Flags [.], ack 1, win 229, options [nop,nop,TS val 123328000 ecr 522957932], length 0
10:10:37.651097 IP 192.168.122.98.39346 > 54.204.39.132.80: Flags [P.], seq 1:113, ack 1, win 229, options [nop,nop,TS val 123328000 ecr 522957932], length 112: HTTP: GET / HTTP/1.1
10:10:37.692900 IP 54.204.39.132.80 > 192.168.122.98.39346: Flags [.], ack 113, win 57, options [nop,nop,TS val 522957942 ecr 123328000], length 0
5 packets captured
5 packets received by filter
0 packets dropped by kernel

该例子中我们只抓取了来自源 IP 为 192.168.122.98 或者 54.204.39.132 的 HTTP (端口号80)的数据包。使用该方法就很容易抓取到数据流中交互双方的数据包了。

5、检查数据包内容

在以上的示例中,我们只按数据包头部的信息来建立规则筛选数据包,例如源地址、目的地址、端口号等等。有时我们需要分析网络连接问题,可能需要分析数据包中的内容来判断什么内容需要被发送、什么内容需要被接收等。tcpdump 提供了两个选项可以查看数据包内容,-X 以十六进制打印出数据报文内容,-A 打印数据报文的 ASCII 值。

例如,HTTP 请求报文内容如下:

$ sudo tcpdump -i any -c10 -nn -A port 80
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on any, link-type LINUX_SLL (Linux cooked), capture size 262144 bytes
13:02:14.871803 IP 192.168.122.98.39366 > 54.204.39.132.80: Flags [S], seq 2546602048, win 29200, options [mss 1460,sackOK,TS val 133625221 ecr 0,nop,wscale 7], length 0
E..<..@[email protected].'[email protected]............
............................
13:02:14.910734 IP 54.204.39.132.80 > 192.168.122.98.39366: Flags [S.], seq 1877348646, ack 2546602049, win 28960, options [mss 1460,sackOK,TS val 525532247 ecr 133625221,nop,wscale 9], length 0
E..<..@./..a6.'...zb.P..o..&...A..q a..........
.R.W.......     ................
13:02:14.910832 IP 192.168.122.98.39366 > 54.204.39.132.80: Flags [.], ack 1, win 229, options [nop,nop,TS val 133625260 ecr 525532247], length 0
E..4..@[email protected].'....P...Ao..'...........
.....R.W................
13:02:14.911808 IP 192.168.122.98.39366 > 54.204.39.132.80: Flags [P.], seq 1:113, ack 1, win 229, options [nop,nop,TS val 133625261 ecr 525532247], length 112: HTTP: GET / HTTP/1.1
E.....@[email protected].'....P...Ao..'...........
.....R.WGET / HTTP/1.1
User-Agent: Wget/1.14 (linux-gnu)
Accept: */*
Host: opensource.com
Connection: Keep-Alive

................
13:02:14.951199 IP 54.204.39.132.80 > 192.168.122.98.39366: Flags [.], ack 113, win 57, options [nop,nop,TS val 525532257 ecr 133625261], length 0
E..4.F@./.."6.'...zb.P..o..'.......9.2.....
.R.a....................
13:02:14.955030 IP 54.204.39.132.80 > 192.168.122.98.39366: Flags [P.], seq 1:643, ack 113, win 57, options [nop,nop,TS val 525532258 ecr 133625261], length 642: HTTP: HTTP/1.1 302 Found
E....G@./...6.'...zb.P..o..'.......9.......
.R.b....HTTP/1.1 302 Found
Server: nginx
Date: Sun, 23 Sep 2018 17:02:14 GMT
Content-Type: text/html; charset=iso-8859-1
Content-Length: 207
X-Content-Type-Options: nosniff
Location: https://opensource.com/
Cache-Control: max-age=1209600
Expires: Sun, 07 Oct 2018 17:02:14 GMT
X-Request-ID: v-6baa3acc-bf52-11e8-9195-22000ab8cf2d
X-Varnish: 632951979
Age: 0
Via: 1.1 varnish (Varnish/5.2)
X-Cache: MISS
Connection: keep-alive

<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
<html><head>
<title>302 Found</title>
</head><body>
<h1>Found</h1>
<p>The document has moved <a href="https://opensource.com/">here</a>.</p>
</body></html>
................
13:02:14.955083 IP 192.168.122.98.39366 > 54.204.39.132.80: Flags [.], ack 643, win 239, options [nop,nop,TS val 133625304 ecr 525532258], length 0
E..4..@[email protected].'....P....o..............
.....R.b................
13:02:15.195524 IP 192.168.122.98.39366 > 54.204.39.132.80: Flags [F.], seq 113, ack 643, win 239, options [nop,nop,TS val 133625545 ecr 525532258], length 0
E..4..@[email protected].'....P....o..............
.....R.b................
13:02:15.236592 IP 54.204.39.132.80 > 192.168.122.98.39366: Flags [F.], seq 643, ack 114, win 57, options [nop,nop,TS val 525532329 ecr 133625545], length 0
E..4.H@./.. 6.'...zb.P..o..........9.I.....
.R......................
13:02:15.236656 IP 192.168.122.98.39366 > 54.204.39.132.80: Flags [.], ack 644, win 239, options [nop,nop,TS val 133625586 ecr 525532329], length 0
E..4..@[email protected].'....P....o..............
.....R..................
10 packets captured
10 packets received by filter
0 packets dropped by kernel

这对定位一些普通 HTTP 调用 API 接口的问题很有用。当然如果是加密报文,这个输出也就没多大用了。

6、保存抓包数据

tcpdump 提供了保存抓包数据的功能以便后续分析数据包。例如,你可以夜里让它在那里抓包,然后早上起来再去分析它。同样当有很多数据包时,显示过快也不利于分析,将数据包保存下来,更有利于分析问题。

使用 -w 选项来保存数据包而不是在屏幕上显示出抓取的数据包:

$ sudo tcpdump -i any -c10 -nn -w webserver.pcap port 80
[sudo] password for ricardo:
tcpdump: listening on any, link-type LINUX_SLL (Linux cooked), capture size 262144 bytes
10 packets captured
10 packets received by filter
0 packets dropped by kernel

该命令将抓取的数据包保存到文件 webserver.pcap。后缀名 pcap 表示文件是抓取的数据包格式。

正如示例中所示,保存数据包到文件中时屏幕上就没有任何有关数据报文的输出,其中 -c10 表示抓取到 10 个数据包后就停止抓包。如果想有一些反馈来提示确实抓取到了数据包,可以使用 -v 选项。

tcpdump 将数据包保存在二进制文件中,所以不能简单的用文本编辑器去打开它。使用 -r 选项参数来阅读该文件中的报文内容:

$ tcpdump -nn -r webserver.pcap
reading from file webserver.pcap, link-type LINUX_SLL (Linux cooked)
13:36:57.679494 IP 192.168.122.98.39378 > 54.204.39.132.80: Flags [S], seq 3709732619, win 29200, options [mss 1460,sackOK,TS val 135708029 ecr 0,nop,wscale 7], length 0
13:36:57.718932 IP 54.204.39.132.80 > 192.168.122.98.39378: Flags [S.], seq 1999298316, ack 3709732620, win 28960, options [mss 1460,sackOK,TS val 526052949 ecr 135708029,nop,wscale 9], length 0
13:36:57.719005 IP 192.168.122.98.39378 > 54.204.39.132.80: Flags [.], ack 1, win 229, options [nop,nop,TS val 135708068 ecr 526052949], length 0
13:36:57.719186 IP 192.168.122.98.39378 > 54.204.39.132.80: Flags [P.], seq 1:113, ack 1, win 229, options [nop,nop,TS val 135708068 ecr 526052949], length 112: HTTP: GET / HTTP/1.1
13:36:57.756979 IP 54.204.39.132.80 > 192.168.122.98.39378: Flags [.], ack 113, win 57, options [nop,nop,TS val 526052959 ecr 135708068], length 0
13:36:57.760122 IP 54.204.39.132.80 > 192.168.122.98.39378: Flags [P.], seq 1:643, ack 113, win 57, options [nop,nop,TS val 526052959 ecr 135708068], length 642: HTTP: HTTP/1.1 302 Found
13:36:57.760182 IP 192.168.122.98.39378 > 54.204.39.132.80: Flags [.], ack 643, win 239, options [nop,nop,TS val 135708109 ecr 526052959], length 0
13:36:57.977602 IP 192.168.122.98.39378 > 54.204.39.132.80: Flags [F.], seq 113, ack 643, win 239, options [nop,nop,TS val 135708327 ecr 526052959], length 0
13:36:58.022089 IP 54.204.39.132.80 > 192.168.122.98.39378: Flags [F.], seq 643, ack 114, win 57, options [nop,nop,TS val 526053025 ecr 135708327], length 0
13:36:58.022132 IP 192.168.122.98.39378 > 54.204.39.132.80: Flags [.], ack 644, win 239, options [nop,nop,TS val 135708371 ecr 526053025], length 0
$

这里不需要管理员权限 sudo 了,因为此刻并不是在网络接口处抓包。

你还可以使用我们讨论过的任何过滤规则来过滤文件中的内容,就像使用实时数据一样。 例如,通过执行以下命令从源 IP 地址 54.204.39.132 检查文件中的数据包:

$ tcpdump -nn -r webserver.pcap src 54.204.39.132
reading from file webserver.pcap, link-type LINUX_SLL (Linux cooked)
13:36:57.718932 IP 54.204.39.132.80 > 192.168.122.98.39378: Flags [S.], seq 1999298316, ack 3709732620, win 28960, options [mss 1460,sackOK,TS val 526052949 ecr 135708029,nop,wscale 9], length 0
13:36:57.756979 IP 54.204.39.132.80 > 192.168.122.98.39378: Flags [.], ack 113, win 57, options [nop,nop,TS val 526052959 ecr 135708068], length 0
13:36:57.760122 IP 54.204.39.132.80 > 192.168.122.98.39378: Flags [P.], seq 1:643, ack 113, win 57, options [nop,nop,TS val 526052959 ecr 135708068], length 642: HTTP: HTTP/1.1 302 Found
13:36:58.022089 IP 54.204.39.132.80 > 192.168.122.98.39378: Flags [F.], seq 643, ack 114, win 57, options [nop,nop,TS val 526053025 ecr 135708327], length 0

下一步做什么?

以上的基本功能已经可以帮助你使用强大的 tcpdump 抓包工具了。更多的内容请参考 tcpdump 网站 以及它的 帮助文件

tcpdump 命令行工具为分析网络流量数据包提供了强大的灵活性。如果需要使用图形工具来抓包请参考 Wireshark

Wireshark 还可以用来读取 tcpdump 保存的 pcap 文件。你可以使用 tcpdump 命令行在没有 GUI 界面的远程机器上抓包然后在 Wireshark 中分析数据包。


via: https://opensource.com/article/18/10/introduction-tcpdump

作者:Ricardo Gerardi 选题:lujun9972 译者:jrg 校对:wxy

本文由 LCTT 原创编译,Linux中国 荣誉推出

zsh 提供了数之不尽的功能和特性,这里有五个可以让你在命令行效率暴增的方法。

Z shell(zsh)是 Linux 和类 Unix 系统中的一个命令解析器)。 它跟 sh (Bourne shell) 家族的其它解析器(如 bash 和 ksh)有着相似的特点,但它还提供了大量的高级特性以及强大的命令行编辑功能,如增强版 Tab 补全。

在这里不可能涉及到 zsh 的所有功能,描述它的特性需要好几百页。在本文中,我会列出 5 个技巧,让你通过在命令行使用 zsh 来提高你的生产力。

1、主题和插件

多年来,开源社区已经为 zsh 开发了数不清的主题和插件。主题是一个预定义提示符的配置,而插件则是一组常用的别名命令和函数,可以让你更方便的使用一种特定的命令或者编程语言。

如果你现在想开始用 zsh 的主题和插件,那么使用一种 zsh 的配置框架是你最快的入门方式。在众多的配置框架中,最受欢迎的则是 Oh My Zsh。在默认配置中,它就已经为 zsh 启用了一些合理的配置,同时它也自带上百个主题和插件。

主题会在你的命令行提示符之前添加一些有用的信息,比如你 Git 仓库的状态,或者是当前使用的 Python 虚拟环境,所以它会让你的工作更高效。只需要看到这些信息,你就不用再敲命令去重新获取它们,而且这些提示也相当酷炫。下图就是我选用的主题 Powerlevel9k

 title=

zsh 主题 Powerlevel9k

除了主题,Oh my Zsh 还自带了大量常用的 zsh 插件。比如,通过启用 Git 插件,你可以用一组简便的命令别名操作 Git, 比如

$ alias | grep -i git | sort -R | head -10
g=git
ga='git add'
gapa='git add --patch'
gap='git apply'
gdt='git diff-tree --no-commit-id --name-only -r'
gau='git add --update'
gstp='git stash pop'
gbda='git branch --no-color --merged | command grep -vE "^(\*|\s*(master|develop|dev)\s*$)" | command xargs -n 1 git branch -d'
gcs='git commit -S'
glg='git log --stat'

zsh 还有许多插件可以用于许多编程语言、打包系统和一些平时在命令行中常用的工具。以下是我 Ferdora 工作站中用到的插件表:

git golang fedora docker oc sudo vi-mode virtualenvwrapper

2、智能的命令别名

命令别名在 zsh 中十分有用。为你常用的命令定义别名可以节省你的打字时间。Oh My Zsh 默认配置了一些常用的命令别名,包括目录导航命令别名,为常用的命令添加额外的选项,比如:

ls='ls --color=tty'
grep='grep  --color=auto --exclude-dir={.bzr,CVS,.git,.hg,.svn}'

除了命令别名以外, zsh 还自带两种额外常用的别名类型:后缀别名和全局别名。

后缀别名可以让你基于文件后缀,在命令行中利用指定程序打开这个文件。比如,要用 vim 打开 YAML 文件,可以定义以下命令行别名:

alias -s {yml,yaml}=vim

现在,如果你在命令行中输入任何后缀名为 ymlyaml 文件, zsh 都会用 vim 打开这个文件。

$ playbook.yml
# Opens file playbook.yml using vim

全局别名可以让你创建一个可在命令行的任何地方展开的别名,而不仅仅是在命令开始的时候。这个在你想替换常用文件名或者管道命令的时候就显得非常有用了。比如:

alias -g G='| grep -i'

要使用这个别名,只要你在想用管道命令的时候输入 G 就好了:

$ ls -l G do
drwxr-xr-x.  5 rgerardi rgerardi 4096 Aug  7 14:08 Documents
drwxr-xr-x.  6 rgerardi rgerardi 4096 Aug 24 14:51 Downloads

接着,我们就来看看 zsh 是如何导航文件系统的。

3、便捷的目录导航

当你使用命令行的时候,在不同的目录之间切换访问是最常见的工作了。 zsh 提供了一些十分有用的目录导航功能来简化这个操作。这些功能已经集成到 Oh My Zsh 中了, 而你可以用以下命令来启用它

setopt  autocd autopushd \ pushdignoredups

使用了上面的配置后,你就不用输入 cd 来切换目录了,只需要输入目录名称,zsh 就会自动切换到这个目录中:

$ pwd
/home/rgerardi
$ /tmp
$ pwd
/tmp

如果想要回退,只要输入 -:

zsh 会记录你访问过的目录,这样下次你就可以快速切换到这些目录中。如果想要看这个目录列表,只要输入 dirs -v

$ dirs -v
0       ~
1       /var/log
2       /var/opt
3       /usr/bin
4       /usr/local
5       /usr/lib
6       /tmp
7       ~/Projects/Opensource.com/zsh-5tips
8       ~/Projects
9       ~/Projects/ansible
10      ~/Documents

如果想要切换到这个列表中的其中一个目录,只需输入 ~## 代表目录在列表中的序号)就可以了。比如

$ pwd
/home/rgerardi
$ ~4
$ pwd
/usr/local

你甚至可以用别名组合这些命令,这样切换起来就变得更简单:

d='dirs -v | head -10'
1='cd -'
2='cd -2'
3='cd -3'
4='cd -4'
5='cd -5'
6='cd -6'
7='cd -7'
8='cd -8'
9='cd -9'

现在你可以通过输入 d 来查看这个目录列表的前10个,然后用目录的序号来进行切换:

$ d
0       /usr/local
1       ~
2       /var/log
3       /var/opt
4       /usr/bin
5       /usr/lib
6       /tmp
7       ~/Projects/Opensource.com/zsh-5tips
8       ~/Projects
9       ~/Projects/ansible
$ pwd
/usr/local
$ 6
/tmp
$ pwd
/tmp

最后,你可以在 zsh 中利用 Tab 来自动补全目录名称。你可以先输入目录的首字母,然后按 TAB 键来补全它们:

$ pwd
/home/rgerardi
$ p/o/z (TAB)
$ Projects/Opensource.com/zsh-5tips/

以上仅仅是 zsh 强大的 Tab 补全系统中的一个功能。接来下我们来探索它更多的功能。

4、先进的 Tab 补全

zsh 强大的补全系统是它的卖点之一。为了简便起见,我称它为 Tab 补全,然而在系统底层,它起到了几个作用。这里通常包括展开以及命令补全,我会在这里用讨论它们。如果想了解更多,详见 用户手册

在 Oh My Zsh 中,命令补全是默认启用的。要启用它,你只要在 .zshrc 文件中添加以下命令:

autoload -U compinit
compinit

zsh 的补全系统非常智能。它会尝试唯一提示可用在当前上下文环境中的项目 —— 比如,你输入了 cdTAB,zsh 只会为你提示目录名,因为它知道其它的项目放在 cd 后面没用。

反之,如果你使用与用户相关的命令便会提示用户名,而 ssh 或者 ping 这类则会提示主机名。

zsh 拥有一个巨大而又完整的库,因此它能识别许多不同的命令。比如,如果你使用 tar 命令, 你可以按 TAB 键,它会为你展示一个可以用于解压的文件列表:

$ tar -xzvf test1.tar.gz test1/file1 (TAB)
file1 file2

如果使用 git 的话,这里有个更高级的示例。在这个示例中,当你按 TAB 键, zsh 会自动补全当前库可以操作的文件:

$ ls
original  plan.txt  zsh-5tips.md  zsh_theme_small.png
$ git status
On branch master
Your branch is up to date with 'origin/master'.

Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git checkout -- <file>..." to discard changes in working directory)

        modified:   zsh-5tips.md

no changes added to commit (use "git add" and/or "git commit -a")
$ git add (TAB)
$ git add zsh-5tips.md

zsh 还能识别命令行选项,同时它只会提示与选中子命令相关的命令列表:

$ git commit - (TAB)
--all                  -a       -- stage all modified and deleted paths
--allow-empty                   -- allow recording an empty commit
--allow-empty-message           -- allow recording a commit with an empty message
--amend                         -- amend the tip of the current branch
--author                        -- override the author name used in the commit
--branch                        -- show branch information
--cleanup                       -- specify how the commit message should be cleaned up
--date                          -- override the author date used in the commit
--dry-run                       -- only show the list of paths that are to be committed or not, and any untracked
--edit                 -e       -- edit the commit message before committing
--file                 -F       -- read commit message from given file
--gpg-sign             -S       -- GPG-sign the commit
--include              -i       -- update the given files and commit the whole index
--interactive                   -- interactively update paths in the index file
--message              -m       -- use the given message as the commit message
... TRUNCATED ...

在按 TAB 键之后,你可以使用方向键来选择你想用的命令。现在你就不用记住所有的 git 命令项了。

zsh 还有很多有用的功能。当你用它的时候,你就知道哪些对你才是最有用的。

5、命令行编辑与历史记录

zsh 的命令行编辑功能也十分有用。默认条件下,它是模拟 emacs 编辑器的。如果你是跟我一样更喜欢用 vi/vim,你可以用以下命令启用 vi 的键绑定。

$ bindkey -v

如果你使用 Oh My Zsh,vi-mode 插件可以启用额外的绑定,同时会在你的命令提示符上增加 vi 的模式提示 —— 这个非常有用。

当启用 vi 的绑定后,你可以在命令行中使用 vi 命令进行编辑。比如,输入 ESC+/ 来查找命令行记录。在查找的时候,输入 n 来找下一个匹配行,输入 N 来找上一个。输入 ESC 后,常用的 vi 命令都可以使用,如输入 0 跳转到行首,输入 $ 跳转到行尾,输入 i 来插入文本,输入 a 来追加文本等等,即使是跟随的命令也同样有效,比如输入 cw 来修改单词。

除了命令行编辑,如果你想修改或重新执行之前使用过的命令,zsh 还提供几个常用的命令行历史功能。比如,你打错了一个命令,输入 fc,你可以在你偏好的编辑器中修复最后一条命令。使用哪个编辑是参照 $EDITOR 变量的,而默认是使用 vi。

另外一个有用的命令是 r, 它会重新执行上一条命令;而 r <WORD> 则会执行上一条包含 WORD 的命令。

最后,输入两个感叹号(!!),可以在命令行中回溯最后一条命令。这个十分有用,比如,当你忘记使用 sudo 去执行需要权限的命令时:

$ less /var/log/dnf.log
/var/log/dnf.log: Permission denied
$ sudo !!
$ sudo less /var/log/dnf.log

这个功能让查找并且重新执行之前命令的操作更加方便。

下一步呢?

这里仅仅介绍了几个可以让你提高生产率的 zsh 特性;其实还有更多功能有待你的发掘;想知道更多的信息,你可以访问以下的资源:

你有使用 zsh 提高生产力的技巧可以分享吗?我很乐意在下方评论中看到它们。


via: https://opensource.com/article/18/9/tips-productivity-zsh

作者:Ricardo Gerardi 选题:lujun9972 译者:tnuoccalanosrep 校对:wxy

本文由 LCTT 原创编译,Linux中国 荣誉推出

本篇文章会介绍如何在 Fedora 系统中,安装、配置、使用 i3 瓦片式桌面管理器。

在我的文章 i3 桌面让 Linux 更好的 5 个理由,我分享了选择 i3 桌面管理器 作为一种 Linux 桌面替代方案的最主要五个理由。

在本篇文章中,我将向大家展示,如何在 Fedora 28 上安装与简单配置 i3。

1、 安装

首先进入 Fedora 系统中,打开一个终端。使用 dnf 来安装需要的软件包,如下:

[ricardo@f28i3 ~]$ sudo dnf install -y i3 i3-ipc i3status i3lock dmenu terminator --exclude=rxvt-unicode
Last metadata expiration check: 1:36:15 ago on Wed 08 Aug 2018 12:04:31 PM EDT.
Dependencies resolved.
================================================================================================
 Package                     Arch         Version                           Repository     Size
================================================================================================
Installing:
 dmenu                       x86_64       4.8-1.fc28                        fedora         33 k
 i3                          x86_64       4.15-1.fc28                       fedora        323 k
 i3-ipc                      noarch       0.1.4-12.fc28                     fedora         14 k
 i3lock                      x86_64       2.9.1-2.fc28                      fedora         33 k
 i3status                    x86_64       2.12-1.fc28                       updates        62 k
 terminator                  noarch       1.91-4.fc28                       fedora        570 k
Installing dependencies:
 dzen2                       x86_64       0.8.5-21.20100104svn.fc28         fedora         60 k

... Skipping dependencies/install messages

Complete!
[ricardo@f28i3 ~]$

注意:在这个命令中,我排除了 rxvt-unicode 这个包,因为我更喜欢 terminator 作为我的终端模拟器。

据用户目前的系统状态,在命令执行过程中可能会安装很多依赖。等待所有的依赖安装完成,之后重启你的电脑。

2、 首次登录与初始化

在你的机器重启之后,你便可以第一次体验 i3 了。在 GNOME 显示管理器(GDM)屏幕,选择你的用户名,之后先别着急输密码,点击下方的密码输入框下方的小齿轮,之后选择 i3 而不是 GNOME,像下方这样:

输入你的密码,并点击 “Sign In”。在你第一次登入之后,会先看到 i3 的配置界面:

点击回车键就会在 $HOME/.config/i3 生成一个配置文件,之后你可以通过这个配置文件来定制化 i3 的一些行为。

在下一屏,你需要选择你的 Mod 键。这一步很关键,因为 Mod 键通常都会作为 i3 命令快捷键的发起键。按回车会选择 Win 键作为默认的 Mod 键。如果你的键盘没有 Win 键,用 Alt 键做替代,用方向键键选择后按回车键确认。

现在你就登录到了 i3 的系统中。由于 i3 是一个极简的窗口管理器,你会看到一个黑屏窗口,以及屏幕底端显示的状态栏:

接下来,让我们看看 i3 的如何实际使用。

3、 基本的快捷键

现在你已经登录到了 i3 会话中,你需要几个基本的快捷键来应对基本的操作。

大多数的 i3 快捷键都会用到之前配置的 Mod 键。在下面的例子中,当我提到 Mod 键,请根据情况使用你定义的做替换。通常使用 Win 键或者 Alt 键。

首先,要打开一个终端,可以使用 Mod+ENTER。重复打开几个终端,观察 i3 是如何自动将它们在桌面中排列。默认情况下, i3 会在水平的方向分割屏幕;使用 Mod + v 来垂直分割,再按 Mod + h 会恢复水平分割模式。

当需要启动其他的应用,按 Mod + d 来打开 dmenu,一个简单的文字应用菜单。默认情况下,dmenu 会呈现出所有在你 $PATH 中设置的应用。使用方向键来选择你想启动的应用,同时你可以键入应用的名称,来缩小选择的范围,之后按回车键来启动选择的应用。

如果你的应用没有提供退出的方法,你可以使用 i3 来关闭对应的窗口,通过按 Mod + Shift +q。注意,你可能会丢失未保存的工作内容。

最后,当你想关闭会话并退出 i3,按 Mod + Shift +e。之后会在窗口的上方提示你是否退出。点击 “Yes, exit i3” 退出,或选择 “X” 来取消。

这些就是 i3 中最基本的快捷键,如果想了解更多,请查阅官方文档

4、 替换 GDM

使用 i3 窗口管理器会降低你操作系统的内存占用;然而,Fedora 依然会使用 GDM 作为登录屏。GDM 会载入几个与 GNOME 相关的库从而占用内存。

如果你想进一步的降低你的内存占用,你可以使用一些更轻量级的显示管理器来替换 GDM,比如 lightdm :

[ricardo@f28i3 ~]$ sudo dnf install -y lightdm
[ricardo@f28i3 ~]$ sudo systemctl disable gdm
Removed /etc/systemd/system/display-manager.service.
[ricardo@f28i3 ~]$ sudo systemctl enable lightdm
Created symlink /etc/systemd/system/display-manager.service -> /usr/lib/systemd/system/lightdm.service.
[ricardo@f28i3 ~]$

之后重启你的机器来使用 Lightdm 的登录界面。

现在你可以继续登录并使用 i3了。


via: https://opensource.com/article/18/8/getting-started-i3-window-manager

作者:Ricardo Gerardi 选题:lujun9972 译者:sd886393 校对:wxy

本文由 LCTT 原创编译,Linux中国 荣誉推出