Himanshu Arora 发布的文章

这篇文章是 Vim 用户指南系列文章中的一篇:

Vim 编辑器提供了很多的特性,要想全部掌握它们很困难。然而,花费更多的时间在命令行编辑器上总是有帮助的。毫无疑问,和 Vim 用户们进行交流能够让你更快地学习新颖有创造性的东西。

注: 本文中用到的例子,使用的 Vim 版本是 7.4.52 。

1、 同时编辑多个文件

如果你是一名软件开发者或者把 Vim 作为主要的编辑器,那么可能很多时候你需要同时编辑多个文件。“ 紧跟 following ”是在同时编辑多个文件时可用的实用技巧。

不需要在多个 shell 界面中打开多个文件,你可以通过把多个文件的文件名作为 Vim 命令的参数从而在一个 shell 界面中打开多个文件。比如:

vim 文件1 文件2 文件3

第一个文件(例子中的文件1)将成为当前文件并被读入缓冲区。

在编辑器中,使用 :next:n 命令来移动到下一个文件,使用 :prev:N 命令返回上一个文件。如果想直接切换到第一个文件或最后一个文件,使用 :bf:bl 命令。特别地,如果想打开另外的文件并编辑,使用 :e 命令并把文件名作为参数(如果该文件不在当前目录中则需要完整路径做为参数)。

任何时候如果需要列出当前打开的所有文件,使用 :ls 命令。看下面展示的屏幕截图。

注意 ”%a” 表示文件在当前活动窗口,而 “#” 表示上一个活动窗口的文件。

2、 通过自动补全节约时间

想节约时间并提高效率吗?使用缩写吧。使用它们能够快速写出文件中多次出现、复杂冗长的词。在 Vim 中缩写命令写就是 ab

比如,当你运行下面的命令以后:

:ab asap as soon as possible

文件中出现的每一个 asap 都会被自动替换为 as soon as possible ,就像你自己输入的一样。

类似地,你可以使用缩写来更正常见的输入错误。比如,下面的命令

:ab recieve receive

将会自动更正拼写错误,就像你自己输入的一样。如果在一次特殊情况下你想阻止缩写展开或更正发生,那么你只需要在输入一个单词的最后一个字母以后按 Ctrl + V ,然后按空格键。

如果你想把刚才使用的缩写保存下来,从而当你下次使用 Vim 编辑器的时候可以再次使用,那么只需将完整的 ab 命令(没有起始的冒号)添加到 /etc/vim/vimrc 文件中。如果想删除某个缩写,你可以使用 una 命令。比如: una asap

3、 切分窗口便于复制/粘贴

有时,你需要从一个文件将一段代码或文本的一部分复制到另一个。当使用 GUI(图形界面)编辑器的时候,这很容易实现,但是当使用一个命令行编辑器的时候,这就变得比较困难并且很费时间。幸运的是, Vim 提供了一种高效、节约时间的方式来完成这件事。

打开两个文件中的一个然后切分 Vim 窗口来打开另一个文件。可以通过使用 split 命令并以文件名作为参数来完成这件事。比如:

:split test.c

上面的命令将分离窗口并打开文件 “test.c”

注意到 split 命令水平分离 Vim 窗口。如果你想垂直分离窗口,那么你可以使用 vsplit 命令。当同时打开了两个文件并从一个文件中复制好内容以后,按 Ctrl + W 切换到另一个文件,然后粘贴。

4、 保存一个没有权限的已编辑文件

有时候当你对一个文件做了大量更改以后才会意识到你对该文件仅有 只读 权限。

虽然把文件关闭,获取权限以后再重新打开是一种解决方法。但是如果你已经做了大量更改,这样做会很浪费时间,因为在这个过程中所有的更改都会丢失。 Vim 提供了一种方式来处理这种情况:你可以在编辑器中在保存文件前更改文件权限。命令是:

:w !sudo tee %

这个命令将会向你询问密码,就像在命令行中使用 sudo 一样,然后就能保存更改。

一个相关的技巧:在 Vim 中编辑一个文件的时候,如果想快速进入命令行提示符,可以在编辑器中运行 :sh 命令,从而你将进入一个交互的 shell 中。完成以后,运行 exit 命令可以快速回到 Vim 模式中。

5、 在复制/粘贴过程中保持缩进

大多数有经验的程序员在 Vim 上工作时都会启用自动缩进。虽然这是一个节约时间的做法,但是在粘贴一段已经缩进了的代码的时候会产生新的问题。比如,下图是我把一段已缩进代码粘贴到一个在自动缩进的 Vim 编辑器中打开的文件中时遇到的问题:

这个问题的解决方法是 pastetoggle 选项。在 /etc/vim/vimrc 文件中加入下面这行内容:

set pastetoggle=<F2>

然后当你在 插入 模式中准备粘贴代码前先按 F2 键,就不会再出现上图中的问题,这样会保留原始的缩进。注意,你可以用其他的任何键来代替 F2,如果它已经映射到了别的功能上。

结论

更进一步的提高你的 Vim 编辑器技巧的唯一方法是,在你日复一日的工作中使用命令行编辑器。留意那些耗时多的操作,然后尝试去寻找是否有编辑器命令可以很快地完成这个操作。


via: https://www.maketecheasier.com/vim-tips-tricks-for-experienced-users/

作者:Himanshu Arora 译者:ucasFL 校对:wxy

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

本文是 Vim 用户指南 系列的其中一篇:

