Shell 命令

2010年8月4日

Shell 命令的详细使用方法。

  1. adduser   创建新的用户账户
  2. alias    设置命令的别名
  3. bzips    .bz2的文件压缩程序
  4. cal    月历显示
  5. cat    将所有内容输出到标准输出设备
  6. chfn    更改finger命令显示的信息
  7. chgrp   变更文件与目录的所属组
  8. chmod   更换文件或目录的权限
  9. chown   更换文件或目录的拥有者或所在组
  10. clear    清除画面上的信息
  11. col    滤除控制字符
  12. cp    复制文件或目录
  13. crontab   设置定时器
  14. date    设置显示系统时间及日期
  15. dd    由键盘输入文件中的数据,然后依照指定格式来转换数据,再输出至所指定的文件或屏幕上
  16. df    显示磁盘文件系统的使用状况
  17. dmesg   显示开机信息
  18. du    显示目录或文件所占磁盘空间
  19. e2fsck   检查ext2文件系统
  20. echo    文字显示
  21. edquota   编辑quota
  22. egrep    查找文件中符合条件的字符串
  23. exec    shell执行命令后即交出控制权
  24. export   设置显示环境变量
  25. fdisk    磁盘分割(分区)
  26. fg    前台执行程序或命令
  27. fgrep   查找文件中符合条件的字符串
  28. file    识别文件类型
  29. find    查找文件或目录
  30. finger   显示用户信息
  31. free    查看内存状态
  32. fsck    检查文件系统并试着修复错误
  33. ftp    传输文件
  34. grep   搜索文件中符合条件的字符串
  35. groupadd   创建组
  36. groupdel   删除组
  37. groupmod   改变组识别码或名称
  38. gunzip    文件解压缩
  39. gzip    文件压缩
  40. halt    关闭系统
  41. help    shell创建命令内容
  42. history    列出所有使用过的命令
  43. hostname   查询及设置主机名称
  44. id    显示用户ID及所属的组ID
  45. ifconfig    显示或设置网络上状态
  46. insmod    加载模块
  47. jobs    显示正在后台执行的工作
  48. kill    删除执行中的程序或工作
  49. last    列出目前与过去登录系统的用户相关信息
  50. less    显示文件内容
  51. lilo    安装内核加载、开机管理程序
  52. linuxconf   设置Linux系统
  53. ln    连接文件或目录
  54. locate    寻找文件
  55. login    登录系统
  56. logout   注销系统
  57. ls    列出目录内容
  58. lsmod   显示已加载系统的模块名称
  59. mail   E-mail管理程序
  60. make   编译系统核心或模块
  61. man   在线查询命令
  62. mcopy   复制MS-DOS文件
  63. mdel   删除MS-DOS文件
  64. mdeltree   删除MS-DOS文件及包含的子目录文件
  65. mdir   显示MS-DOS目录
  66. mkbootdisk   创建目前系统的引导盘
  67. mkdir   创建目录
  68. mke2fs   创建ext2文件系统
  69. mkfs   创建各种文件系统
  70. more   一页一页地显示文件内容(文本文件)
  71. miunt   挂入文件系统
  72. mouseconfig   设置鼠标相关参数
  73. mv   移动或更名现有的文件或目录
  74. netconfig   Red Hat Linux用来设置网络功能的图形接口程序
  75. netstat   显示目前系统的网络状态
  76. nice   变更程序执行时的优先等级
  77. nohup   在用户注销系统后继续以后台的方式执行指定的命令
  78. open   查找第一个可使用的虚拟终端,并执行位于“–”符号后的命令
  79. passwd   提供管理员及用户管理或变更密码
  80. patch   利用修补文件来修改源文件
  81. pine   邮件处理程序,它可收发电子邮件及浏览新闻组
  82. ping   使用ICMP对远程主机发出要求响应的信息,以侦测远程主机的网络功能是否正常
  83. ps   显示程序执行的状况
  84. pwd   显示目前的工作目录
  85. quota   查询磁盘空间限制以及使用情形
  86. quotacheck   检查磁盘使用空间及限制
  87. quotaoff   关闭磁盘使用空间限制
  88. quotaon   开启磁盘使用空间限制
  89. reboot   停止系统运作并重新开机
  90. renice   重新调整程序执行的优先级
  91. repquota   显示磁盘空间限制状况
  92. rm   删除文件或目录
  93. rmdir   删除目录
  94. rpm   管理Red Hat Linux套件
  95. set   设置Shell的执行方式
  96. setup   设置公用程序,可设置的选项包括:登录认证方法、键盘配置、
  97. 鼠标配置、开机启动服务、声卡本配置、时区设置和 X Window配置等
  98. shutdown   系统关机
  99. startx   启动 X Window
  100. stat   显示inode内容
  101. su   变更用户身份
  102. sync   将内存缓冲区内的数据写入磁盘
  103. tail   列出文件内容最后部分
  104. talk   和其他用户交谈
  105. tar   文件备份
  106. telnet   登录远程主机
  107. top   显示及管理执行中的程序
  108. traceroute   显示封包到远程主机间的详细路径
  109. umask   在创建文件时预设的权限屏蔽
  110. umount   卸载文件系统
  111. unalias   删除别名
  112. uname   显示系统信息
  113. uncompress   将.Z文件解压缩
  114. unzip   将.Zip文件解压缩
  115. useradd   创建用户账号
  116. userdel   删除用户账户
  117. vi   编辑文本文件
  118. w   显示目前登录系统的用户信息
  119. wall   将信息传送至每位终端用户
  120. whereis   查找文件,预设whereis去查找的文件包括:/bin、/etc、/sbin、
  121. /usr/bin、/usr/etc、/usr/games、/usr/include、/usr/lib、
  122. /usr/local、/usr/man、/usr/sbin、/usr/src、/usr/local/bin、
  123. /usr/local/etc、/usr/local/game、/usr/local/lib 和/usr/local/man>
  124. which   在环境变量¥PATH 设置的目录中,搜索符合条件的文件
  125. who   显示目前登录系统的用户信息
  126. whoami   显示用户名称
  127. whois   搜索并显示用户信息
  128. write   可传送信息给另一位登录的用户
  129. Xconfigurator   设置 Xfree86
  130. xf86config   设置XFree86
  131. zip   压缩程序

admin Linux

Linux下vim命令

2010年8月4日

进入vi的命令

vi filename :打开或新建文件,并将光标置于第一行首

vi +n filename :打开文件,并将光标置于第n行首

vi + filename :打开文件,并将光标置于最后一行首

vi +/pattern filename:打开文件,并将光标置于第一个与pattern匹配的串处

vi -r filename :在上次正用vi编辑时发生系统崩溃,恢复filename

vi filename….filename :打开多个文件,依次进行编辑

移动光标类命令[/b]

h :光标左移一个字符

l :光标右移一个字符

space:光标右移一个字符

Backspace:光标左移一个字符

k或Ctrl+p:光标上移一行

j或Ctrl+n :光标下移一行

Enter :光标下移一行

w或W :光标右移一个字至字首

b或B :光标左移一个字至字首

e或E :光标右移一个字至字尾

) :光标移至句尾

( :光标移至句首

}:光标移至段落开头