Vim 编辑器是一个基于命令行的工具,是传奇编辑器 vi 的增强版。尽管图形界面的富文本编辑有很多,但是熟悉 Vim 对于每一位 Linux 的使用者都能有所帮助——无论你是经验丰富的系统管理员,还是刚上手树莓派的新手用户。

这个轻量级的编辑器是个非常强大的工具。在有经验的使用者手中,它能完成不可思议的任务。除了常规的文本编辑功能以外,它还支持一些进阶特性。例如,基于正则表达式的搜索和替换、编码转换,以及语法高亮、代码折叠等的编程特性。

使用 Vim 时有一个非常重要的一点需要注意,那就是按键的功能取决于编辑器当前的“模式”。例如,在“普通模式”输入字母j时,光标会向下移动一行。而当你在“插入模式”下输入字符,则只是正常的文字录入。

下面就是速查表,以便于你充分利用 Vim。

基本操作

快捷键功能
Esc从当前模式转换到“普通模式”。所有的键对应到命令。
i“插入模式”用于插入文字。回归按键的本职工作。
:“命令行模式” Vim 希望你输入类似于保存该文档命令的地方。

方向键

快捷键功能
h光标向左移动一个字符
jCtrl + J光标向下移动一行
kCtrl + P光标向上移动一行
l光标向右移动一个字符
0(数字 0)移动光标至本行开头
$移动光标至本行末尾
^移动光标至本行第一个非空字符处
w向前移动一个词 (上一个字母和数字组成的词之后)
W向前移动一个词 (以空格分隔的词)
5w向前移动五个词
b向后移动一个词 (下一个字母和数字组成的词之前)
B向后移动一个词 (以空格分隔的词)
5b向后移动五个词
G移动至文件末尾
gg移动至文件开头

浏览文档

快捷键功能
(跳转到上一句
)跳转到下一句
{跳转到上一段
}跳转到下一段
[[跳转到上一部分
]]跳转到下一部分
[]跳转到上一部分的末尾
][跳转到上一部分的开头

插入文本

快捷键功能
a在光标后插入文本
A在行末插入文本
i在光标前插入文本
o(小写字母 o)在光标下方新开一行
O(大写字母 O)在光标上方新开一行

特殊插入

快捷键功能
:r [filename]在光标下方插入文件 [filename] 的内容
:r ![command]执行命令 [command] ,并将输出插入至光标下方

删除文本

快捷键功能
x删除光标处字符
dw删除一个词
d0删至行首
d$删至行末
d)删至句末
dgg删至文件开头
dG删至文件末尾
dd删除该行
3dd删除三行

简单替换文本

快捷键功能
r{text}将光标处的字符替换成 {text}
R进入覆写模式,输入的字符将替换原有的字符

复制/粘贴文本