{:光标移至段落结尾

nG:光标移至第n行首

n+:光标下移n行

n-:光标上移n行

n$:光标移至第n行尾

H :光标移至屏幕顶行

M :光标移至屏幕中间行

L :光标移至屏幕最后行

0:(注意是数字零)光标移至当前行首

$:光标移至当前行尾

屏幕翻滚类命令

Ctrl+u:向文件首翻半屏

Ctrl+d:向文件尾翻半屏

Ctrl+f:向文件尾翻一屏

Ctrl+b;向文件首翻一屏

nz:将第n行滚至屏幕顶部,不指定n时将当前行滚至屏幕顶部。

插入文本类命令

i :在光标前

I :在当前行首

a:光标后

A:在当前行尾

o:在当前行之下新开一行

O:在当前行之上新开一行

r:替换当前字符

R:替换当前字符及其后的字符,直至按ESC键

s:从当前光标位置处开始,以输入的文本替代指定数目的字符

S:删除指定数目的行,并以所输入文本代替之

ncw或nCW:修改指定数目的字

nCC:修改指定数目的行

删除命令

ndw或ndW:删除光标处开始及其后的n-1个字

do:删至行首

d$:删至行尾

ndd:删除当前行及其后n-1行

x或X:删除一个字符,x删除光标后的,而X删除光标前的

Ctrl+u:删除输入方式下所输入的文本

搜索及替换命令

/pattern:从光标开始处向文件尾搜索pattern

?pattern:从光标开始处向文件首搜索pattern

n:在同一方向重复上一次搜索命令

N:在反方向上重复上一次搜索命令

:s/p1/p2/g:将当前行中所有p1均用p2替代

:n1,n2s/p1/p2/g:将第n1至n2行中所有p1均用p2替代

:g/p1/s//p2/g:将文件中所有p1均用p2替换

选项设置

all:列出所有选项设置情况

term:设置终端类型

ignorance:在搜索中忽略大小写

list:显示制表位(Ctrl+I)和行尾标志($)

number:显示行号

report:显示由面向行的命令修改过的数目

terse:显示简短的警告信息

warn:在转到别的文件时若没保存当前文件则显示NO write信息

nomagic:允许在搜索模式中,使用前面不带“\”的特殊字符

nowrapscan:禁止vi在搜索到达文件两端时,又从另一端开始

mesg:允许vi显示其他用户用write写到自己终端上的信息

最后行方式命令

:n1,n2 co n3:将n1行到n2行之间的内容拷贝到第n3行下

:n1,n2 m n3:将n1行到n2行之间的内容移至到第n3行下

:n1,n2 d :将n1行到n2行之间的内容删除

:w :保存当前文件

:e filename:打开文件filename进行编辑

:x:保存当前文件并退出

:q:退出vi

:q!:不保存文件并退出vi

:!command:执行shell命令command

:n1,n2 w!command:将文件中n1行至n2行的内容作为command的输入并执行之,若不指定n1,n2,则表示将整个文件内容作为command的输入

:r!command:将命令command的输出结果放到当前行

寄存器操作

“?nyy:将当前行及其下n行的内容保存到寄存器?中,其中?为一个字母,n为一个数字

“?nyw:将当前行及其下n个字保存到寄存器?中,其中?为一个字母,n为一个数字

“?nyl:将当前行及其下n个字符保存到寄存器?中,其中?为一个字母,n为一个数字

“?p:取出寄存器?中的内容并将其放到光标位置处。这里?可以是一个字母,也可以是一个数字

ndd:将当前行及其下共n行文本删除,并将所删内容放到1号删除寄存器中。

admin Linux

自动产生MAKEFILE

2010年7月30日

自动产生MAKEFILE

最近在学习Makefile,找到一个automake的一个资料,跟着敲了一遍,感觉效果不错,虽然还不知道里面原理神马的,以下为正文:

在 Unix 上写程式的人大概都碰过 Makefile,尤其是用 C 来开发程式的人。用 make 来开发和编译程式的确很方便,可是要写出一个 Makefile就不简单了。偏偏介绍 Makefile 的文件不多,GNU Make 那份印出来要几百页的文件,光看完 Overview 就快阵亡了,难怪许多人闻 Unix 色变。本文将介绍如何利用 GNU Autoconf 及 Automake 这两套软体来协助我们『自动』产生 Makefile 档,并且让开发出来的软体可以像 Apache,MySQL 和常见的 GNU 软体一样,只要会 “./configure”, “make”,“make install” 就可以把程式安装到系统中。如果您有心开发 OpenSource 的软体,或只是想在 Unix 系统下写写程式。希望这份介绍文件能帮助您轻松地进入 Unix Programming 的殿堂。

1. 简介
Makefile 基本上就是『目标』(target), 『关连』(dependencies) 和『动作』三者所组成的一连串规则。而 make 就会根据 Makefile 的规则来决定如何编译 (compile) 和连结 (link) 程式。实际上,make 可做的不只是编译和连结程式,例如 FreeBSD 的 port collection 中,Makefile 还可以做到自动下载原始程式套件,解压缩 (extract) ,修补(patch),设定,然後编译,安装至系统中。

Makefile 基本构造虽然简单,但是妥善运用这些规则就也可以变出许多不同的花招。却也因此,许多刚开始学习写 Makefile 时会感到没有规范可循,每个人写出来的 Makefile 长得都不太一样,不知道从何下手,而且常常会受限於自己的开发环境,只要环境变数不同或路径改一下,可能Makefile 就得跟着修改。虽然有 GNU Makefile Conventions (GNUMakefile 惯例) 订出一些使用 GNU 程式设计时撰写 Makefile 的一些标准和规范,但是内容很长而且很复杂, 并且经常做些调整,为了减轻程式设计师维护 Makefile 的负担,因此有了 Automake。

程式设计师只需写一些预先定义好的巨集 (macro),交给 Automake 处理後会产生一个可供 Autoconf 使用的 Makefile.in 档。再配合利用Autoconf 产生的自动设定档 configure 即可产生一份符合 GNU Makefile惯例的 Makeifle 了。

2. 上路之前

在开始试着用 Automake 之前,请先确认你的系统已经安装以下的软体:

1. GNU Automake
2. GNU Autoconf
3. GNU m4
4. perl
5. GNU Libtool (如果你需要产生 shared library)

我会建议你最好也使用 GNU C/C 编译器 、GNU Make 以及其它 GNU 的工具程式来做为开发的环境,这些工具都是属於 Open Source Software不仅免费而且功能强大。如果你是使用 Red Hat Linux 可以找到所有上述软体的 rpm 档,FreeBSD 也有现成的 package 可以直接安装,或着你也可以自行下载这些软体的原始档回来 DIY。以下的范例是在 Red HatLinux 5.2 CLE2 的环境下所完成的。

3. 一个简单的例子

Automake 所产生的 Makefile 除了可以做到程式的编译和连结,也已经把如何产生程式文件 (如 manual page, info 档及 dvi 档) 的动作,还有把原始程式包装起来以供散 的动作都考虑进去了,所以原始程式所存放的目录架构最好符合 GNU 的标准惯例,接下来我拿 hello.c 来做为例子。

在工作目录下建立一个新的子目录 “devel”,再在 devel 下建立一个“hello” 的子目录,这个目录将作为我们存放 hello 这个程式及其相关档案的地方:

% mkdir devel
% cd devel
% mkdir hello
% cd hello

用编辑器写个 hello.c 档,
#include
int main(int argc, char** argv)
{
printf(“Hello, GNU!\n”);
return 0;
}

接下来就要用 Autoconf 及 Automake 来帮我们产生 Makefile 档了,
1. 用 autoscan 产生一个 configure.in 的雏型,执行 autoscan 後会产生一个configure.scan 的档案,我们可以用它做为 configure.in档的蓝本。

% autoscan
% ls
configure.scan hello.c

2. 编辑 configure.scan 档,如下所示,并且把它的档名改成 configure.in

dnl Process this file with autoconf to produce a configure script.

AC_INIT(hello.c)
AM_INIT_AUTOMAKE(hello, 1.0)
dnl Checks for programs.

AC_PROG_CC
dnl Checks for libraries.
dnl Checks for header files.
dnl Checks for typedefs, structures, and compiler characteristics.
dnl Checks for library functions.
AC_OUTPUT(Makefile)

3. 执行 aclocal 和 autoconf ,分别会产生 aclocal.m4 及 configure 两个档案
% aclocal
% autoconf
% ls
aclocal.m4configureconfigure.inhello.c

4. 编辑 Makefile.am 档,内容如下
AUTOMAKE_OPTIONS= foreign
bin_PROGRAMS= hello
hello_SOURCES= hello.c

5. 执行 automake –add-missing ,Automake 会根据 Makefile.am 档产生一些档案,包含最重要的 Makefile.in
% automake –add-missing
automake: configure.in: installing `./install-sh’
automake: configure.in: installing `./mkinstalldirs’
automake: configure.in: installing `./missing’

6. 最後执行 ./configure ,
% ./configure
creating cache ./config.cache
checking for a BSD compatible install… /usr/bin/in
stall -c
checking whether build environment is sane… yes
checking whether make sets ${MAKE}… yes
checking for working aclocal… found
checking for working autoconf… found
checking for working automake… found
checking for working autoheader… found
checking for working makeinfo… found
checking for gcc… gcc
checking whether the C compiler (gcc ) works… yes
checking whether the C compiler (gcc ) is a cross-compiler… no
checking whether we are using GNU C… yes
checking whether gcc accepts -g… yes
updating cache ./config.cache
creating ./config.status
creating Makefile

现在你的目录下已经产生了一个 Makefile 档,下个 “make” 指令就可以开始编译 hello.c 成执行档,执行 ./hello 和 GNU 打声招呼吧!
% make
gcc -DPACKAGE=\”hello\” -DVERSION=\”1.0\” -I. -I. -g -O2 -c hello.c
gcc -g -O2 -o hello hello.o
% ./hello
Hello! GNU!

你还可以试试 “make clean”,”make install”,”make dist” 看看会有什麽结果。你也可以把产生出来的 Makefile 秀给你的老板,让他从此对你刮目相看 :-)

4. 一探究竟
上述产生 Makefile 的过程和以往自行编写的方式非常不一样,舍弃传统自行定义 make 的规则,使用 Automake 只需用到一些已经定义好的巨集即可。我们把巨集及目标 (target) 写在 Makefile.am 档内,Automake读入 Makefile.am 档後会把这一串已经定义好的巨集展开并且产生对应的Makefile.in 档, 然後再由 configure 这个 shell script 根据Makefile.in 产生适合的 Makefile。

4.1 编辑 configure.in 档

Autoconf 是用来产生 ’configure’ 档的工具。’configure’ 是一个shell script,它可以自动设定原始程式以符合各种不同平台上 Unix 系统的特性,并且根据系统叁数及环境产生合适的 Makefile 档或是C 的标头档 (header file),让原始程式可以很方便地在这些不同的平台上被编译出来。Autoconf 会读取 configure.in 档然後产生 ’configure’ 这个shell script。
configure.in 档的内容是一连串 GNU m4 的巨集,这些巨集经过autoconf 处理後会变成检查系统特徵的 shell script。configure.in 内巨集的顺序并没有特别的规定,但是每一个 configure.in 档必须在所有巨集前加入 AC_INIT 巨集,然後在所有巨集的最後面加上 AC_OUTPUT 巨集。我们可先用 autoscan 扫描原始档以产生一个 configure.scan 档,再对 configure.scan 做些修改成 configure.in 档。在范例中所用到的巨集如下:
dnl
这个巨集後面的字不会被处理,可视为注解。
AC_INIT(FILE)
这个巨集用来检查原始码所在的路径,autoscan 会自动产生,我们不必修改它。
AM_INIT_AUTOMAKE(PACKAGE,VERSION)
这是使用 Automake 所必备的巨集,PACKAGE 是我们所要产生软体套件的名称,VERSION 是版本编号。
AC_PROG_CC
检查系统可用的 C 编译器,如果原始程式是用 C 写的就需要这个巨集。
AC_OUTPUT(FILE)
设定 configure 所要产生的档案,如果是 Makefile 的话,configure 便会把它检查出来的结果带入 Makefile.in 档然後产生合适的 Makefile。

实际上,我们使用 Automake 时,还须要一些其它的巨集,这些额外的巨集我们用 aclocal 来帮我们产生。执行 aclocal 会产生 aclocal.m4 档,如果没有特别的用途,我们可以不必修改它,用 aclocal 所产生的巨集会告诉 Automake 怎麽做。

有了 configure.in 及 aclocal.m4 两个档案後,便可以执行 autoconf来产生 configure 档了。

4.2 编辑 Makefile.am 档

接下来我们要编辑 Makefile.am 档,Automake 会根据 configure.in 中的巨集把Makefile.am 转成 Makefile.in 档。Makefile.am 档定义我们所要产的目标:

AUTOMAKE_OPTIONS
设定 automake 的选项。Automake 主要是帮助开发 GNU 软体的人员维护软体套件,所以在执行 automake 时,会检查目录下是否存在标准 GNU 软体套件中应具备的文件档案,例如 ’NEWS’、’AUTHOR’、’ChangeLog’ 等文件档。设成 foreign 时,automake 会改用一般软体套件的标准来检查。
bin_PROGRAMS
定义我们所要产生的执行档档名。如果要产生多个执行档,每个档名用空白字元隔开。
hello_SOURCES
定义 ’hello’ 这个执行档所需要的原始档。如果 ’hello’ 这个程式是由多个原始档所产生,必须把它所用到的原始档都列出来,以空白字元隔开。假设 ’hello’ 这个程式需要 ’hello.c’、’main.c’、’hello.h’ 三个档案的话,则定义 hello_SOURCES= hello.c main.c hello.h 如果我们定义多个执行档,则对每个执行档都要定义相对的filename_SOURCES。

编辑好 Makefile.am 档,就可以用 automake –add-missing 来产生Makefile.in。加上 –add-missing 选项是告诉 automake 顺便帮我们加入包装一个软体套件所必备的档案。Automake 产生出来的 Makefile.in档是完全符合 GNU Makefile 的惯例,我们只要执行 configure 这个shell script 便可以产生合适的 Makefile 档了。

4.3 使用 Makefile

利用 configure 所产生的 Makefile 档有几个预设的目标可供使用,我们只拿其中几个简述如下:

make all
产生我们设定的目标,即此范例中的执行档。只打 make 也可以,此时会开始编译原始码,然後连结,并且产生执行档。
make clean
清除之前所编译的执行档及目的档 (object file, *.o)。
make distclean
除了清除执行档和目的档外,也把 configure 所产生的 Makefile也清除掉。
make install
将程式安装至系统中。如果原始码编译无误,且执行结果正确,便可以把程式安装至系统预设的执行档存放路径。如果我们用bin_PROGRAMS 巨集的话,程式会被安装至 /usr/local/bin 这个目录。
make dist
将程式和相关的档案包装成一个压缩档以供散播 (distribution) 。执行完在目录下会产生一个以 PACKAGE-VERSION.tar.gz 为名称的档案。PACKAGE 和 VERSION 这两个变数是根据 configure.in 档中
AM_INIT_AUTOMAKE(PACKAGE, VERSION) 的定义。在此范例中会产生’hello-1.0.tar.gz’ 的档案。
make distcheck
和 make dist 类似,但是加入检查包装後的压缩档是否正常。这个目标除了把程式和相关档案包装成 tar.gz 档外,还会自动把这个压缩档解开,执行 configure,并且进行 make all 的动作,确认编译无误後,会显示这个 tar.gz 档已经准备好可供散播了。这个检查非常有用,检查过关的套件,基本上可以给任何一个具备 GNU 发展环境的人去重新编译。就 hello-1.tar.gz 这个范例而言,除了在 RedHat Linux 上,在 FreeBSD 2.2.x 版也可以正确地重新编译。

要注意的是,利用 Autoconf 及 Automake 所产生出来的软体套件是可以在没有安装 Autoconf 及 Automake 的环境上使用的,因为 configure 是一个 shell script,它己被设计可以在一般 Unix 的 sh 这个 shell 下执行。但是如果要修改 configure.in 及 Makefile.am 档再产生新的configure 及 Makefile.in 档时就一定要有 Autoconf 及 Automake 了。

5. 相关讯息

Autoconf 和 Automake 功能十分强大,你可以从它们所附的 info 档找到详细的用法。你也可以从许多现存的 GNU 软体或 Open Source 软体中找到相关的 configure.in 或 Makefile.am 档,它们是学习 Autoconf 及Automake 更多技巧的最佳范例。

这篇简介只用到了 Autoconf 及 Automake 的皮毛罢了,如果你有心加入Open Source 软体开发的行列,希望这篇文件能帮助你对产生 Makefile有个简单的依据。其它有关开发 GNU 程式或 C 程式设计及 Makefile 的详细运用及技巧,我建议你从 GNU Coding Standards3 (GNU 编码标准规定) 读起,里面包含了 GNU Makefile 惯例,还有发展 GNU 软体套件的标准程序和惯例。这些 GNU 软体的线上说明文件可以在 http://www.gnu.org/ 这个网站上找到。

6. 结语
经由 Autoconf 及 Automake 的辅助,产生一个 Makefile 似乎不再像以前那麽困难了,而使用 Autoconf 也使得我们在不同平台上或各家 Unix 之间散播及编译程式变得简单,这对於在 Unix 系统上开发程式的人员来 说减轻了许多负担。妥善运用这些 GNU 的工具软体,可以帮助我们更容易 去发展程式,而且更容易维护原始程式码。

admin 编程

vim&gvim技巧大全

2010年7月30日

—————————————-

# 基础
—————————————-
* # g* g#          : 寻找光标处的狭义单词(<cword>) (前向/后向)
%                  : 括号配对寻找 {}[]()
matchit.vim        : 使得 % 能够配对标记 <tr><td><script> <?php 等等
<C-N><C-P>          : 插入模式下的单词自动完成
<C-X><C-L>          : 行自动完成(超级有用)
/<C-R><C-W>        : 把狭义单词 <cword> 写到 搜索命令 行
/<C-R><C-A>        : 把广义单词 <cWORD> 写到 搜索命令 行
:set ignorecase    : 搜索时忽略大小写
:syntax on          : 在 Perl,HTML,PHP 等中进行语法着色
:h regexp<C-D>      : 按下 control-D 键即可得到包含有 regexp 的帮助主题的列表
: (使用TAB可以实现帮助的自动补齐)
—————————————-
# 使更新 _vimrc 更容易
:nmap ,s :source $VIM/_vimrc # 译释:nmap 是绑定一个在normal模式下的快捷键
:nmap ,v :e $VIM/_vimrc
# 译释:在normal模式下,先后按下 ,s 两个键执行_vimrc,而 ,v 则是编辑_vimrc
—————————————-
# visual 模式 (例子是:轻松添加其他的 HTML Tags)
:vmap sb “zdi<b><C-R>z</b><ESC>  :在visual模式下选中的文字前后分别加上<b>和</b>
# 译释:vmap 是绑定一个在visual模式下的快捷键

# 译释:原理:在visual模式下,# 译释:原理:在visual模式下,”zd 把一个选中的区域命名为z 然后删除,
# i 进入插入模式,输入<b>,<C-R>z 撤销刚才的删除,然后再写入</b>,
# 最后<ESC>返回normal模式

# 译释:”z 命令创建一个选中的区域为register,并把它命名为z

# 译释:更令人开心的有:在visual模式下选中几行,然后输入 2> ,
#      则选中的行会全部缩进两个tab
#      555,偶一开始还是用 :x x,xx s/^/\t\t/,好傻啊!

:vmap st “zdi<?= <C-R>z ?><ESC>  :在visual模式下选中的文字前后分别加上<?= 和 ?>
—————————————-
# 文件浏览
:Ex                            : 开启目录浏览器,注意首字母E是大写的
:Sex                            : 在一个分割的窗口中开启目录浏览器
:ls                            : 显示当前buffer的情况
:cd ..                          : 进入父目录
:args                          : 显示目前打开的文件
:lcd %:p:h                      : 更改到当前文件所在的目录
# 译释:lcd是紧紧改变当前窗口的工作路径,% 是代表当前文件的文件名,
# 加上 :p扩展成全名(就是带了路径),加上 :h析取出路径

:autocmd BufEnter * lcd %:p:h  : 自动更改到当前文件所在的目录
# 译释:autocmd指定一个自动命令,BufEnter指定一个事件,* 指定事件的对象,
# lcd %:p:h 指定一个动作
# hehe,好像和写记叙文差不多
—————————————-
# 缓冲区(buffer)浏览器 (第三方的一个最流行的脚本)
# 需要下载 bufexplorer.vim ,http://www.vim.org/script.php?script_id=42 上就有
\be                            : 在缓冲区浏览器中打开缓冲区列表
\bs                            : 以分割窗口的形式打开缓冲区浏览器
—————————————-
# 大小写转换
guu                            : 行小写
gUU                            : 行大写
g~~                            : 行翻转(当然指大小写啦)
# 译释: g 是大小写转换命令(greate),u/U/~是三种转换形式(小写/大写/翻转),
# 最后一个重复则表示该转换是对于一行而言的

guw                            : 字大写(狭义字) 译注:建议对比iw
gUw                            : 字小写(狭义字)
g~w                            : 字翻转(狭义字)
# 译释:最后一个w 表示该转换是对于一个字而言的,由于是在normal模式下,
# 所以这个w 表示一个狭义字<cword>

vEU                            : 字大写(广义字)
vE~                            : 字翻转(广义字)
# 译释:vE 这个指令组合会进入visual模式,然后选择一个广义字<CWORD>

ggguG                          : 把整个文章全部小写(ft!bt!)
gf                              : 取当前光标处的广义字作为文件名,然后试图打开它!
# 译释:为什么是广义字呢?因为这样可以方便的取到路径啊,像/var/www/html/index.htm

ga                              : 显示光标处字符的ascii,hex,oct,…晕菜的一堆转换
ggVGg?                          : 用rot13编码整个文件(晕!)
# 译释:gg到文件首行首字符,V进入Visual-Line模式,G到文件末行首字符,
#      这样就选中了整篇文章,然后g?就是用rot13编码整个文件啦
#
# 【关于rot13——谁让英文是偶数个字母啊】
# ROT13 是一种简单的编码,它把字母分成前后两组,每组13个,编码和解码
# 的算法相同,仅仅交换字母的这两个部分,即:[a..m] –> [n..z] 和 [n..z]
# –> [a..m] 。 ROT13 用简易的手段使得信件不能直接被识别和阅
# 读,也不会被搜索匹配程序用通常的方法直接找到。经常用于 USENET 中发表一
# 些攻击性或令人不快的言论或有简单保密需要的文章。
# 由于 ROT13 是自逆算法,所以,解码和编码是同一个过程。

<C-A>,<C-X>                    : 增加,减少 光标处的狭义字所表示的数字
:(,仅仅是分割了这两个命令,不是命令的一部分)
: Win32的用户可能需要重新定义一下Ctrl-A,呵呵
# 译注:good guy, 令人不得不想到perl的数字串

<C-R>=5*5                      : 插入25 (这是一个迷你计算器耶!)
—————————————-
# 好玩的东东
:h 42            : 也可以访问 http://www.google.com/search?q=42
: 第一个结果就是 News. Douglas Adams 1952 – 2001.
: Floor 42 extends its deepest sympathies to
: the family, friends, and fans of Douglas Adams.
:h holy-grail
:h!
—————————————-
# 标记和移动
‘.              : 跳到最后修改的那一行 (超级有用)(ft,怎么又是这个评价)
`.              : 不仅跳到最后修改的那一行,还要定位到修改点
<C-O>            : 依次沿着你的跳转记录向回跳 (从最近的一次开始)
<C-I>            : 依次沿着你的跳转记录向前跳
:ju(mps)        : 列出你跳转的足迹
:help jump-motions
:history        : 列出历史命令记录
:his c          : 命令行命令历史
:his s          : 搜索命令历史
q/              : 搜索命令历史的窗口
q:              : 命令行命令历史的窗口
:<C-F>          : 历史命令记录的窗口
—————————————-
# 缩写和键盘映射(原文中文件举例都用了c:/aaa/x,偶全给他改成/path/file了,哼唧)
:map  <f7>  :’a,’bw! /path/file
# 译释:map是映射一个normal模式下的键
# 这里是把F7键映射成把标记a到标记b中间的内容另存为一个文件/path/file
# 标记(mark)的方法:把光标移动到需要标记的地方,输入m,然后输入标记名,例如a

# 引用标记的方法:’a ,即:单引号加标记名

:map  <f8>  :r /path/file # 译释:把F8键映射成在当前位置插入文件/path/file的内容
:map  <f11>  :.w! /path/file2<CR>
# 译释:.(点号)表示当前行
# 所以F11就是把当前行存为/path/file2
# 最后的<CR>表示一个回车
:map  <f12>  :r /path/file2<CR>
:ab php          : 列出php表示的缩写
# 译释:定义一个缩写使用::iab hm hmisty
# 一个有趣的现象是,它列出的会是php和它的前子串开头的缩写
# 例如,有这么几个缩写:
# h => hmisty1 , hm => hmisty2 , hmi => hmisty3, m => hmisty4
# 那么使用 :ab hm会显示这么几个缩写:hm 和 h
# 而不是你想象中的 hm 和 hmi

:map ,          : 列出以逗号开始的键盘映射
# 译释:一般而言,我们称这些逗号开始的组合键为“逗号命令”
# 不过hmisty更喜欢用;构成“分号命令”
# 而且不是用map,而是用imap
# 因为偶懒么,懒得按<Esc>,所以直接在insert模式下就执行命令了
# 为什么用分号呢?因为我最常用它写程序啊
# perl/C/C++/object pascal/java,都是用分号结束一个语句
# 我们一般很少在分号后面连续写其他字符
# 所以用“分号+其他键”就很少会在输入的时候造成冲突

# 在键盘映射中常用的表示
<CR>            : 回车
<ESC>            : Esc
<LEADER>        : 转义符号 \
<BAR>            : 管道符号 |
—————————————-
# 列出寄存器(Registers)
:reg            : 显示所有当前的registers
“1p              : “表示引用register,1表示一个名字叫做1的register,
: p就是粘贴(paste)命令
# 译释:”也用来定义register
# 先输入 “,表示定义register
# 然后输入名字,如0~9,a~z
# 然后执行删除或复制命令,如dd或y,
#        或者是visual模式下的d(删除选中的部分)或y(复制选中的部分)
# 则被删除或复制的部分就被存入了这个命名的register
#
# 观察:一个特殊的register, “” ,里面存储了一个匿名的删除/复制
# 在你执行dd或y的时候,被作用的部分被存到了”"中
# 这些和perl是多么像啊
—————————————-
# Useful trick
“ayy@a          : 把当前行作为一个Vim命令来执行
# 译释:”ayy 是定义当前行到register a,然后@a是执行register a中存储的指令
# yy: 复制一行
# 10yy: 复制从此向下的10行

yy@”            : 用上面所提到的那个匿名register
—————————————-
# 从其他程序获取输出 (需要外部程序)
:r!ls.exe        : 读取ls的输出到当前位置
!!date          : 读取date的输出 (但是会替换当前行的内容)
# 译释:其实你输入了!!后,vim就自动转换到 :.! 等待你继续输入

# 使用外部程序sort进行排序(sort是Unix标准命令,ls,date也是)
:%!sort -u      : 使用sort程序排序整个文件(用结果重写文件)
# 译释:%表示整个文件的所有行
# !sort表示执行外部命令sort
# -u是sort的参数,man sort看看,这个参数的意义是合并相同的行
# u就是unique,如果两行内容相同,则结果中只保留一行的说

:’a,’b!sort -u  : 对mark a 到mark b中间的内容进行排序
!1} sort -u      : 排序当前段落 (只能在normal模式下使用!!)
# 译释:!表示使用filter,1}表示filter的对象是从当前行开始向后数一段
# 段落指到空行处结束,不包括空行
# 其实你一旦输入 !1},vim就自动计算当前段落应该到那一行(eg.+5),然后生成
# :.,.+5! 等待之后输入sort -u,回车,完成操作
# .表示当前行,.+5当然就是当前行向后数5行
—————————————-
# 多文档操作 (基础)
# 译注:用 :ls! 可以显示出当前所有的buffer
:bn              : 跳转到下一个buffer
:bp              : 跳转到上一个buffer
:wn              : 存盘当前文件并跳转到下一个(又是“超级……”,ft!)
:wp              : 存盘当前文件并跳转到上一个
:bd              : 把这个文件从buffer列表中做掉
:bun            : 卸掉buffer (关闭这个buffer的窗口但是不把它从列表中做掉)
:badd file.c    : 把文件file.c添加到buffer列表
:b 3            : 跳到第3个buffer
:b main          : 跳到一个名字中包含main的buffer,例如main.c              : (ultra,这个怎么翻译?:()
:sav php.html    : 把当前文件存为php.html并打开php.html
:sav! %<.bak    : 换一个后缀保存
:e!              : 返回到修改之前的文件(修改之后没有存盘)
:w /path/%      : 把文件存到一个地儿
:e #            : 编辑标记为#的buffer(这个buffer必须含有一个可编辑的文件)
: 用ls命令就能看到哪一个buffer有#
: %a表示当前正在编辑的buffer
: u 表示不能编辑或者已经被做掉的buffer
:e #3            : 编辑编号为3的buffer(这个buffer必须含有一个可编辑的文件)
:rew            : 回到第一个可编辑的文件
:brew            : 回到第一个buffer
:sp fred.txt    : 在一个水平分割的窗口中打开文件fred.txt # 译注:vs fred.txt可以实现垂直分割
:sball          : 把当前所有含有可编辑文件的buffer显示到一个分割窗口中              : (偶该考虑把super翻译成 高级指令 了,ft)
:map  <F5> :ls<CR>:e # : 在normal模式下按F5键,则会显示所有含有一个

: 可编辑文件的buffer,然后提示你输入buffer的序号,
: 输入后回车,则编辑这个buffer
# 译注:这是一个键盘绑定

:set hidden      : 允许不保存buffer而切换buffer (w/o=without)
—————————————-
# 在分割窗口中快速切换
:map <C-J> <C-W>j<C-W>_
# 译注:原文此处有误,前面应该加上冒号
# 这是一个键盘绑定,把Ctrl-J定义成切换到下一个窗口并最大化
:map <C-K> <C-W>k<C-W>_
—————————————-
# 命令录制 (最佳技巧,ft)
qq  #录制到q
.. #输入一系列复杂的指令
q  #再次按q停止录制
@q  #执行q中存储的指令
@@  #重复执行
# 编辑register/录制
“ap #把register a中的内容贴到当前位置
.. #现在你可以修改它了
“add#删除之,重新存入register a
@a  #执行register a中的指令
—————————————-
# _vimrc基础
:set incsearch                        : 实时匹配你输入的内容
:set wildignore=*.o,*.obj,*.bak,*.exe : tab键的自动完成现在会忽略这些
:set shiftwidth=4                    : 现在自动缩进将是4个字符
# 译注:一个tab位通常是8个字符
# 所以,我们还要设定 :set tabstop=4,这样,所有的缩进都是4字符了
# emacs默认就是4字符缩进吧?
:set vb t_vb=”.                        : 沉默方式(不要叫beep!)
—————————————-
# 加载windows iexplorer来浏览(我想这只有在windows下用gvim才能用到)
:nmap ,f :update<CR>:silent !start c:\progra~1\intern~1\iexplore.exe file://%:p
# 译释:nmap是做一个normal模式下的键盘绑定
# 这里绑定了一个逗号命令 ,f
# :update是写这个文件,与:w不同,它只有当文件被修改了的时候才写
# :silent别让弹出窗口报告执行结果
# !…后面就是执行windows命令了。呵呵,去问bill gates什么意思吧。
# 不过偶用gvim 6.1试过了,好用!

:nmap ,i :update<CR>: !start c:\progra~1\intern~1\iexplore.exe <cWORD><CR>
—————————————-
# 用VIM编辑ftp文件
:cmap ,r  :Nread ftp://209.51.134.122/public_html/index.html
:cmap ,w  :Nwrite ftp://209.51.134.122/public_html/index.html
# 译注:原文丢失了开头的冒号
# cmap是命令(command)模式绑定

gvim ftp://209.51.134.122/public_html/index.html
# 这一句就是开始编辑一个ftp远端的文件,ft
—————————————-
# 附加到一个register (就是用大写的register名字啦!)
“a5yy #复制5行到a中
10j  #下移10行
“A5yy #再添加5行到a中
—————————————-
[I    : 显示光标处的狭义字可以匹配的行(高级指令)
# 译注:# 可以全文查找与光标处的狭义字相匹配的字,
# 这在查找函数原型和实现,或者变量使用的时候很有用
----------------------------------------
# 常规缩进
:'a,'b>>
# 译释:把mark a到mark b之间的内容进行两次缩进

# 在visual模式下缩进 (无限可重复)
:vnoremap < <gv
# 译释::vnoremap 重定义了visual模式下 < 符号的含义
# 把它定义成 <gv
# 即:先<向外缩进,然后gv重新选择上一次选择了的区域
# 这样在visual模式下就可以实现连续按<而连续缩进了
:vnoremap > >gv
# 同里,内缩
----------------------------------------
# 查找(译注:建议先学习正则表达式)
# 译注:查找命令不用进入:命令模式,直接按/就可以了
# 如果没有修饰,可以不要右边的/
# 和smth bbs差不多啦,呵呵
/joe/e                      : 光标停留在匹配单词最后一个字母处
/joe/e+1                    : 光标停留在匹配单词最后一个字母的下一个字母处
/joe/s                      : 光标停留在匹配单词第一个字母处
/^joe.*fred.*bill/          : ft,标准正则表达式
/^[A-J]\+/                  : 找一个以A~J中一个字母重复两次或以上开头的行
/forum\(\_.\)*pent          : 多行匹配
/fred\_s*joe/i              : 中间可以有任何空白,包括换行符\n
# 译注:这个和perl不太一样的哦
/fred\|joe                  : 匹配FRED或JOE
/\<fred\>/i                : 匹配fred,fred必须是一个独立的单词,而不是子串
# 译注:这和perl也不太一样,perl是用\b做单词定界符的
/\<\d\d\d\d\>              : 匹配4个数字
\<\d\{4}\>                  : 也是匹配4个数字
# 在visual模式下查找
:vmap g/ y/<C-R>”<CR>      : 匹配选中的高亮文字
# 译释:vmap是在visual模式下的键盘映射
# 映射了g/这个命令组合
# y 把选中的高亮文字写入匿名register ”
# / 打开搜索模式
# <C-R> 准备粘贴register
# ” 粘贴了”"中的内容
# <CR> 回车,执行

:vmap <silent> g/    y/<C-R>=escape(@”, ‘\\/.*$^~[]‘)<CR><CR> : with spec chars
# 译释:@#$&^*@#%&*#$@!

# 跨行匹配,\_ 表示允许匹配换行符,或者说,允许匹配新行
# 译注:小心,和perl不一样
/<!–\_p\{-}–>                  : 匹配多行注释
/fred\_s*joe/i                    : 似乎上面有了,ft
/bugs\(\_.\)*bunny                : 中间可以有无数东西
:h \_                            : 看看关于 \_ 的帮助

# 查找当前光标位置所在子例程/函数(subroutine/function)的声明
:nmap gx yiw/^\(sub\<bar>function\)\s\+<C-R>”<CR>
# 译释:nmap 做一个normal模式下的键盘绑定
# y 进入复制状态,后面需要一个motion
# 接着就用 iw 指出了这个motion,是inner word
# inner word也是狭义字<cword>,但是和 w 不同
# w 是从光标位置开始向后看
# 而inner word总是把光标移到第一个字母,从而总能得到一个完整的狭义字
# 试一试 gUw 和 gUiw 就知道区别了,呵呵。

# 在多个文档中搜索
:bufdo /searchstr
:argdo /searchstr
—————————————-
# 替换
# 译注:替换命令需要先进入:命令模式

:%s/fred/joe/igc            : 一个常见的替换命令,修饰符igc和perl中一样意思
:%s/\r//g                  : 删除DOS方式的回车^M
:%s=  *$==                  : 删除行尾空白
:’a,’bg/fred/s/dick/joe/igc : 非常有用!(ft,又来了!)
# 译释:’a,’b指定一个范围:mark a ~ mark b
# g//用一个正则表达式指出了进行操作的行必须可以被fred匹配
# 看后面,g//是一个全局显示命令
# s/dick/joe/igc则对于这些满足条件的行进行替换

# 列复制
# 译注:@#%&^#*^%#$!
:%s= [^ ]\+$=&&=            : 复制最后一列
:%s= \f\+$=&&=              : 一样的功能
:%s= \S\+$=&&              : ft,还是一样 # 反向引用,或称记忆
:s/\(.*\):\(.*\)/\2 :  \1/  : 颠倒用:分割的两个字段
:%s/^\(.*\)\n\1/\1$/        : 删除重复行 # 非贪婪匹配,\{-}
:%s/^.\{-}pdf/new.pdf/      : 只是删除第一个pdf # 跨越可能的多行
:%s/<!–\_.\{-}–>//        : 又是删除多行注释(咦?为什么要说“又”呢?)
:help /\{-}                : 看看关于 非贪婪数量符 的帮助
:s/fred/<c-r>a/g            : 替换fred成register a中的内容,呵呵 # 写在一行里的复杂命令
:%s/\f\+\.gif\>/\r&\r/g | v/\.gif$/d | %s/gif/jpg/
# 译注:就是用 | 管道啦

# 或者
:%s/suck\|buck/loopy/gc    : 或者(或者需要\,ft!,|不是或者)
# ft, \不就是转义了么!这个和perl真是不同了!

# 调用VIM函数
:s/__date__/\=strftime(“%c”)/ : 插入时间串

# 处理列,替换所有在第三列中的str1
:%s:\(\(\w\+\s\+\)\{2}\)str1:\1str2:

# 交换第一列和最后一列 (共4列)
:%s:\(\w\+\)\(.*\s\+\)\(\w\+\)$:\3\2\1:

# filter all form elements into paste register
# 把所有的form元素(就是html里面的form啦)放到register里?
# ft, 头疼,不解释了
:redir @*|sil exec ‘g#<\(input\|select\|textarea\|/\=form\)\>#p’|redir END
:nmap ,z :redir @*<Bar>sil exec ‘g@<\(input\<Bar>select\<Bar>textarea\<Bar>/\=fo
# 上面这一行不能完全显示,最好Copy Article下去看

—————————————-
# 全局(global)显示命令,就是用 :g+正则表达式
# 译释: :g/{pattern}/{cmd} 就是全局找到匹配的行
# 然后对这些行执行命令{cmd}
:g/\<fred\>/                : 显示所有能够为单词fred所匹配的行
:g/<pattern>/z#.5          : 显示内容,还有行号,呵呵
:g/<pattern>/z#.5|echo “==========”  : 漂亮的显示,ft!

# 全局命令 (其他)
:g/^\s*$/d                  : 删除所有空行
:g!/^dd/d                  : 删除不含字串’dd’的行
:v/^dd/d                    : 同上 # 译释:v == g!,就是不匹配!
:g/fred/,/joe/d            : not line based (very powerfull)
:v/./.,/./-1join            : 压缩空行
:g/^$/,/./-j                : 压缩空行
:g/<input\|<form/p          : 或者 要用\|
:g/^/pu _                  : 把文中空行扩增一倍 (pu = put)                        : 即:原来两行间有一个空行,现在变成2个
:g/^/m0                    : 按行翻转文章 (m = move)
:g/fred/t$                  : 拷贝行,从fred到文件末尾(EOF)
:%norm jdd                  : 隔行删除
# 译释:% 指明是对所有行进行操作
# norm指出后面是normal模式的指令
# j是下移一行,dd是删除行

# incrementing numbers
:.,$g/^\d/exe “norm! \<c-a>” : 增加在BOL(beginning of line)处的数字
# 译注:.,$ 指明命令从当前行执行到最后一行
# 如果没有 .,$ 限定范围,那么g//就会对整个文件进行操作
# exe 是执行后面的命令组合

:.,$g/^\d/exe “norm \<c-p>”  : Win32下必须重定义Ctrl-A

# 保存全局命令的结果 (注意必须使用添加模式)
:g/fred/y A                : 添加所有为fred所匹配的行到register a
:’a,’b g/^Error/ . w >> errors.txt

# 复制每一行,然后在复制出来的每一行两侧加上一个 print ‘复制出来的内容’
:g/./yank|put|-1s/’/”/g|s/.*/Print ‘&’/
—————————————-
# 全局命令和替换命令联姻 (强大的编辑能力)
:’a,’bg/fred/s/joe/susan/gic : 可以使用反向引用来匹配
:g/fred/,/joe/s/fred/joe/gic :  non-line based (ultra)
—————————————-
# 先找fred,然后找joe,然后#$^$%^#$%^@%^%&%^*!
:/fred/;/joe/-2,/sid/+3s/sally/alley/gIC
—————————————-
# 重定向到register * 和 粘贴register *
:redir @*                    : 重定向命令的输出结果(最下方命令行上的结果)                          : 到register * (ft,* 代表0~1,a~z,..)
:redir END                  : 结束重定向
# 处理粘贴
“*yy                        : 上面讲过了,就是复制到register *中
“*p                          : 然后贴出来
—————————————-
:redir >> out.txt            : 重定向到一个文件
—————————————-
# 重新格式化文本
gq<CR>
gqap  (a是motion p是段落(visual模式))
ggVGgq  重新格式化整个文章
—————————————-
# 对多个文档实施命令
:argdo %s/foo/bar/          : 对所有:args列表中的文档执行命令
:bufdo %s/foo/bar/
:windo %s/foo/bar/
:argdo exe ‘%!sort’|w!      : 使用外部命令
—————————————-
# 命令行的一些好玩的东东
gvim -h                    : 启动的时候启动帮助(Win32)
vi -h 或 vim -h            : 这个是unix下用
ls | gvim -                : 编辑一个数据流!
gvim -o file1 file2        : 以分割窗口打开两个文件

# 指出打开之后执行的命令
gvim.exe -c “/main” joe.c  : 打开joe.c,然后跳转到’main’

# 对一个文件执行多个命令
vim -c “%s/ABC/DEF/ge | update” file1.c

# 对一组文件执行多个命令
vim -c “argdo %s/ABC/DEF/ge | update” *.c

# 自动编辑文件 (编辑命令序列Ex commands已经包含在convert.vim中了)
vim -s “convert.vim” file.c

# 不要加载.vimrc和任何plugins (启动一个干净的VIM)
gvim -u NONE -U NONE -N
—————————————-
# GVIM 不同的地方
gvim -d file1 file2        : vimdiff (比较不同)
dp                        : 把光标处的不同放到另一个文件
do                        : 在光标处从另一个文件取得不同
—————————————-
# Vim陷阱
# 在vim的正则表达式中, + 和 | 都必须加转义符 \
# 小心,这和perl不一样!
/fred\+/      : 匹配fred或freddy但是不匹配free
—————————————-
# \v ,或叫做very magic (通常都是这么叫)可以取消转义符
/codes\(\n\|\s\)*where  : 普通的正则表达式
/\vcodes(\n|\s)*where  : very magic,| 不用加 \ 了!

—————————————-
# 把东西送到命令行/搜索行 (SUPER:偶不再翻译这种叹词了)
<C-R><C-W>              : 送一个狭义词
<C-R><C-A>              : 送一个广义词
<C-R>-                  : 送一个小型删除寄存器register
<C-R>[0-9a-z]          : 送一个命名寄存器register
<C-R>%                  : 送文件名过去 (#也行)
—————————————-
# 操作寄存器
:let @a=@_              : 清除register a
:let @*=@a              : 寄存器赋值
:map  <f11> “qyy:let @q=@q.”zzz”
# 译注:猜猜这个无聊的绑定是什么意思?
—————————————-
# 关于帮助的帮助
:h quickref            : 翻到VIM Quick Reference页(有用!)
:h tips                : Vim自己的tips
:h visual<C-D><tab>    : 得到一个关于visual关键字的帮助列表                    : 然后用tab键去选择
:h ctrl<C-D>            : 显示所有关于Ctrl的帮助
:h :r                  : :ex冒号命令
:h CTRL-R              : 普通模式命令
:h \r                  : \r在正则表达式中是什么意思呢?
:h i_CTRL-R            : insert模式下的Ctrl-R
:h c_CTRL-R            : 命令行(command-line)模式下的Ctrl-R
:h v_CTRL-V            : visual模式下的Ctrl-V
:h tutor                : VIM 指南
gvim -h                : 关于 VIM 命令的帮助
vi/vim -h
<C-S>T                  : Control Shift T go backwards in help
: 偶不清楚有什么用:(
—————————————-
# 选项设置在哪里?
:scriptnames            : 列出所有加载的 plugins, _vimrcs
:verbose set history    : 显示history的值并指出设置文件的位置
—————————————-
# 制作你自己的VIM帮助
:helptags /vim/vim61/doc  : 重建 /doc 中所有的 *.txt 帮助文件
:help add-local-help
—————————————-
# 用外部程序来运行程序 (例如 perl :)
map  <f2>  :w<CR>:!perl -c %<CR>
# 译释::w<CR>写文件
# :!perl -c %<CR>用perl来运行当前文件
# 当前文件必须有文件名!
—————————————-
# 插入DOS换行符
:%s/nubian/<C-V><C-M>&/g          :  Ctrl-V是一种转义,它说要解释<C-M>
:%s/nubian/<C-Q><C-M>&/g          :  对于Win32应该这样
:%s/nubian/^M&/g                  :  你看到的^M是一个字符
:%s/nubian/\r&/g                  :  更好的形式
—————————————-
# 把最后一个命令贴到当前位置
i<c-r>:
# 把最后一个搜索指令贴到当前位置
i<c-r>/
# 译释:i是进入insert模式,
# Ctrl-r是开启插入模式下register的引用
# :和/分别引用了两个register的内容
—————————————-
# 更多的完成功能
<C-X><C-F>                        :插入当前目录下的一个文件名到当前位置
# 在insert模式下使用
# 然后用 Ctrl-P/Ctrl-N 翻页
—————————————-
# 替换一个visual区域
# 选择一个区域,然后输入 :s/Emacs/Vim/ 等等,vim会自动进入:模式
:’<,’>s/Emacs/Vim/g              : 前面的’<,’>是vim自动添加的
—————————————-
# 在文件中插入行号(不是显示行号,是插入!)
:g/^/exec “s/^/”.strpart(line(“.”).”    “, 0, 4)
—————————————-
# 用VIM的方式来编号行
:set number                      :显示行号
:set nonu                        :取消显示
:%s/^/\=strpart(line(‘.’).”        “,0,&ts)

#从任意行开始编号(需要perl,嘿嘿)
:’a,’b!perl -pne ‘BEGIN{$a=223} substr($_,2,0)=$a++’
#似乎有点小问题,你试试看:)

qqmnYP`n^Aq                      : 记录到q 然后用 @q 重复
#似乎不能工作,你试试看:)

# 递增已存在数字到文件末
:.,$g/^\d/exe “normal! \<c-a>”

# 高级递增,看:
http://vim.sourceforge.net/tip_view.php?tip_id=150
—————————————-
# 高级递增 (“真的很有用”,ft)
” 把下面几句放到 _vimrc #vimrc脚本用 ” 做行注释符
let g:I=0
function! INC(increment)
let g:I =g:I + a:increment
return g:I
endfunction
” 例如从mark a 到mark b 递增,从223开始,步长为5
:let I=223
:’a,’bs/$/\=INC(5)/
” (原文:create a map for INC)
” 但是cab是清楚命令行缩写啊?怎么回事?
cab viminc :let I=223 \| ‘a,’bs/$/\=INC(5)/
—————————————-
# 加密(小心使用,不要忘了密码)

:X                                : 然后vim会提示你输入密码
:h :X
—————————————-
# modeline (make a file readonly etc) must be in first/last 5 lines
# 不会用,不翻了
// vim:noai:ts=2:sw=4:readonly:
:h modeline
—————————————-
# Creating your own GUI Toolbar entry
# 对于text模式下的vim没用,不翻了
amenu  Modeline.Insert\ a\ VIM\ modeline <Esc><Esc>ggOvim:ff=unix ts=4 ss=4<CR>v
—————————————-
# 一个保存当前光标下的狭义字到一个文件的函数
function! SaveWord()  “这里用!是强制覆盖以前的定义
normal yiw
exe ‘:!echo ‘.@0.’ >> word.txt’
endfunction
map ,p :call SaveWord() #使用该函数的一个例子
—————————————-
# 删除重复行的函数
function! Del()
if getline(“.”) == getline(line(“.”) – 1)
norm dd
endif
endfunction

:g/^/ call Del() #使用该函数的一个例子
—————————————-
# 双字节编码 (non alpha-numerics)
:digraphs                        : 显示编码表
:h dig                            : 帮助
i<C-K>e’                          : 输入 é
i<C-V>233                        : 输入 é (Unix)
i<C-Q>233                        : 输入 é (Win32)
ga                                : 查看字符的hex值
—————————————-
# 文件名自动完成 (例如 main_c.c)
:e main_<tab>                    : tab 键完成
gf                                : 打开光标处广义字命名的文件 (normal模式)
main_<C-X><C-F>                  : 文件名自动完成(insert模式)
—————————————-
# Vim复杂使用
# 交换两个单词
:%s/\<\(on\|off\)\>/\=strpart(“offon”, 3 * (“off” == submatch(0)), 3)/g
—————————————-
# 把text文件转换成html文件(oh,ft)
:runtime! syntax/2html.vim        : 转换 txt 成 html
:h 2html                          : 看看帮助
—————————————-
# VIM 有一个内部自带的 grep 命令
:grep some_keyword *.c            : 得到一个包含some_keyword的c文件名列表
:cn                              : 去下一个出现的位置
—————————————-
# 强制无后缀文件的语法着色方式 .pl
:set syntax=perl # 取消语法着色
:set syntax off # 改变色彩主题 (在~vim/vim??/colors中的任何文件)
:colorscheme blue —————————————-
:set noma (non modifiable)        : 防止修改
:set ro (Read Only)              : 只读保护
—————————————-
# Sessions (打开一系列文件)
gvim file1.c file2.c lib/lib.h lib/lib2.h :在”session”中加载一系列文件
:mksession                        : 生成一个Session文件 (默认是Session.vim)
:q
gvim -S Session.vim              : 重新读取一个session,也就读取了所有文件,ft
—————————————-
# 标记(tags) (跳转到subroutines/functions)
taglist.vim                      : 最流行的插件
:Tlist                            : 显示Tags (functions的列表)
<C-]>                            : 跳转到光标处的function
: 这个键 Ctrl-] 和vim帮助中是一样的
—————————————-
# Just Another Vim Hacker JAVH
# Juat Another Perl Hacker JAPH,嘿嘿
vim -c “:%s/^/WhfgTNabgureRIvzSUnpxre/|:%s/[R-T]/ /Ig|:normal ggVGg?”
# 译释:呵呵,谁来解释一下吧!
# 其实不过是在启动vim的时候执行了一个命令
# 先写入了 Just Another Vim Hacker 的rot13编码
# 然后再解码
—————————————-
终于翻完了,呵呵。好累啊!
__END__


hmisty, hey misty!
H misty
Haow Much I’m Special To You
vi 剪贴操作补充(一)

强烈建议大家先看看 doc/change.txt 里关于寄存器部分的内容,
只是简单提及一下,英文不太好的朋友请找 vim 的中文文档。
我要介绍的超强武器是 ctrl-r,在 insert mode
和 command mode 均可使用,功能就是插入寄存器相关内容。
大家可以试试先 copy 或 delete 一些文本,然后在
normal mode 或 command mode 输入 ctrl-r “,看到了吗,
你粘贴了寄存器”的内容。

寄存器的主要有以下几种:
a. The unnamed register “”
“d”, “c”, “s”, “x” 和 “y” 等涉及删除或拷贝的命令
都会将内容存放于此(有例外)。

b. 10 numbered registers “0 to “9
0 为最近拷贝的内容,1-9 为最近删除的内容。
指定 named register 时不会存放于此。

c. The small delete register “-
删除不多于一行的内容会存在于此。

d. 26 named registers “a to “z or “A to “Z
小写与大写的区别是,小写是覆盖方式,大写是添加方式。

e. four read-only registers “:, “., “% and “#
“. 存放上次插入的文本
有什么用?呵,例如,你输入了一段文本,在另一个地方也
要有相同的内容,你输完后,一般要选择并复制一下吧?
而用这个,直接移到需要插入的地方,i<ctrl-r>. 即可。
“% 是当前编辑文件全名
呵,vim 中,% 就是代表当前编辑文件名的变量,好记吧?
不过,一般直接用 % 就行,例如”:!cat %”,vim 会自动
扩展。
“# 是alternate file 名称 (这个我不知道)
“: 上次执行的命令
记起来比较容易,冒号就是命令行提示符嘛。这个有些什么用呢?
在测试配置文件时十分有用,先在命令行输入命令,调试好后,
在 insert mode 里按Ctrl-R : 就可将该命令插到文件中。

f. the expression register “=
呵,表达式寄存器,可以输入一个表达式,并插入结果。

g. The selection and drop registers “*, “+ and “~
跟 gui 即 X/Windows 剪贴板有关的变量。
在 X 中,鼠标中键与系统剪贴板不一样,至于区别,大家自己
试验一下,这里给个提示,在命令行下输入 reg 可以列出所有
寄存器的内容。
h. The black hole register “_
黑洞

i. Last search pattern register “/
上次搜索的内容。例如,我要搜索一个单词 linuxforum,但我
比较懒,先输入 /linux,发现出现很多个 linux,多次按 n 无果,
难道要重新输入 /linuxforum ? 不用,只需要 /<ctrl-r>/forum 即可。
呵,聪明的你一定想到了,用命令行历史也可以调来,按 ctrl-p 或 ctrl-n
即可上下翻阅。这样也可以嘛,也比较快捷,但要查找 forumlinux 呢?
用 ctrl-r 的话只需 /forum<ctrl-r>/ 。

vim 使用技巧
作者: camry.wu

我是 vim 粉丝, 用了许久, 有一些自己的感受, 又到处挖到一些别人的技巧. 感觉对 vim
粉丝比较有用, 就把它记在这儿. 希望借此文套出大家自己的巧活, 就正应了抛砖引玉的古
话了.

先稍为介绍一下 vim. vi 是 unix/linux 下极为普遍的一种文本编辑器, 大部分机器上都
有. vi 有各种变种, 在不同的机器上常用不同的变种软件. 其中 vim 比较好用也用得比较
广泛. vim 是 Vi IMproved 的缩写, 表示更好的 vi. 我个人觉得它是非常好的编辑器(为
了避免 Emacs 粉丝挑眼, 就不说最好了). 没用过的也建议试试看, 当然 vim 对编写文本
文件很方便好用, 比如编写程序, html文档等等, 却不能用来编写 word 文档.

关于 vim 的安装, 基本使用方法等网络上能搜出许多, 就不在这里罗嗦了, 要是对 vim 有
兴趣, 那就看看这里(中文文档): http://vcd.cosoft.org.cn/pwiki/index.php

本文就说些其中比较有用, 比较常用的命令, 若能熟练运用这些命令, 那么会发现编辑文件
很舒服.

说明:
以下的例子中 xxx 表示在命令模式下输入 xxx 并回车
以下的例子中 :x xx 表示在扩展模式下输入 xxx 并回车
小括号中的命令表示相关命令.
在编辑模式或可视模式下输入的命令会另外注明.

1. 查找

/xxx(?xxx)      表示在整篇文档中搜索匹配xxx的字符串, / 表示向下查找, ? 表示
向上查找.其中xxx可以是正规表达式,关于正规式就不多说了.
一般来说是区分大小写的, 要想不区分大小写, 那得先输入
:set ignorecase
查找到以后, 再输入 n 查找下一个匹配处, 输入 N 反方向查找.

*(#)            当光标停留在某个单词上时, 输入这条命令表示查找与该单词匹配的
下(上)一个单词. 同样, 再输入 n 查找下一个匹配处, 输入 N 反方
向查找.

g*(g#)          此命令与上条命令相似, 只不过它不完全匹配光标所在处的单词, 而
是匹配包含该单词的所有字符串.

gd              本命令查找与光标所在单词相匹配的单词, 并将光标停留在文档的非
注释段中第一次出现这个单词的地方.

%              本命令查找与光标所在处相匹配的反括号, 包括 () [] {}

f(F)x          本命令表示在光标所在行进行查找, 查找光标右(左)方第一个x字符.
找到后:
输入 ; 表示继续往下找
输入 , 表示反方向查找

2. 快速移动光标
在 vi 中, 移动光标和编辑是两件事, 正因为区分开来, 所以可以很方便的进行光标定
位和编辑. 因此能更快一点移动光标是很有用的.

w(e)            移动光标到下一个单词.
b              移动光标到上一个单词.

0              移动光标到本行最开头.
^              移动光标到本行最开头的字符处.
$              移动光标到本行结尾处.

H              移动光标到屏幕的首行.
M              移动光标到屏幕的中间一行.
L              移动光标到屏幕的尾行.
gg              移动光标到文档首行.
G              移动光标到文档尾行.
c-f            (即 ctrl 键与 f 键一同按下) 本命令即 page down.
c-b            (即 ctrl 键与 b 键一同按下, 后同) 本命令即 page up.

”              此命令相当有用, 它移动光标到上一个标记处, 比如用 gd, * 等查
找到某个单词后, 再输入此命令则回到上次停留的位置.

‘.              此命令相当好使, 它移动光标到上一次的修改行.

`.              此命令相当强大, 它移动光标到上一次的修改点.

3. 拷贝, 删除与粘贴
在 vi 中 y 表示拷贝, d 表示删除, p 表示粘贴. 其中拷贝与删除是与光标移动命令
结合的, 看几个例子就能够明白了.

yw              表示拷贝从当前光标到光标所在单词结尾的内容.
dw              表示删除从当前光标到光标所在单词结尾的内容.
y0              表示拷贝从当前光标到光标所在行首的内容.

admin Linux

Fedora sudo 和root权限添加

2010年7月29日

在LINUX里当我们需要执行一条root权限的命令时,每次都要su到root,总是有些不方便?那么我们可以用sudo代替它。fedora 默认新建的用户不在sudo组,但可以编辑/etc/sudoers文件将普通用户加入sudo组。要注意的是修改该文件只能使用visudo命令:
1、首先切换到root
#su -
(注意有- ,这和su不同,在用命令”su”的时候只是切换到root,但没有把root的环境变量传过去,还是当前用户的环境变量,而使用带横线参数的”su -”命令则将环境变量也一起转换过去,就象用root登录一样)
2、然后
#visudo
这个和vi的用法一样,移动光标,到最后一行,按a,进入append模式,输入以下这行内容
去掉下面这行的注释:

%wheel ALL=(ALL)             ALL

将user添加到wheel组中:
su -c 'gpasswd -a <username> wheel'

3、测试 sudo
测试以上是否正确配置了 sudo ,只需要在普通用户权限下输入
$ sudo whoami
如果配置正确,则命令会返回“root”字样。


				

admin RedHat系列教程

迅雷/快车/旋风地址转换原理分析

2010年7月28日
首先呢,要说说Base64编码。
Base64编码是一种加密/解密字符串的算法
他可以把一段字符串A通过特定的加密算法变成字符串B
并且单凭你的肉眼是无法通过B来反推出A来
但通过逆推算法便能很迅速的将字符串B转换为字符串A
这就是加密/解密字符串的算法。
简单的来说,Base64编码的特点就是
加密解密速度快,并且须通过特定算法解密。

下面这段代码就是一段通过Base64加密后的字符串
5qyi6L+O5p2l5Yiw5LuY552/55qE6YOo6JC95qC844CC

通过肉眼你根本无法知道这段代码的意义,以下则是解密后的字符串
欢迎来到付睿的部落格。

下面开始说说实质性的东西。
Base64是较为常见的一种用于传输8Bit字节代码的编码方式之一,他要求把3个8Bit的字节转换为4个6Bit的字节,既3×8=4×6=24, 然后把6Bit高位用0补成8Bit,使得3个8bit原文变成4个8Bit字节的代码,所以说转换后的字符串会比原字符串长。

举个例子(仅仅是个例子e113)
原文为 qweqweqw asdasdas zxczxczx
转换后 00qweqwe 00qwasda 00sdaszx 00czxczx

转换后的字符串对应一个编码表,即Base64编码的码表(摘自RFC2045)
Table 1: The Base64 Alphabet
Value Encoding Value Encoding Value Encoding Value Encoding
0 A 17 R 34 i 51 z
1 B 18 S 35 j 52 0
2 C 19 T 36 k 53 1
3 D 20 U 37 l 54 2
4 E 21 V 38 m 55 3
5 F 22 W 39 n 56 4
6 G 23 X 40 o 57 5
7 H 24 Y 41 p 58 6
8 I 25 Z 42 q 59 7
9 J 26 a 43 r 60 8
10 K 27 b 44 s 61 9
11 L 28 c 45 t 62 +
12 M 29 d 46 u 63 /
13 N 30 e 47 v
14 O 31 f 48 w (pad) =
15 P 32 g 49 x
16 Q 33 h 50 y

如此一来便能使4个8Bit的译文有对应的字符代表。
那么再来看一个实际的例子(2进制表示)

转换前 10101101 10111010 01110110
转换后 00101011 00011011 00101001 00110110
十进制 43 27 41 54
对应值 r b p 2

所以说编码后字符串为 rbp2
如此也可以逆向推算出原文。

但是,我们也可能遇到一个问题
就是如果原文字节数是10,11或者13该怎么办?(非3整数倍)
Base64编码是这样来解决的:
原文字节不够的地方全部用0来补足,转换时用=代替。
但是编码后的字符串不会含有2个以上的=,因为等号个数=原文字节数 mod 3

ok,这就是简单的Base64编码的介绍。
当然,我是看了老罗的文章后才了解到的。

接下来,说说专用链和Base64的关系。
其实呢,说白了专用链就是使用了Base64编码,因为我之前提到的Base64的特点,他的高速的加密以及解密。
接下来我将是用一个软件的下载地址来做示范,讲解3种程序的专用链。

例子的下载地址是(此链接不存在,仅作为演示)
http://www.free-z.net/1.rar

迅雷专用链
迅雷的专用链是在原地址的前面加“AA”,最后加“ZZ”后再是用Base64加密
即使用Base64编码如下字符串
AAhttp://www.free-z.net/1.rarZZ

编码后字符串为
QUFodHRwOi8vd3d3LmZyZWUtei5uZXQvMS5yYXJaWg==

迅雷专用链即在此字符串前加thunder://,即
thunder://QUFodHRwOi8vd3d3LmZyZWUtei5uZXQvMS5yYXJaWg==

快车专用链
快车的专用链是在原地址的前面和后面都加上“[FLASHGET]”后再是用Base64加密
即使用Base64编码如下字符串
http://www.free-z.net/1.rar

编码后字符串为
W0ZMQVNIR0VUXWh0dHA6Ly93d3cuZnJlZS16Lm5ldC8xLnJhcltGTEFTSEdFVF0=

快车专用链即在此字符串前加Flashget://,尾部加&freeznet,即
Flashget://W0ZMQVNIR0VUXWh0dHA6Ly93d3cuZnJlZS16Lm5ldC8xLnJhcltGTEFTSEdFVF0=&freeznet

腾讯旋风专用链
腾讯旋风专用链是最为简单的,直接将原地址Base64编码即可,即
对字符串http://www.free-z.net/1.rar直接编码,可获得
aHR0cDovL3d3dy5mcmVlLXoubmV0LzEucmFy

然后在此字符串之前加qqdl://即可,即
qqdl://aHR0cDovL3d3dy5mcmVlLXoubmV0LzEucmFy

admin 参考消息

包你能学会的技术:Linux内核入门集

2010年7月27日

包你能学会的技Linux内核入

取内核代

Linux内核一直都被视为学习Linux最难的一块,相信大家也一定看过不少关于内核的文章,但扪心自问,你现在究竟掌握了多少?本文将从零开始介绍被视为高深的Linux内核,内容涉及内核源代码的下载,编译,安装,以及内核开发相关的内容。

如何Linux内核源代

下载Linux内核当然要去官方网站了,网站提供了两种文件下载,一种是完整的Linux内核,另一种是内核增量补丁,它们都是tar归档压缩包。除非你有特别的原因需要使用旧版本的Linux内核,否则你应该总是升级到最新版本。

使用Git

由Linus领头的内核开发队伍从几年前就开始使用Git版本控制系统管理Linux内核了,而Git项目本身也是由Linus创建的,它和传统的CVS不一样,Git是分布式的,因此它的用法和工作流程很多开发人员可能会感到很陌生,但我强烈建议使用Git下载和管理Linux内核源代码。

你可以使用下面的Git命令获取Linux内核代码树的最新“推送”版本:

$ git clone git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6.git

然后使用下面的命令将你的代码树与Linux的代码树最新状态同步:

$ git pull

安装内核源代

内核包有GNU zip(gzip)和bzip2格式。Bzip2是默认和首选格式,因为它的压缩比通常比gzip更好,bzip2格式的Linux内核包一般采用linux-x.y.z.tar.bz2形式的文件名,这里的x.y.z是内核源代码的具体版本号,下载到源代码包后,解压和抽取就很简单了,如果你下载的是bzip2包,运行:

$ tar xvjf linux-x.y.z.tar.bz2

如果你下载的是gzip包,则运行:

$ tar xvzf linux-x.y.z.tar.gz

无论执行上面哪一个命令,最后都会将源代码解压和抽取到linux-x.y.z目录下,如果你使用Git下载和管理内核源代码,你不需要下载tar包,只需要运行git clone命令,它就会自动下载和解压。

内核源代码通常都会安装到/usr/src/linux下,但在开发的时候最好不要使用这个源代码树,因为针对你的C库编译的内核版本通常也链接到这里的。

Linux内核开发人员会将自己的修改做成补丁与其它人员分享,而且补丁是增量的,增量补丁是从一个内核树移动到另一个内核树的有效方法,不用下载完整的内核包就可以升级内核,不仅可节省带宽,也节省了内核升级时间,应用补丁之前先进入内核源代码树所在目录,然后运行:

$ patch –p1 < ../patch-x.y.z

注意,补丁包也有明确的版本号,这里的版本号与Linux内核源代码的版本号要一致,内核和补丁版本号不一致时,强制应用补丁会引起意想不到的后果。

内核源代码树

内核源代码树分为许多目录,它们下面又包含许多子目录,源代码树的顶级目录及其描述参见下表。

描述
arch 特定架构的源代码
block 块I/O层
crypto 加密API
Documentation 内核源代码文档
drivers 设备驱动
firmware 使用某个驱动需要的设备固件
fs VFS和独立文件系统
include 内核头
init 内核启动和初始化
ipc 进程间通信
kernel 核心子系统,如调度器
lib 助手例行程序
mm 内存管理子系统和VM
net 网络子系统
samples 示例,示范代码
scripts 用于生成内核的脚本
security Linux安全模块
sound 声音子系统
usr 早期的用户空间代码(叫做initramfs)
tools 辅助Linux开发的工具
virt 虚拟化基础设施

在源代码树的根目录下还有很多文件需要说明,COPYING是内核许可描述文件(即GNU GPL v2),CREDITS是参与Linux内核的开发人员名单,MAINTAINERS列出了维护各个子系统和驱动的个人,Makefile是内核Makefile的基础。

生成内核

生成内核其实很简单,甚至比编译和安装其它系统级组件,如glibc还要简单,从2.6版本开始,Linux内核引入了一个新的配置和生成系统,它使生产内核的操作变得更加简单了。

配置内核

既然已经拿到内核源代码,那我们在开始编译前就可以根据需要自行配置和定制,可以编译你指定的功能和想要的驱动,配置内核是生成内核必须的一步,因为内核提供了大量的功能,支持各种不同的硬件,有很多都需要配置,内核配置是由配置选项控制的,配置选项都有CONFIG前缀,例如,对称多处理(SMP)是由CONFIG_SMP配置选项配置的,如果设置了这个选项,SMP就被启用了,反之则被禁用,配置选项可以确定会生成哪个文件,也可以通过预处理指令操控代码。

配置选项可以控制生成过程要么是布尔型,要么是三态型,布尔型就是“是”或“否”,大部分内核配置选项都属于布尔型,如CONFIG_PREEMPT,而三态型则在“是”和“否”的基础上,又增加一个“模块”选项,模块选项表示配置选项被设置了,但最后会编译成模块,而不是直接编译进内核,模块可以理解为可独立动态载入的对象,一般来说,驱动配置通常都是三态型。

配置选项也可以是字符串或整数,这样的选项不会控制生成过程,指定的值由内核源代码访问预处理宏时使用,例如,可以为某个配置选项指定静态分配数组的大小。

Linux厂商也会随发行版提供预编译的内核,如Canonical为Ubuntu,或Red Hat为Fedora提供的内核,这样的内核通常只启用了需要的内核功能,几乎所有驱动都被编译成模块了,这样的内核提供了一个良好的基础内核和广泛的硬件模块支持,无论如何,想要成为内核高手,你应该编译自己的内核。

值得庆幸的是,内核提供了很多工具简化配置 ,最简单的工具是基于文本命令行的实用程序,如:

$ make config

这个工具会一个选项一个选项地配置,但用户需要参与,如指定“是(y)”,“否(n)”还是“模块(m)”,整个配置过程需要很长的时间,因此,除非是有人按小时计费请你升级内核,实在找不出别的理由用这种最原始的方法配置内核了,相反,有现成的基于ncurses的图形化工具可以代替。

$ make menuconfig

或是基于gtk+的图形化工具

$ make gconfig

上述三个工具都将配置选项分成多个类别,如“处理器类型和特征”,你可以在这些类别上来回移动,查看内核选项,当然也可以修改它们的设置了。

下面这个命令会根据你的架构创建一个默认的配置基础。

$ make defconfig

虽然默认配置有些武断(在i386上,默认配置是由Linus配置的),但如果你从未配置过内核,它提供了一个良好的开端。

配置选项存储在源代码树根目录下一个名叫.config的文件中,你可以打开这个文件手工编辑其中的配置选项,修改后或要在新的内核源代码树上应用现有配置文件,你可以使用下面的命令验证和更新配置:

$ make oldconfig

在生成内核之前必须运行这个命令。

配置选项CONFIG_IKCONFIG_PROC指定了完整的内核配置文件压缩包位置,默认是/proc/config.gz,这样在生成新内核时要克隆现有的配置就变得非常简单了。如果你当前的内核开启了这个选项,你可以从/proc拷贝该配置文件,然后在此基础上生成新的内核:

$ zcat /proc/config.gz > .config   $ make oldconfig

内核配置好后,使用下面的命令进行生成:

$ make

和2.6以前的内核不一样,在生成内核前不再需要执行make dep命令了,依赖树会自动维护,也不需要再指定特定的生成类型,如bzImage,或独立生成模块,默认Makefile规则会自动处理好一切。

将干信息最小化

在生成过程中会遭到警告和错误的干扰。最小化干扰信息的一个诀窍是重定向make的输出,但仍然会看到一些警告和错误:

$ make > ../detritus

如果你想查看生成输出,你可以事后阅读这个文件,如果你完全不想看到任何输出,那么就重定向到/dev/null:

$ make > /dev/null

时执行多个生成作

Make命令提供了一个功能可以将生成过程拆分成多个平行的作业,这些作业可以独立运行,也可以并行运行,在多处理器系统上可以极大地提高生成速度,也提高了处理器利用率,因为生成大型源代码树会出现大量的I/O等待时间。

默认情况下,make只能拆分成一个作业,因为Makefiles常常会包含不正确的依赖信息,如果真是这样,多个并行执行的作业将会引起混乱,最终会导致生成过程失败,如果Makefiles中的依赖信息无误,那么完全可以拆分成多个作业执行,如:

$ make –jn

这里的n表示拆分的作业数量,通常按每个处理器拆分成1-2个作业,例如,在一个16核心的机器上 ,你可以运行:

$ make -j32 > /dev/null

使用distcc或ccache等优秀的工具也可以大大提高生成速度。

安装新内核

内核生成好之后,你需要安装它,如何安装于系统架构和引导加载程序有关,我们以x86架构,grub引导加载程序为例进行说明。

首先将arch/i386/boot/bzImage拷贝到/boot,重命名为vmlinuz- version,这里的version也是版本号,然后编辑/boot/grub/grub.conf,为新内核添加相应的项目,如果是使用LILO引导装载程序,则修改/etc/lilo.conf文件,然后运行lilo。

模块的安装与系统架构无关,都是自动完成的,以root用户运行:

% make modules_install

这个命令会将所有编译好的模块安装到/lib/modules下对应的子目录中。

生成过程会在源代码树根目录下创建一个System.map文件,它包含一个符号查找表,映射内核符号到它们的起始地址,在调试期间可以用它将内存地址转换成函数和变量名。

可能会遇到的问题

与普通用户空间的应用程序相比,Linux内核有多个特殊的属性,下面是我认为最重要的一些不同:

◆内核既不访问C库也不访问标准C头;

◆内核是用GNU C编码的;

◆内核缺少用户空间提供的内存保护;

◆内核不能容易地执行浮点运算;

◆内核有一个小型的固定大小的进程堆栈;

◆由于内核支持异步中断和SMP,因此同步和并发是内核主要担心的问题;

◆可移植性也很重要。

下面我们就逐个来了解一下这些问题,所有内核开发人员都必须记住它们。

libc

和用户空间应用程序不一样,内核并没有链接到标准的C库,也没有链接到任何其它的库,这样设计的原因有很多,包括如先有鸡还是先有蛋的问题,但主要原因还是速度和内核大小,不要说完整的C库,就是它的一个子集也够大,内核太大只会导致效率低下。

不要担心,许多常用的libc函数都在内核中实现了,例如,常见的字符串操作函数就位于lib/string.c中,只需要包括它的头文件<linux/string.h >就可以了。

这里的头文件指的是内核源代码树中的头文件,内核也只能使用树内的头文件,基础文件位于源代码根目录的include/目录下,例如,<linux/inotify.h>头文件就位于include/linux/inotify.h。

与架构相关的头文件则位于arch/<architecture>/include/asm,例如,如果在x86架构下编译,与你架构相关的文件就是arch/x86/include/asm,只需要在引用这些头的地方加上asm/前缀即可,如<asm/ioctl.h>。

漏掉的大部分都是类似printf()这样的函数,内核不会使用printf(),但它提供了printk()函数,其表现绝不比printf()差,printk()会拷贝格式化的字符串到内核日志缓冲区,syslog程序就是从这里读取信息的,其用法也和printf()类似:

printk(“Hello world! A string ’%s’ and an integer ’%d’\n”, str, i);

printf()和printk()之间最大的不同是,printk()允许你指定一个优先级标记,syslogd使用这个标记确定在哪里显示内核消息,下面是一个使用优先级标记的示例:

printk(KERN_ERR ”this is an error!\n”);

注意在KERN_ERR和打印的消息之间没有逗号,这是故意这么设计的,优先级使用一个预定义的字符定义,在编译期间它与打印的信息是串联的。

GNU C

和许多Unix内核类似,Linux内核也是用C编写的,但也许会让人很意外,内核不是用严谨的ANSI C编写的,内核开发人员用的却是gcc(GNU编译器集,包含了编译内核和Linux C程序的C编译器)中的各种语言扩展。

内核开发人员同时使用了C语言的ISO C99和GNU C扩展,这些变化让Linux内核与gcc结合得更紧密,但最近又出现了一个编译器 – 英特尔的C编译器 – 也对gcc的功能支持得相当好,因此也可以用它来编译Linux内核。最低支持的gcc版本是3.2,建议采用gcc 4.4或更高的版本编译。使用ISO C99扩展也是可以的,因为C99是C语言的官方版本。

函数

C99和GNU C都支持内联函数,内联函数是直接插入到每个函数调用的位置的,消除了函数调用和返回的开销,允许进一步优化,因为编译器可以同时优化调用者和被调用函数,但它也有缺点,代码大小会增加,因为函数的内容被直接复制到所调用者内部了,因此也会增加内存消耗和指令缓存空间。内核开发人员一般在小型时间很关键的函数中才会使用内联函数。

定义函数时,使用static和inline关键字声明内联函数,例如:

static inline void wolf(unsigned long tail_size)

函数必须先声明后使用,否则编译器就不能使函数内联,一般做法是将内联函数放在头文件中,因为它们被标记为static,不会创建输出函数,如果内联函数仅在一个文件中使用,可以放在该文件的顶部。

在内核中,与复杂的宏相比,出于安全和可读性方面考虑,内联函数是首选。

联汇编

Gcc C编译器允许在C函数中嵌入汇编指令,asm()编译器指令用于内联汇编代码,例如,这个内联汇编指令执行x86处理器的rdtsc指令,返回时间戳寄存器(tsc)的值:

unsigned int low, high;
asm volatile(“rdtsc” : ”=a” (low), ”=d” (high));
/* low and high now contain the lower and upper 32-bits of the 64-bit tsc */

Linux内核是用C和汇编语言混合编写的,与底层硬件相关的代码很多都是用汇编语言写的,剩下的大部分内核代码都是直接用C编写的。

分支注解

Gcc C编译器内置了一个指令优化条件分支,内核将这个打包成易于使用的宏 -likely()和unlikely()。

先看下面这样的if语句:

if (error) { /* … */ }

将这个分支标记为非常不可能采用

/* we predict ‘error’ is nearly always zero … */ if (unlikely(error)) { /* … */ }

相反,将这个分支标记为非常可能采用

/* we predict ’success’ is nearly always nonzero … */ if (likely(success)) { /* … */ }

当分支指令已经知道一个优先级,或你想在一种情况下优化另一种情况时应该使用上述指令,最重要的是,当分支正确标记时,这些指令会提升性能,但如果分支标记错误则会降低性能,在内核代码中,unlikely()要使用得更多,因为if语句倾向于表示一种特殊情况。

无内存保

当用户空间的应用程序尝试一个非法的内存访问时,内核可以捕捉到错误,发送SIGSEGV信号,杀掉进程,如果内核尝试一个非法的内存访问时,结果就不受控制了,因为谁也无法去控制内核,这也是内核最主要的失误。

此外,内核内存也是不可分页的,因此你消耗的每个内存字节都比物理内存的一个字节要少。

不能(容易)使用浮点数

当用户空间进程使用浮点指令时,内核要负责处理从整型到浮点模式的转换。

与用户空间不一样,内核不能无缝支持浮点数,因为它自己不能轻易地捕捉到自己,在内核中使用浮点数需要手动保存和恢复浮点数寄存器,因此除非却有必要,否则尽量不要在内核中做浮点运算。

小型,固定大小的堆

用户空间可以静态分配许多不同的堆栈,包括巨型结构和千元数组,这个行为是合法的,因为用户空间有很大的堆栈,并可以动态增长。

内核堆栈不大也不是动态的,相反,它很小且是固定的,内核堆栈的精确大小根据架构有所不同,在x86上,堆栈大小是在编译时确定的,一般是4KB或8KB,历史上,内核堆栈有2页,通常表示它处于32位架构上,大小是8KB,如果是16KB就表示是64位架构,总之大小是固定的,每个进程接收它自己的堆栈。

和并

内核最容易受竞争条件影响,和一个单线程的用户空间应用程序不一样,有许多内核特性允许同时访问共享资源,因此需要同步以防止竞争,特别是:

◆Linux是一种抢占式多任务操作系统,进程是由内核的进程调度器随意调度和再次调度的,内核必须在这些任务之间同步;

◆Linux支持对称多处理(SMP),因此,如果没有适当的保护,在两个或多个处理器上同时执行的内核代码可能会同时访问相同的资源;

◆中断是异步发生的,因此,如果没有适当的保护,在访问资源期间也可能发生中断,中断处理程序可能就会访问到相同的资源;

◆Linux是有优先权的,因此,如果没有适当的保护,内核代码可能会优先执行,访问其它代码正在使用的资源。

解决这些问题的一般方法是自旋锁和信号量。

可移植性的重要性

虽然用户空间应用程序一般不会太重视可移植性,但Linux的确是一个可移植性操作系统,应该保持一致,这意味着与架构无关的C代码必须在大量的系统上正确地编译和运行,与架构相关的代码必须在内核源代码树中使用特定的目录分隔开。

总结

可以肯定,内核有它独特的性质,它有它自己的一些原则,不过,内核的复杂性和障碍与其它大型软件项目相比,并没有什么大的不同,Linux开发道路上最重要的一步是认识到内核并不可怕,不熟悉?当然!不可逾越?当然不是!

admin Linux

Fedora13启用root账户

2010年7月24日

vim /etc/pam.d/gdm

找到如下行,注释掉:

#auth       required    pam_succeed_if.so user != root quiet

vim /etc/pam.d/gdm-password

找到如下行,注释掉:

#auth        required      pam_succeed_if.so user != root quiet

admin Linux

fedora 13关闭tty3,tty4,tty5

2010年7月24日

#vim /etc/sysconfig/init

找到该行:ACTIVE_CONSOLES=/dev/tty[1-6]

修改为:ACTIVE_CONSOLES=/dev/tty[1-2]

如果根本不用命令行的可以只保留tty1

修改为:ACTIVE_CONSOLES=/dev/tty[1]

admin RedHat系列教程

不常见却很有用的linux命令

2010年7月23日
  1. chvt [1-7]     #切换tty[1-7]控制台相当于ctrl+alt+F[1-7]
  2. setterm -blank 0     #禁用显示器休眠
  3. stty -echo     #屏幕上不显示任何输入
  4. setterm -dump [1-7] 或cat /dev/vcs[1-7]     #拍照
  5. watch -n1 “cat /dev/vcs1″     #监控tty1的用户的行为(每秒显示)
  6. cat /dev/zero >/tmp/zero     #生成0字节文件,在短时间内让硬盘空间爆满
  7. skill -STOP tty1     #停止 /强迫关闭 tty1
  8. skill -CONT tty1     #重新启动 /如果在停止状态则重新启动,否则忽略
  9. pgrep -t tty1     #显示控制台id的PID
  10. netstat -Cr   #动态显示路由的去向

admin Linux