快捷键功能
yy复制当前行至存储缓冲区
["x]yy复制当前行至寄存器 x
p在当前行之后粘贴存储缓冲区中的内容
P在当前行之前粘贴存储缓冲区中的内容
["x]p在当前行之后粘贴寄存器 x 中的内容
["x]P在当前行之前粘贴寄存器 x 中的内容

撤销/重做操作

快捷键功能
u撤销最后的操作
Ctrl+r重做最后撤销的操作

搜索和替换

快捷键功能
/search_text检索文档,在文档后面的部分搜索 search\_text
?search_text检索文档,在文档前面的部分搜索 search\_text
n移动到后一个检索结果
N移动到前一个检索结果
:%s/original/replacement检索第一个 “original” 字符串并将其替换成 “replacement”
:%s/original/replacement/g检索并将所有的 “original” 替换为 “replacement”
:%s/original/replacement/gc检索出所有的 “original” 字符串,但在替换成 “replacement” 前,先询问是否替换

书签

快捷键功能
m {a-zA-Z}在当前光标位置设置书签,书签名可用一个大小写字母({a-zA-Z})
:marks列出所有书签
{a-zA-Z}跳转到书签 {a-zA-Z}

选择文本

快捷键功能
v进入逐字可视模式
V进入逐行可视模式
Esc退出可视模式

改动选中文本

快捷键功能
~切换大小写
d删除一个词
c变更
y复制
>右移
<左移
!通过外部命令进行过滤

保存并退出

快捷键功能
:q退出 Vim,如果文件已被修改,将退出失败
:w保存文件
:w new_name用 new\_name 作为文件名保存文件
:wq保存文件并退出 Vim
:q!退出 Vim,不保存文件改动
ZZ退出 Vim,如果文件被改动过,保存改动内容
ZQ与 :q! 相同,退出 Vim,不保存文件改动

下载 Vim 快捷键速查表

仅仅是这样是否还不足以满足你?别担心,我们已经为你整理好了一份下载版的速查表,以备不时之需。

点此下载(英文)


via: https://www.maketecheasier.com/vim-keyboard-shortcuts-cheatsheet/

作者:Himanshu Arora 译者:martin2011qi 校对:wxy

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

这篇文章是 VIM 用户指南 系列文章中的一篇:

对一个程序员来说,选择一个文本编辑器是一件非常重要的事。因为不同编辑器之间有着不少的差异:图形界面或者非图形界面、不同的快捷键、不同的编程语言支持、不同的插件以及自定义设置等等。我建议不是去搜索最棒的编辑器,而是去选择最适合你的习惯且最适应你的任务的那一个。假如你打算在一个团体中工作,那么最好和你的共事者选择一样的编辑器。这样的话,一旦你在使用中遇到问题,你就可以去向他们寻求帮助。

这正是我在几年之前开始使用 Vim 的原因。通常来说,Vim 会被置于传说中的 Emacs 的对立面。我承认我对 Emacs 知之甚少,但是对于它俩,你需要知道的是它们都可以被深度定制,并且在初学时也都非常令人困惑。这个教程并不会介绍有关 Vim 的所有内容,而是将介绍一些基础以使你在最初就能正确使用它,随后还会展示一些小技巧,借此(希望能)让你有能力自己去探索学习。

Vim 一词来源于 “Vi IMproved”。Vi 是一个被广泛安装于 Unix 系统的非图形界面文本编辑器,并且它也被默认安装在了 Linux 系统中。Vim 是这个原始编辑器的增强版,但是不同于 Vi,并不是每个发行版都默认安装了它。

安装

在 Ubuntu 中可以使用如下命令来安装 Vim:

sudo apt-get install vim

如果你已经对某些插件有了兴趣,使用以下命令:

sudo apt-cache search vim

这命令将给你输出一个很长的和 Vim 有关的包列表。在这之中,有针对不同编程语言的工具,有插件管理器,等等。

在这系列教程中,我将会在 Ubuntu 上使用最新版的 Vim(7.3.154,LCTT 译注:现在最新版为 8.0)。当然你也可以使用其它任何版本。

热身

在终端输入 vim 命令,你将会看到一个非常棒的欢迎界面。

(LCTT 译注:看到了欢迎界面中那行“Help poor children in Uganda!” 了吗?)

如果你之前从未使用过 Vi 或者 Vim,那么你很可能甚至不知道该怎么退出它... 是的,这是事实。任何你常用的快捷键在 Vim 中都将失去原有的效果。(LCTT 译注:网上有个流传的笑话——“如何制造乱码”,“让新手退出 vi”)

首先,要使用任何命令式的功能,像 保存 save 或者 退出 exit ,你都先得输入一个冒号(:)。保存是 :w 而退出是 :q。如果你想不保存文件就退出,那么就要使用强制退出命令 :q!。Vim 中非常棒的一点是你不需要分开输入各个命令,换言之,如果你想保存然后退出,你就可以直接使用 :wq

现在,我们退出 Vim 再打开一个文本文件。为此,你只需把想要编辑的文件名加在命令后面即可:

vim [文本文件名]

一般而言,当你打开一个文本文件,你将会处在查看模式。这使得 Vim 与众不同并且最初会让人感到困惑。Vim 主要由两种模式构成:查看模式和编辑模式。查看模式用于查看内容并且使用一些命令。想要进入编辑模式,只需按 i 键进行 插入 insert 或者 a 键进行 添加 add 。想要返回到查看模式或者进行命令式功能的操作,按 Escape 键即可。 插入 insert 添加 add 的差异仅仅在于你是想在光标位置之前还是在光标之后进入编辑模式并进行文字输入。要想彻底地明白,你应该亲自去尝试一下。我的建议是:仅在行尾使用 添加 add ,而在其它时候使用 插入 insert

(LCTT 译注:此段落中“查看模式”原文是 “visual mode”,疑为“view mode”,在此模式下可以查看文本,但是不能进行编辑;而“visual mode” 是编辑模式的一种,可以按 v 键进入,然后就可以用方向键从当前光标位置开始进行选择,并以反白的视觉效果显示,通常选择后可以按 y 进行复制、按 d 进行剪切等操作。此外, 本文作者的用语并不标准,按照 Vim 自己的用语来说,此处所谓的“查看模式”,应该称之为“普通模式”,“编辑模式”应该称之为“插入模式”,不过意思是一致的。)

要想在文本之中移动光标,你通常可以使用键盘上的方向键,它们无论是在查看模式还是在编辑模式都可以生效。不过,一个真正的纯粹主义者将会告诉你使用按键 h 向左,j 向下,k 向上,l 向右来(在查看模式)进行移动。

现在你已经明白了如何和简单地控制 Vim,我们再来更加深入一些。

一些简单命令

现在你已经熟悉了在正常模式和插入模式之间进行切换,下面是一些可以在正常模式中使用的命令:

  • x:删除一个字符
  • u:撤销一个操作(相当与 Ctrl+z
  • dd:删除一行内容
  • dw:删除一个单词
  • yy:复制一行内容
  • yw:复制一个单词
  • p:粘贴一个之前删除或复制的行或者单词
  • e:跳到下个单词(LCTT 译注:词尾)(比单纯用方向键更快)
  • r:替换一个字母(按 r,松开,然后再按新字母)

当然不止这些,不过这些对现在来说已经足够了。如果你掌握了上面的全部,你将能你很顺溜地使用 Vim 了。

对于那些还想知道更多的人,我再多提一下。你可以在任何这些命令之前加上一个数值,那么这个命令将被重复执行相应的次数。例如,5x 将在当前行连续删除 5 个字母,而 3p 将会粘贴 3 次。

高级命令

最后,作为对你自己继续探索的鼓励和示例,这里给出几个高级且常用的命令:

  • /所搜索的内容:在文中搜索特定内容
  • :sp 文本文件名:将屏幕水平分割成上下两半,新文件展示在另一半。想要在两侧切换焦点,可以使用 Ctrl+w 快捷键。
  • :vsp 文本文件名:同上,但是是垂直分割屏幕
  • Ctrl+Shift+CCtrl+Shift+V:在终端中复制和粘贴文本
  • :! 命令名:在 Vim 中运行 Vim 外的终端命令,直接发送给 shell。例如,:! ls 将在不退出编辑器的同时,显示你当前目录内的文件。

结论

我觉得你现在应该已经有了足够的准备来开始使用 Vim。你还可以通过安装各种插件,编辑 ~.vimrc 文件,或者在 shell 中输入 vimtutor 命令来使用交互式教程以学到更多。

如果你有任何你想分享的关于 Vim 的其它命令,请在评论中告知我们。


via: https://www.maketecheasier.com/start-with-vim-linux/

作者:Himanshu Arora 译者:Yinr 校对:jasminepeng

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

如果你是 Linux 命令行的用户,有的时候你可能不希望某些命令记录在你的命令行历史中。原因可能很多,例如,你在公司担任某个职位,你有一些不希望被其它人滥用的特权。亦或者有些特别重要的命令,你不希望在你浏览历史列表时误执行。

然而,有方法可以控制哪些命令进入历史列表,哪些不进入吗?或者换句话说,我们在 Linux 终端中可以开启像浏览器一样的无痕模式吗?答案是肯定的,而且根据你想要的具体目标,有很多实现方法。在这篇文章中,我们将讨论一些行之有效的方法。

注意:文中出现的所有命令都在 Ubuntu 下测试过。

不同的可行方法

前面两种方法已经在之前一篇文章中描述了。如果你已经了解,这部分可以略过。然而,如果你不了解,建议仔细阅读。

1. 在命令前插入空格

是的,没看错。在命令前面插入空格,这条命令会被 shell 忽略,也就意味着它不会出现在历史记录中。但是这种方法有个前提,只有在你的环境变量 HISTCONTROL 设置为 "ignorespace" 或者 "ignoreboth" 才会起作用。在大多数情况下,这个是默认值。

所以,像下面的命令(LCTT 译注:这里[space]表示输入一个空格):

[space]echo "this is a top secret"

如果你之前执行过如下设置环境变量的命令,那么上述命令不会出现在历史记录中。

export HISTCONTROL = ignorespace

下面的截图是这种方式的一个例子。

第四个 "echo" 命令因为前面有空格,它没有被记录到历史中。

2. 禁用当前会话的所有历史记录

如果你想禁用某个会话所有历史,你可以在开始命令行工作前简单地清除环境变量 HISTSIZE 的值即可。执行下面的命令来清除其值:

export HISTSIZE=0

HISTSIZE 表示对于 bash 会话其历史列表中可以保存命令的个数(行数)。默认情况,它设置了一个非零值,例如在我的电脑上,它的值为 1000。

所以上面所提到的命令将其值设置为 0,结果就是直到你关闭终端,没有东西会存储在历史记录中。记住同样你也不能通过按向上的箭头按键或运行 history 命令来看到之前执行的命令。

3. 工作结束后清除整个历史

这可以看作是前一部分所提方案的另外一种实现。唯一的区别是在你完成所有工作之后执行这个命令。下面是刚说到的命令:

history -cw

刚才已经提到,这个和 HISTSIZE 方法有相同效果。

4. 只针对你的工作关闭历史记录

虽然前面描述的方法(2 和 3)可以实现目的,它们可以清除整个历史,在很多情况下,有些可能不是我们所期望的。有时候你可能想保存直到你开始命令行工作之间的历史记录。对于这样的需求,你开始在工作前执行下述命令:

[space]set +o history

备注:[space] 表示空格。并且由于空格的缘故,该命令本身也不会被记录。

上面的命令会临时禁用历史功能,这意味着在这命令之后你执行的所有操作都不会记录到历史中,然而这个命令之前的所有东西都会原样记录在历史列表中。

要重新开启历史功能,执行下面的命令:

[Space]set -o history

它将环境恢复原状,也就是你完成了你的工作,执行上述命令之后的命令都会出现在历史中。

5. 从历史记录中删除指定的命令

现在假设历史记录中已经包含了一些你不希望记录的命令。这种情况下我们怎么办?很简单。直接动手删除它们。通过下面的命令来删除:

history | grep "part of command you want to remove"

上面的命令会输出历史记录中匹配的命令,每一条前面会有个数字。

一旦你找到你想删除的命令,执行下面的命令,从历史记录中删除那个指定的项:

history -d [num]

下面是这个例子的截图。

第二个 ‘echo’命令被成功的删除了。

(LCTT 译注:如果你不希望上述命令本身也被记录进历史中,你可以在上述命令前加个空格)

同样的,你可以使用向上的箭头一直往回翻看历史记录。当你发现你感兴趣的命令出现在终端上时,按下 “Ctrl + U”清除整行,也会从历史记录中删除它。

总结

有多种不同的方法可以操作 Linux 命令行历史来满足你的需求。然而请记住,从历史中隐藏或者删除命令通常不是一个好习惯,尽管本质上这并没有错。但是你必须知道你在做什么,以及可能产生的后果。


via: https://www.maketecheasier.com/linux-command-line-history-incognito/

作者:Himanshu Arora 译者:chunyang-wen 校对:wxy

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

Credit: Moini

作为一个程序员,我知道我肯定会犯错误——怎么可能不犯错!程序员也是人啊。有的错误能在编码过程中及时发现,而有些却得等到软件测试了才能显露出来。然而,还有一类错误并不能在这两个阶段被解决,这就导致软件不能正常运行,甚至是提前终止。

如果你还没猜出是那种错误,我说的就是和内存相关的错误。手动调试这些错误不仅耗时,而且很难发现并纠正。值得一提的是,这种错误很常见,特别是在用 C/C++ 这类允许手动管理内存的语言编写的软件里。

幸运的是,现在有一些编程工具能够帮你在软件程序中找到这些和内存相关的错误。在这些工具集中,我评估了五款支持 Linux 的、流行的、自由开源的内存调试器: Dmalloc 、 Electric Fence 、 Memcheck 、 Memwatch 以及 Mtrace 。在日常编码中,我已经用过这五个调试器了,所以这些评估是建立在我的实际体验之上的。

Dmalloc

开发者:Gray Watson

评估版本:5.5.2

支持的 Linux 版本:所有种类

许可: CC 3.0

Dmalloc 是 Gray Watson 开发的一款内存调试工具。它是作为库来实现的,封装了标准内存管理函数如malloc() , calloc() , free()等,使程序员得以检测出有问题的代码。

cw dmalloc output

Dmalloc

如同工具的网页所示,这个调试器提供的特性包括内存泄漏跟踪、 重复释放内存 double free 错误跟踪、以及 越界写入 fence-post write 检测。其它特性包括报告错误的文件/行号、通用的数据统计记录。

更新内容

5.5.2 版本是一个 bug 修正发行版,修复了几个有关构建和安装的问题。

有何优点

Dmalloc 最大的优点就是高度可配置性。比如说,你可以配置它以支持 C++ 程序和多线程应用。 Dmalloc 还提供一个有用的功能:运行时可配置,这表示在 Dmalloc 执行时,可以轻易地启用或者禁用它提供的一些特性。

你还可以配合 GNU Project Debugger (GDB)来使用 Dmalloc ,只需要将dmalloc.gdb文件(位于 Dmalloc 源码包中的 contrib 子目录里)的内容添加到你的主目录中的.gdbinit文件里即可。

另外一个让我对 Dmalloc 爱不释手的优点是它有大量的资料文献。前往官网的 Documentation 栏目,可以获取所有关于如何下载、安装、运行、怎样使用库,和 Dmalloc 所提供特性的细节描述,及其生成的输出文件的解释。其中还有一个章节介绍了一般问题的解决方法。

注意事项

跟 Mtrace 一样, Dmalloc 需要程序员改动他们的源代码。比如说你可以(也是必须的)添加头文件dmalloc.h,工具就能汇报产生问题的调用的文件或行号。这个功能非常有用,因为它节省了调试的时间。

除此之外,还需要在编译你的程序时,把 Dmalloc 库(编译 Dmalloc 源码包时产生的)链接进去。

然而,还有点更麻烦的事,需要设置一个环境变量,命名为DMALLOC_OPTION,以供工具在运行时配置内存调试特性,比如定义输出文件的路径。可以手动为该环境变量分配一个值,不过初学者可能会觉得这个过程有点困难,因为该值的一部分用来表示要启用的 Dmalloc 特性——以十六进制值的累加值表示。这里有详细介绍。

一个比较简单方法设置这个环境变量是使用 Dmalloc 实用指令,这是专为这个目的设计的方法。

总结

Dmalloc 真正的优势在于它的可配置选项。而且高度可移植,曾经成功移植到多种操作系统如 AIX 、 BSD/OS 、 DG/UX 、 Free/Net/OpenBSD 、 GNU/Hurd 、 HPUX 、 Irix 、 Linux 、 MS-DOG 、 NeXT 、 OSF 、 SCO 、 Solaris 、 SunOS 、 Ultrix 、 Unixware 甚至 Unicos(运行在 Cray T3E 主机上)。虽然使用 Dmalloc 需要学习许多知识,但是它所提供的特性值得为之付出。

Electric Fence

开发者:Bruce Perens

评估版本:2.2.3

支持的 Linux 版本:所有种类

许可:GPL v2

Electric Fence 是 Bruce Perens 开发的一款内存调试工具,它以库的形式实现,你的程序需要链接它。Electric Fence 能检测出内存溢出和访问已经释放的内存。

cw electric fence output

Electric Fence

顾名思义, Electric Fence 在每个所申请的缓存边界建立了虚拟围栏,这样一来任何非法的内存访问都会导致段错误。这个调试工具同时支持 C 和 C++ 程序。

更新内容

2.2.3 版本修复了工具的构建系统,使得 -fno-builtin-malloc 选项能真正传给 GNU Compiler Collection (GCC)

有何优点

我喜欢 Electric Fence 的首要一点是它不同于 Memwatch 、 Dmalloc 和 Mtrace ,不需要对你的源码做任何的改动,你只需要在编译的时候把它的库链接进你的程序即可。

其次, Electric Fence 的实现保证了产生越界访问的第一个指令就会引起段错误。这比在后面再发现问题要好多了。

不管是否有检测出错误, Electric Fence 都会在输出产生版权信息。这一点非常有用,由此可以确定你所运行的程序已经启用了 Electric Fence 。

注意事项

另一方面,我对 Electric Fence 真正念念不忘的是它检测内存泄漏的能力。内存泄漏是 C/C++ 软件最常见也是最不容易发现的问题之一。不过, Electric Fence 不能检测出栈溢出,而且也不是线程安全的。

由于 Electric Fence 会在用户分配内存区的前后分配禁止访问的虚拟内存页,如果你过多的进行动态内存分配,将会导致你的程序消耗大量的额外内存。

Electric Fence 还有一个局限是不能明确指出错误代码所在的行号。它所能做只是在检测到内存相关错误时产生段错误。想要定位错误的行号,需要借助 GDB这样的调试工具来调试启用了 Electric Fence 的程序。

最后一点,尽管 Electric Fence 能检测出大部分的缓冲区溢出,有一个例外是,如果所申请的缓冲区大小不是系统字长的倍数,这时候溢出(即使只有几个字节)就不能被检测出来。

总结

尽管局限性较大, Electric Fence 的易用性仍然是加分项。只要链接一次程序, Electric Fence 就可以在监测出内存相关问题的时候报警。不过,如同前面所说, Electric Fence 需要配合像 GDB 这样的源码调试器使用。

Memcheck

开发者Valgrind 开发团队

评估版本:3.10.1

支持的 Linux 发行版:所有种类

许可:GPL

Valgrind 是一个提供好几款调试和分析 Linux 程序性能的工具的套件。虽然 Valgrind 能和不同语言——Java 、 Perl 、 Python 、 Assembly code 、 ortran 、 Ada 等——编写的程序一起工作,但是它主要还是针对使用 C/C++ 所编写的程序。

Memcheck ,一款内存错误检测器,是其中最受欢迎的工具。它能够检测出如内存泄漏、无效的内存访问、未定义变量的使用以及堆内存分配和释放相关的问题等诸多问题。

更新内容

工具套件( 3.10.1 )主要修复了 3.10.0 版本发现的 bug 。除此之外,“从主干开发版本向后移植的一些补丁,修复了缺失的 AArch64 ARMv8 指令和系统调用”。

有何优点

同其它所有 Valgrind 工具一样, Memcheck 也是命令行程序。它的操作非常简单:通常我们会使用诸如 prog arg1 arg2 格式的命令来运行程序,而 Memcheck 只要求你多加几个值即可,如 valgrind --leak-check=full prog arg1 arg2

cw memcheck output

Memcheck

(注意:因为 Memcheck 是 Valgrind 的默认工具,所以在命令行执行命令时无需提及 Memcheck。但是,需要在编译程序之初带上 -g 参数选项,这一步会添加调试信息,使得 Memcheck 的错误信息会包含正确的行号。)

我真正倾心于 Memcheck 的是它提供了很多命令行选项(如上所述的--leak-check选项),如此不仅能控制工具运转还可以控制它的输出。

举个例子,可以开启--track-origins选项,以查看程序源码中未初始化的数据;可以开启--show-mismatched-frees选项让 Memcheck 匹配内存的分配和释放技术。对于 C 语言所写的代码, Memcheck 会确保只能使用free()函数来释放内存,malloc()函数来申请内存。而对 C++ 所写的源码, Memcheck 会检查是否使用了deletedelete[]操作符来释放内存,以及new或者new[]来申请内存。

Memcheck 最好的特点,尤其是对于初学者来说,是它会给用户建议使用哪个命令行选项能让输出更加有意义。比如说,如果你不使用基本的--leak-check选项, Memcheck 会在输出时给出建议:“使用 --leak-check=full 重新运行以查看更多泄漏内存细节”。如果程序有未初始化的变量, Memcheck 会产生信息:“使用 --track-origins=yes 以查看未初始化变量的定位”。

Memcheck 另外一个有用的特性是它可以创建 抑制文件 suppression files ,由此可以略过特定的不能修正的错误,这样 Memcheck 运行时就不会每次都报警了。值得一提的是, Memcheck 会去读取默认抑制文件来忽略系统库(比如 C 库)中的报错,这些错误在系统创建之前就已经存在了。可以选择创建一个新的抑制文件,或是编辑现有的文件(通常是/usr/lib/valgrind/default.supp)。

Memcheck 还有高级功能,比如可以使用定制内存分配器检测内存错误。除此之外, Memcheck 提供监控命令,当用到 Valgrind 内置的 gdbserver ,以及客户端请求机制(不仅能把程序的行为告知 Memcheck ,还可以进行查询)时可以使用。

注意事项

毫无疑问, Memcheck 可以节省很多调试时间以及省去很多麻烦。但是它使用了很多内存,导致程序执行变慢(由文档可知,大概会花费 20 至 30 倍时间)。

除此之外, Memcheck 还有其它局限。根据用户评论, Memcheck 很明显不是线程安全的;它不能检测出 静态缓冲区溢出;还有就是,一些 Linux 程序如 GNU Emacs 目前还不能配合 Memcheck 工作。

如果有兴趣,可以在这里查看 Valgrind 局限性的详细说明。

总结

无论是对于初学者还是那些需要高级特性的人来说, Memcheck 都是一款便捷的内存调试工具。如果你仅需要基本调试和错误检查, Memcheck 会非常容易上手。而当你想要使用像抑制文件或者监控指令这样的特性,就需要花一些功夫学习了。

虽然罗列了大量的局限性,但是 Valgrind(包括 Memcheck )在它的网站上声称全球有成千上万程序员使用了此工具。开发团队称收到来自超过 30 个国家的用户反馈,而这些用户的工程代码有的高达两千五百万行。

Memwatch

开发者:Johan Lindh

评估版本:2.71

支持的 Linux 发行版:所有种类

许可:GNU GPL

Memwatch 是由 Johan Lindh 开发的内存调试工具,虽然它扮演的主要角色是内存泄漏检测器,但是(根据网页介绍)它也具有检测其它如内存重复释放和错误释放、缓冲区溢出和下溢、野指针写入等等内存相关问题的能力。

Memwatch 支持用 C 语言所编写的程序。也可以在 C++ 程序中使用它,但是这种做法并不提倡(由 Memwatch 源码包随附的 Q&A 文件中可知)。

更新内容

这个版本添加了ULONG_LONG_MAX以区分 32 位和 64 位程序。

有何优点

跟 Dmalloc 一样, Memwatch 也有优秀的文档资料。参考 USING 文件,可以学习如何使用 Memwatch ,可以了解 Memwatch 是如何初始化、如何清理以及如何进行 I/O 操作,等等。还有一个 FAQ 文件,旨在帮助用户解决使用过程遇到的一般问题。最后还有一个test.c文件提供工作案例参考。

cw memwatch output

Memwatch

不同于 Mtrace , Memwatch 产生的日志文件(通常是memwatch.log)是人类可阅读的格式。而且, Memwatch 每次运行时总会把内存调试结果拼接到输出该文件的末尾。如此便可在需要之时轻松查看之前的输出信息。

同样值得一提的是当你执行了启用 Memwatch 的程序, Memwatch 会在标准输出中产生一个单行输出,告知发现了错误,然后你可以在日志文件中查看输出细节。如果没有产生错误信息,就可以确保日志文件不会写入任何错误,多次运行的话确实能节省时间。

另一个我喜欢的优点是 Memwatch 还提供了在源码中获取其输出信息的方式,你可以获取信息,然后任由你进行处理(参考 Memwatch 源码中的mwSetOutFunc()函数获取更多有关的信息)。

注意事项

跟 Mtrace 和 Dmalloc 一样, Memwatch 也需要你往你的源文件里增加代码:你需要把memwatch.h这个头文件包含进你的代码。而且,编译程序的时候,你需要连同memwatch.c一块编译;或者你可以把已经编译好的目标模块包含起来,然后在命令行定义MEMWATCHMW_STDIO变量。不用说,想要在输出中定位行号, -g 编译器选项也少不了。

此外, Memwatch 缺少一些特性。比如 Memwatch 不能检测出对一块已经被释放的内存进行写入操作,或是在分配的内存块之外的进行读取操作。而且, Memwatch 也不是线程安全的。还有一点,正如我在开始时指出,在 C++ 程序上运行 Memwatch 的结果是不能预料的。

总结

Memcheck 可以检测很多内存相关的问题,在处理 C 程序时是非常便捷的调试工具。因为源码小巧,所以可以从中了解 Memcheck 如何运转,有需要的话可以调试它,甚至可以根据自身需求扩展升级它的功能。

Mtrace

开发者: Roland McGrath 和 Ulrich Drepper

评估版本: 2.21

支持的 Linux 发行版:所有种类

许可:GNU GPL

Mtrace 是 GNU C 库中的一款内存调试工具,同时支持 Linux 上的 C 和 C++ 程序,可以检测由函数malloc()free()不匹配的调用所引起的内存泄漏问题。

cw mtrace output

Mtrace

Mtrace 实际上是实现了一个名为mtrace()的函数,它可以跟踪程序中所有 malloc/free 调用,并在用户指定的文件中记录相关信息。文件以一种机器可读的格式记录数据,所以有一个 Perl 脚本——同样命名为 mtrace ——用来把文件转换并为人类可读格式。

更新内容

Mtrace 源码Perl 文件同 GNU C 库( 2.21 版本)一起释出,除了更新版权日期,其它别无改动。

有何优点

Mtrace 最好的地方是它非常简单易学。你只需要了解在你的源码中如何以及何处添加 mtrace() 及对应的 muntrace() 函数,还有如何使用 Mtrace 的 Perl 脚本。后者非常简单,只需要运行指令mtrace <program-executable> <log-file-generated-upon-program-execution>(例子见开头截图最后一条指令)。

Mtrace 另外一个优点是它的可伸缩性,这体现在不仅可以使用它来调试完整的程序,还可以使用它来检测程序中独立模块的内存泄漏。只需在每个模块里调用mtrace()muntrace()即可。

最后一点,因为 Mtrace 会在mtrace()——在源码中添加的函数——执行时被触发,因此可以很灵活地使用信号动态地(在程序执行时)使能 Mtrace 。

注意事项

因为mtrace()mauntrace()函数 —— 声明在mcheck.h文件中,所以必须在源码中包含此头文件 —— 的调用是 Mtrace 工作的基础(mauntrace()函数并非总是必要),因此 Mtrace 要求程序员至少改动源码一次。

需要注意的是,在编译程序的时候带上 -g 选项( GCCG++ 编译器均有提供),才能使调试工具在输出结果时展示正确的行号。除此之外,有些程序(取决于源码体积有多大)可能会花很长时间进行编译。最后,带 -g 选项编译会增加了可执行文件的大小(因为提供了额外的调试信息),因此记得程序需要在测试结束后,不带 -g 选项重新进行编译。

使用 Mtrace ,你需要掌握 Linux 环境变量的基本知识,因为在程序执行之前,需要把用户把环境变量MALLOC_TRACE的值设为指定的文件(mtrace()函数将会记录全部信息到其中)路径。

Mtrace 在检测内存泄漏和试图释放未经过分配的内存方面存在局限。它不能检测其它内存相关问题如非法内存访问、使用未初始化内存。而且,有人抱怨 Mtrace 不是线程安全的。

总结

不言自明,我在此讨论的每款内存调试器都有其优点和局限。所以,哪一款适合你取决于你所需要的特性,虽然有时候容易安装和使用也是一个决定因素。

要想捕获软件程序中的内存泄漏, Mtrace 最适合不过了。它还可以节省时间。由于 Linux 系统已经预装了此工具,对于不能联网或者不可以下载第三方调试调试工具的情况, Mtrace 也是极有助益的。

另一方面,相比 Mtrace , Dmalloc 不仅能检测更多错误类型,还提供更多特性,比如运行时可配置、 GDB 集成。而且, Dmalloc 不像这里所说的其它工具,它是线程安全的。更不用说它的详细资料了,这让 Dmalloc 成为初学者的理想选择。

虽然 Memwatch 的资料比 Dmalloc 的更加丰富,而且还能检测更多的错误种类,但是你只能在 C 语言写就的程序中使用它。一个让 Memwatch 脱颖而出的特性是它允许在你的程序源码中处理它的输出,这对于想要定制输出格式来说是非常有用的。

如果改动程序源码非你所愿,那么使用 Electric Fence 吧。不过,请记住, Electric Fence 只能检测两种错误类型,而此二者均非内存泄漏。还有就是,需要基本了解 GDB 以最大化发挥这款内存调试工具的作用。

Memcheck 可能是其中综合性最好的了。相比这里提及的其它工具,它能检测更多的错误类型,提供更多的特性,而且不需要你的源码做任何改动。但请注意,基本功能并不难上手,但是想要使用它的高级特性,就必须学习相关的专业知识了。


via: http://www.computerworld.com/article/3003957/linux/review-5-memory-debuggers-for-linux-coding.html

作者:Himanshu Arora 译者:soooogreen 校对:PurlingNayuki,ezio

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

如果你是一个 linux 系统管理员,那么毫无疑问你必须花费大量的工作时间在命令行上:安装和卸载软件,监视系统状态,复制、移动、删除文件,查错,等等。很多时候都是你输入一个命令,然后等待很长时间直到执行完成。也有的时候你执行的命令挂起了,而你只能猜测命令执行的实际情况。

通常 linux 命令不提供和进度相关的信息,而这些信息特别重要,尤其当你只有有限的时间时。然而这并不意味着你是无助的——现在有一个命令,pv,它会显示当前在命令行执行的命令的进度信息。在本文我们会讨论它并用几个简单的例子说明其特性。

PV 命令

PV 由Andrew Wood 开发,是 Pipe Viewer 的简称,意思是通过管道显示数据处理进度的信息。这些信息包括已经耗费的时间,完成的百分比(通过进度条显示),当前的速度,全部传输的数据,以及估计剩余的时间。

"要使用 PV,需要配合合适的选项,把它放置在两个进程之间的管道。命令的标准输入将会通过标准输出传进来的,而进度会被输出到标准错误输出。”

上述解释来自该命令的帮助页。

下载和安装

Debian 系的操作系统,如 Ubuntu,可以简单的使用下面的命令安装 PV:

sudo apt-get install pv

如果你使用了其他发行版本,你可以使用各自的包管理软件在你的系统上安装 PV。一旦 PV 安装好了你就可以在各种场合使用它(详见下文)。需要注意的是下面所有例子都使用的是 pv 1.2.0。

特性和用法

我们(在 linux 上使用命令行的用户)的大多数使用场景都会用到的命令是从一个 USB 驱动器拷贝电影文件到你的电脑。如果你使用 cp 来完成上面的任务,你会什么情况都不清楚,直到整个复制过程结束或者出错。

然而pv 命令在这种情景下很有帮助。比如:

pv /media/himanshu/1AC2-A8E3/fNf.mkv > ./Desktop/fnf.mkv

输出如下:

pv-copy

所以,如你所见,这个命令显示了很多和操作有关的有用信息,包括已经传输了的数据量,花费的时间,传输速率,进度条,进度的百分比,以及剩余的时间。

pv 命令提供了多种显示选项开关。比如,你可以使用-p 来显示百分比,-t 来显示时间,-r 表示传输速率,-e 代表eta(LCTT 译注:估计剩余的时间)。好事是你不必记住某一个选项,因为默认这几个选项都是启用的。但是,如果你只要其中某一个信息,那么可以通过控制这几个选项来完成任务。

这里还有一个-n 选项来允许 pv 命令显示整数百分比,在标准错误输出上每行显示一个数字,用来替代通常的可视进度条。下面是一个例子:

pv -n /media/himanshu/1AC2-A8E3/fNf.mkv > ./Desktop/fnf.mkv

pv-numeric

这个特殊的选项非常合适某些情境下的需求,如你想把用管道把输出传给dialog 命令。

接下来还有一个命令行选项,-L 可以让你修改 pv 命令的传输速率。举个例子,使用 -L 选项来限制传输速率为2MB/s。

pv -L 2m /media/himanshu/1AC2-A8E3/fNf.mkv > ./Desktop/fnf.mkv

pv-ratelimit

如上图所见,数据传输速度按照我们的要求被限制了。

另一个pv 可以帮上忙的情景是压缩文件。这里有一个例子可以向你解释如何与压缩软件Gzip 一起工作。

pv /media/himanshu/1AC2-A8E3/fnf.mkv | gzip > ./Desktop/fnf.log.gz

pv-gzip

结论

如上所述,pv 是一个非常有用的小工具,它可以在命令没有按照预期执行的情况下帮你节省你宝贵的时间。而且这些显示的信息还可以用在 shell 脚本里。我强烈的推荐你使用这个命令,它值得你一试。


via: https://www.maketecheasier.com/monitor-progress-linux-command-line-operation/

作者:Himanshu Arora 译者:ezio 校对:wxy

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