免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
楼主: compare2000
打印 上一主题 下一主题

linux git常见命令整理 [复制链接]

论坛徽章:
3
天秤座
日期:2013-12-27 13:44:58射手座
日期:2014-05-22 16:52:43天蝎座
日期:2014-08-13 16:03:21
31 [报告]
发表于 2014-05-22 18:02 |只看该作者
自定导入脚本
如果先前的系统不是 Subversion 或 Perforce 之一,先上网找一下有没有与之对应的导入脚本——导入 CVS,Clear Case,Visual Source Safe,甚至存档目录的导入脚本已经存在。假如这些工具都不适用,或者使用的工具很少见,抑或你需要导入过程具有更多可制定性,则应该使用git fast-import。该命令从标准输入读取简单的指令来写入具体的 Git 数据。这样创建 Git 对象比运行纯 Git 命令或者手动写对象要简单的多(更多相关内容见第九章)。通过它,你可以编写一个导入脚本来从导入源读取必要的信息,同时在标准输出直接输出相关指示。你可以运行该脚本并把它的输出管道连接到git fast-import。

下面演示一下如何编写一个简单的导入脚本。假设你在进行一项工作,并且按时通过把工作目录复制为以时间戳 back_YY_MM_DD 命名的目录来进行备份,现在你需要把它们导入 Git 。目录结构如下:

$ ls /opt/import_fromback_2009_01_02back_2009_01_04back_2009_01_14back_2009_02_03current为了导入到一个 Git 目录,我们首先回顾一下 Git 储存数据的方式。你可能还记得,Git 本质上是一个 commit 对象的链表,每一个对象指向一个内容的快照。而这里需要做的工作就是告诉fast-import 内容快照的位置,什么样的 commit 数据指向它们,以及它们的顺序。我们采取一次处理一个快照的策略,为每一个内容目录建立对应的 commit ,每一个 commit 与之前的建立链接。

正如在第七章 “Git 执行策略一例” 一节中一样,我们将使用 Ruby 来编写这个脚本,因为它是我日常使用的语言而且阅读起来简单一些。你可以用任何其他熟悉的语言来重写这个例子——它仅需要把必要的信息打印到标准输出而已。同时,如果你在使用 Windows,这意味着你要特别留意不要在换行的时候引入回车符(译注:carriage returns,Windows 换行时加入的符号,通常说的\r )—— Git 的 fast-import 对仅使用换行符(LF)而非 Windows 的回车符(CRLF)要求非常严格。

首先,进入目标目录并且找到所有子目录,每一个子目录将作为一个快照被导入为一个 commit。我们将依次进入每一个子目录并打印所需的命令来导出它们。脚本的主循环大致是这样:

last_mark = nil# 循环遍历所有目录Dir.chdir(ARGV[0]) do  Dir.glob("*").each do |dir|    next if File.file?(dir)    # 进入目标目录    Dir.chdir(dir) do       last_mark = print_export(dir, last_mark)    end  endend我们在每一个目录里运行 print_export ,它会取出上一个快照的索引和标记并返回本次快照的索引和标记;由此我们就可以正确的把二者连接起来。”标记(mark)” 是fast-import 中对 commit 标识符的叫法;在创建 commit 的同时,我们逐一赋予一个标记以便以后在把它连接到其他 commit 时使用。因此,在print_export 方法中要做的第一件事就是根据目录名生成一个标记:

mark = convert_dir_to_mark(dir)实现该函数的方法是建立一个目录的数组序列并使用数组的索引值作为标记,因为标记必须是一个整数。这个方法大致是这样的:

$marks = []def convert_dir_to_mark(dir)  if !$marks.include?(dir)    $marks << dir  end  ($marks.index(dir) + 1).to_send有了整数来代表每个 commit,我们现在需要提交附加信息中的日期。由于日期是用目录名表示的,我们就从中解析出来。print_export 文件的下一行将是:

date = convert_dir_to_date(dir)而 convert_dir_to_date 则定义为

def convert_dir_to_date(dir)  if dir == 'current'    return Time.now().to_i  else    dir = dir.gsub('back_', '')    (year, month, day) = dir.split('_')    return Time.local(year, month, day).to_i  endend它为每个目录返回一个整型值。提交附加信息里最后一项所需的是提交者数据,我们在一个全局变量中直接定义之:

$author = 'Scott Chacon <schacon@example.com>'我们差不多可以开始为导入脚本输出提交数据了。第一项信息指明我们定义的是一个 commit 对象以及它所在的分支,随后是我们生成的标记,提交者信息以及提交备注,然后是前一个 commit 的索引,如果有的话。代码大致这样:

# 打印导入所需的信息puts 'commit refs/heads/master'puts 'mark :' + markputs "committer #{$author} #{date} -0700"export_data('imported from ' + dir)puts 'from :' + last_mark if last_mark时区(-0700)处于简化目的使用硬编码。如果是从其他版本控制系统导入,则必须以变量的形式指明时区。 提交备注必须以特定格式给出:

data (size)\n(contents)该格式包含了单词 data,所读取数据的大小,一个换行符,最后是数据本身。由于随后指明文件内容的时候要用到相同的格式,我们写一个辅助方法,export_data:

def export_data(string)  print "data #{string.size}\n#{string}"end唯一剩下的就是每一个快照的内容了。这简单的很,因为它们分别处于一个目录——你可以输出 deleeall 命令,随后是目录中每个文件的内容。Git 会正确的记录每一个快照:

puts 'deleteall'Dir.glob("**/*").each do |file| next if !File.file?(file)  inline_data(file)end注意:由于很多系统把每次修订看作一个 commit 到另一个 commit 的变化量,fast-import 也可以依据每次提交获取一个命令来指出哪些文件被添加,删除或者修改过,以及修改的内容。我们将需要计算快照之间的差别并且仅仅给出这项数据,不过该做法要复杂很多——还如不直接把所有数据丢给 Git 然它自己搞清楚。假如前面这个方法更适用于你的数据,参考fast-import 的 man 帮助页面来了解如何以这种方式提供数据。

列举新文件内容或者指明带有新内容的已修改文件的格式如下:

M 644 inline path/to/filedata (size)(file contents)这里,644 是权限模式(加入有可执行文件,则需要探测之并设定为 755),而 inline 说明我们在本行结束之后立即列出文件的内容。我们的 inline_data 方法大致是:

def inline_data(file, code = 'M', mode = '644')  content = File.read(file)  puts "#{code} #{mode} inline #{file}"  export_data(content)end我们重用了前面定义过的 export_data,因为这里和指明提交注释的格式如出一辙。

最后一项工作是返回当前的标记以便下次循环的使用。

return mark注意:如果你在用 Windows,一定记得添加一项额外的步骤。前面提过,Windows 使用 CRLF 作为换行字符而 Git fast-import 只接受 LF。为了绕开这个问题来满足 git fast-import,你需要让 ruby 用 LF 取代 CRLF:

$stdout.binmode搞定了。现在运行该脚本,你将得到如下内容:

$ ruby import.rb /opt/import_from commit refs/heads/mastermark :1committer Scott Chacon <schacon@geemail.com> 1230883200 -0700data 29imported from back_2009_01_02deleteallM 644 inline file.rbdata 12version twocommit refs/heads/mastermark :2committer Scott Chacon <schacon@geemail.com> 1231056000 -0700data 29imported from back_2009_01_04from :1deleteallM 644 inline file.rbdata 14version threeM 644 inline new.rbdata 16new version one(...)要运行导入脚本,在需要导入的目录把该内容用管道定向到 git fast-import。你可以建立一个空目录然后运行 git init 作为开头,然后运行该脚本:

$ git initInitialized empty Git repository in /opt/import_to/.git/$ ruby import.rb /opt/import_from | git fast-importgit-fast-import statistics:---------------------------------------------------------------------Alloc'd objects:       5000Total objects:           18 (         1 duplicates                  )      blobs  :            7 (         1 duplicates          0 deltas)      trees  :            6 (         0 duplicates          1 deltas)      commits:            5 (         0 duplicates          0 deltas)      tags   :            0 (         0 duplicates          0 deltas)Total branches:           1 (         1 loads     )      marks:           1024 (         5 unique    )      atoms:              3Memory total:          2255 KiB       pools:          2098 KiB     objects:           156 KiB---------------------------------------------------------------------pack_report: getpagesize()            =       4096pack_report: core.packedGitWindowSize =   33554432pack_report: core.packedGitLimit      =  268435456pack_report: pack_used_ctr            =          9pack_report: pack_mmap_calls          =          5pack_report: pack_open_windows        =          1 /          1pack_report: pack_mapped              =       1356 /       1356---------------------------------------------------------------------你会发现,在它成功执行完毕以后,会给出一堆有关已完成工作的数据。上例在一个分支导入了5次提交数据,包含了18个对象。现在可以运行 git log 来检视新的历史:

$ git log -2commit 10bfe7d22ce15ee25b60a824c8982157ca593d41Author: Scott Chacon <schacon@example.com>Date:   Sun May 3 12:57:39 2009 -0700    imported from currentcommit 7e519590de754d079dd73b44d695a42c9d2df452Author: Scott Chacon <schacon@example.com>Date:   Tue Feb 3 01:00:00 2009 -0700    imported from back_2009_02_03就它了——一个干净整洁的 Git 仓库。需要注意的是此时没有任何内容被检出——刚开始当前目录里没有任何文件。要获取它们,你得转到 master 分支的所在:

$ ls$ git reset --hard masterHEAD is now at 10bfe7d imported from current$ lsfile.rb  libfast-import 还可以做更多——处理不同的文件模式,二进制文件,多重分支与合并,标签,进展标识等等。一些更加复杂的实例可以在 Git 源码的contib/fast-import 目录里找到;其中较为出众的是前面提过的 git-p4 脚本。

8.3  总结
现在的你应该掌握了在 Subversion 上使用 Git 以及把几乎任何先存仓库无损失的导入为 Git 仓库。下一章将介绍 Git 内部的原始数据格式,从而是使你能亲手锻造其中的每一个字节,如果必要的话。

论坛徽章:
3
天秤座
日期:2013-12-27 13:44:58射手座
日期:2014-05-22 16:52:43天蝎座
日期:2014-08-13 16:03:21
32 [报告]
发表于 2014-05-22 18:03 |只看该作者
Git详解九:Git内部原理  
Git 内部原理
不管你是从前面的章节直接跳到了本章,还是读完了其余各章一直到这,你都将在本章见识 Git 的内部工作原理和实现方式。我个人发现学习这些内容对于理解 Git 的用处和强大是非常重要的,不过也有人认为这些内容对于初学者来说可能难以理解且过于复杂。正因如此我把这部分内容放在最后一章,你在学习过程中可以先阅 读这部分,也可以晚点阅读这部分,这完全取决于你自己。

既然已经读到这了,就让我们开始吧。首先要弄明白一点,从根本上来讲 Git 是一套内容寻址 (content-addressable) 文件系统,在此之上提供了一个 VCS 用户界面。马上你就会学到这意味着什么。

早期的 Git (主要是 1.5 之前版本) 的用户界面要比现在复杂得多,这是因为它更侧重于成为文件系统而不是一套更精致的 VCS 。最近几年改进了 UI 从而使它跟其他任何系统一样清晰易用。即便如此,还是经常会有一些陈腔滥调提到早期 Git 的 UI 复杂又难学。

内容寻址文件系统这一层相当酷,在本章中我会先讲解这部分。随后你会学到传输机制和最终要使用的各种库管理任务。



9.1  底层命令 (Plumbing) 和高层命令 (Porcelain)
本书讲解了使用 checkout, branch, remote 等共约 30 个 Git 命令。然而由于 Git 一开始被设计成供 VCS 使用的工具集而不是一整套用户友好的 VCS,它还包含了许多底层命令,这些命令用于以 UNIX 风格使用或由脚本调用。这些命令一般被称为 “plumbing” 命令(底层命令),其他的更友好的命令则被称为 “porcelain” 命令(高层命令)。

本书前八章主要专门讨论高层命令。本章将主要讨论底层命令以理解 Git 的内部工作机制、演示 Git 如何及为何要以这种方式工作。这些命令主要不是用来从命令行手工使用的,更多的是用来为其他工具和自定义脚本服务的。

当你在一个新目录或已有目录内执行 git init 时,Git 会创建一个 .git 目录,几乎所有 Git 存储和操作的内容都位于该目录下。如果你要备份或复制一个库,基本上将这一目录拷贝至其他地方就可以了。本章基本上都讨论该目录下的内容。该目录结构如下:

$ lsHEADbranches/configdescriptionhooks/indexinfo/objects/refs/该目录下有可能还有其他文件,但这是一个全新的 git init 生成的库,所以默认情况下这些就是你能看到的结构。新版本的 Git 不再使用branches 目录,description 文件仅供 GitWeb 程序使用,所以不用关心这些内容。config 文件包含了项目特有的配置选项,info 目录保存了一份不希望在 .gitignore 文件中管理的忽略模式 (ignored patterns) 的全局可执行文件。hooks 目录包住了第六章详细介绍了的客户端或服务端钩子脚本。

另外还有四个重要的文件或目录:HEAD 及 index 文件,objects 及refs 目录。这些是 Git 的核心部分。objects 目录存储所有数据内容,refs 目录存储指向数据 (分支) 的提交对象的指针,HEAD 文件指向当前分支,index 文件保存了暂存区域信息。马上你将详细了解 Git 是如何操纵这些内容的。



9.2  Git 对象
Git 是一套内容寻址文件系统。很不错。不过这是什么意思呢?这种说法的意思是,从内部来看,Git 是简单的 key-value 数据存储。它允许插入任意类型的内容,并会返回一个键值,通过该键值可以在任何时候再取出该内容。可以通过底层命令hash-object 来示范这点,传一些数据给该命令,它会将数据保存在 .git 目录并返回表示这些数据的键值。首先初使化一个 Git 仓库并确认objects 目录是空的:

$ mkdir test$ cd test$ git initInitialized empty Git repository in /tmp/test/.git/$ find .git/objects.git/objects.git/objects/info.git/objects/pack$ find .git/objects -type f$Git 初始化了 objects 目录,同时在该目录下创建了 pack 和 info 子目录,但是该目录下没有其他常规文件。我们往这个 Git 数据库里存储一些文本:

$ echo 'test content' | git hash-object -w --stdind670460b4b4aece5915caf5c68d12f560a9fe3e4参数 -w 指示 hash-object 命令存储 (数据) 对象,若不指定这个参数该命令仅仅返回键值。--stdin 指定从标准输入设备 (stdin) 来读取内容,若不指定这个参数则需指定一个要存储的文件的路径。该命令输出长度为 40 个字符的校验和。这是个 SHA-1 哈希值──其值为要存储的数据加上你马上会了解到的一种头信息的校验和。现在可以查看到 Git 已经存储了数据:

$ find .git/objects -type f.git/objects/d6/70460b4b4aece5915caf5c68d12f560a9fe3e4可以在 objects 目录下看到一个文件。这便是 Git 存储数据内容的方式──为每份内容生成一个文件,取得该内容与头信息的 SHA-1 校验和,创建以该校验和前两个字符为名称的子目录,并以 (校验和) 剩下 38 个字符为文件命名 (保存至子目录下)。

通过 cat-file 命令可以将数据内容取回。该命令是查看 Git 对象的瑞士军刀。传入 -p 参数可以让该命令输出数据内容的类型:

$ git cat-file -p d670460b4b4aece5915caf5c68d12f560a9fe3e4test content可以往 Git 中添加更多内容并取回了。也可以直接添加文件。比方说可以对一个文件进行简单的版本控制。首先,创建一个新文件,并把文件内容存储到数据库中:

$ echo 'version 1' > test.txt$ git hash-object -w test.txt83baae61804e65cc73a7201a7252750c76066a30接着往该文件中写入一些新内容并再次保存:

$ echo 'version 2' > test.txt$ git hash-object -w test.txt1f7a7a472abf3dd9643fd615f6da379c4acb3e3a数据库中已经将文件的两个新版本连同一开始的内容保存下来了:

$ find .git/objects -type f.git/objects/1f/7a7a472abf3dd9643fd615f6da379c4acb3e3a.git/objects/83/baae61804e65cc73a7201a7252750c76066a30.git/objects/d6/70460b4b4aece5915caf5c68d12f560a9fe3e4再将文件恢复到第一个版本:

$ git cat-file -p 83baae61804e65cc73a7201a7252750c76066a30 > test.txt$ cat test.txtversion 1或恢复到第二个版本:

$ git cat-file -p 1f7a7a472abf3dd9643fd615f6da379c4acb3e3a > test.txt$ cat test.txtversion 2需要记住的是几个版本的文件 SHA-1 值可能与实际的值不同,其次,存储的并不是文件名而仅仅是文件内容。这种对象类型称为 blob 。通过传递 SHA-1 值给cat-file -t 命令可以让 Git 返回任何对象的类型:

$ git cat-file -t 1f7a7a472abf3dd9643fd615f6da379c4acb3e3ablobtree (树) 对象
接下去来看 tree 对象,tree 对象可以存储文件名,同时也允许存储一组文件。Git 以一种类似 UNIX 文件系统但更简单的方式来存储内容。所有内容以 tree 或 blob 对象存储,其中 tree 对象对应于 UNIX 中的目录,blob 对象则大致对应于 inodes 或文件内容。一个单独的 tree 对象包含一条或多条 tree 记录,每一条记录含有一个指向 blob 或子 tree 对象的 SHA-1 指针,并附有该对象的权限模式 (mode)、类型和文件名信息。以 simplegit 项目为例,最新的 tree 可能是这个样子:

$ git cat-file -p master^{tree}100644 blob a906cb2a4a904a152e80877d4088654daad0c859      README100644 blob 8f94139338f9404f26296befa88755fc2598c289      Rakefile040000 tree 99f1a6d12cb4b6f19c8655fca46c3ecf317074e0      libmaster^{tree} 表示 branch 分支上最新提交指向的 tree 对象。请注意 lib 子目录并非一个 blob 对象,而是一个指向别一个 tree 对象的指针:

$ git cat-file -p 99f1a6d12cb4b6f19c8655fca46c3ecf317074e0100644 blob 47c6340d6459e05787f644c2447d2595f5d3a54b      simplegit.rb从概念上来讲,Git 保存的数据如图 9-1 所示。



图 9-1. Git 对象模型的简化版
你可以自己创建 tree 。通常 Git 根据你的暂存区域或 index 来创建并写入一个 tree 。因此要创建一个 tree 对象的话首先要通过将一些文件暂存从而创建一个 index 。可以使用 plumbing 命令update-index 为一个单独文件 ── test.txt 文件的第一个版本 ──    创建一个 index    。通过该命令人为的将 test.txt 文件的首个版本加入到了一个新的暂存区域中。由于该文件原先并不在暂存区域中 (甚至就连暂存区域也还没被创建出来呢) ,必须传入--add 参数;由于要添加的文件并不在当前目录下而是在数据库中,必须传入 --cacheinfo 参数。同时指定了文件模式,SHA-1 值和文件名:

$ git update-index --add --cacheinfo 100644 \  83baae61804e65cc73a7201a7252750c76066a30 test.txt在本例中,指定了文件模式为 100644,表明这是一个普通文件。其他可用的模式有:100755 表示可执行文件,120000 表示符号链接。文件模式是从常规的 UNIX 文件模式中参考来的,但是没有那么灵活 ── 上述三种模式仅对 Git 中的文件 (blobs) 有效 (虽然也有其他模式用于目录和子模块)。

现在可以用 write-tree 命令将暂存区域的内容写到一个 tree 对象了。无需 -w 参数 ── 如果目标 tree 不存在,调用write-tree 会自动根据 index 状态创建一个 tree 对象。

$ git write-treed8329fc1cc938780ffdd9f94e0d364e0ea74f579$ git cat-file -p d8329fc1cc938780ffdd9f94e0d364e0ea74f579100644 blob 83baae61804e65cc73a7201a7252750c76066a30      test.txt可以这样验证这确实是一个 tree 对象:

$ git cat-file -t d8329fc1cc938780ffdd9f94e0d364e0ea74f579tree再根据 test.txt 的第二个版本以及一个新文件创建一个新 tree 对象:

$ echo 'new file' > new.txt$ git update-index test.txt$ git update-index --add new.txt这时暂存区域中包含了 test.txt 的新版本及一个新文件 new.txt 。创建 (写) 该 tree 对象 (将暂存区域或 index 状态写入到一个 tree 对象),然后瞧瞧它的样子:

$ git write-tree0155eb4229851634a0f03eb265b69f5a2d56f341$ git cat-file -p 0155eb4229851634a0f03eb265b69f5a2d56f341100644 blob fa49b077972391ad58037050f2a75f74e3671e92      new.txt100644 blob 1f7a7a472abf3dd9643fd615f6da379c4acb3e3a      test.txt请注意该 tree 对象包含了两个文件记录,且 test.txt 的 SHA 值是早先值的 “第二版” (1f7a7a)。来点更有趣的,你将把第一个 tree 对象作为一个子目录加进该 tree 中。可以用read-tree 命令将 tree 对象读到暂存区域中去。在这时,通过传一个 --prefix 参数给 read-tree,将一个已有的 tree 对象作为一个子 tree 读到暂存区域中:

$ git read-tree --prefix=bak d8329fc1cc938780ffdd9f94e0d364e0ea74f579$ git write-tree3c4e9cd789d88d8d89c1073707c3585e41b0e614$ git cat-file -p 3c4e9cd789d88d8d89c1073707c3585e41b0e614040000 tree d8329fc1cc938780ffdd9f94e0d364e0ea74f579      bak100644 blob fa49b077972391ad58037050f2a75f74e3671e92      new.txt100644 blob 1f7a7a472abf3dd9643fd615f6da379c4acb3e3a      test.txt如果从刚写入的新 tree 对象创建一个工作目录,将得到位于工作目录顶级的两个文件和一个名为 bak 的子目录,该子目录包含了 test.txt 文件的第一个版本。可以将 Git 用来包含这些内容的数据想象成如图 9-2 所示的样子。



图 9-2. 当前 Git 数据的内容结构
commit (提交) 对象
你现在有三个 tree 对象,它们指向了你要跟踪的项目的不同快照,可是先前的问题依然存在:必须记往三个 SHA-1 值以获得这些快照。你也没有关于谁、何时以及为何保存了这些快照的信息。commit 对象为你保存了这些基本信息。

要创建一个 commit 对象,使用 commit-tree 命令,指定一个 tree 的 SHA-1,如果有任何前继提交对象,也可以指定。从你写的第一个 tree 开始:

$ echo 'first commit' | git commit-tree d8329ffdf4fc3344e67ab068f836878b6c4951e3b15f3d通过 cat-file 查看这个新 commit 对象:

$ git cat-file -p fdf4fc3 tree d8329fc1cc938780ffdd9f94e0d364e0ea74f579 author Scott Chacon 1243040974 -0700 committer Scott Chacon 1243040974 -0700 first commit  commit 对象有格式很简单:指明了该时间点项目快照的顶层树对象、作者/提交者信息(从 Git 设理发店的 user.name 和user.email中获得)以及当前时间戳、一个空行,以及提交注释信息。

接着再写入另外两个 commit 对象,每一个都指定其之前的那个 commit 对象:

$ echo 'second commit' | git commit-tree 0155eb -p fdf4fc3cac0cab538b970a37ea1e769cbbde608743bc96d$ echo 'third commit'  | git commit-tree 3c4e9c -p cac0cab1a410efbd13591db07496601ebc7a059dd55cfe9每一个 commit 对象都指向了你创建的树对象快照。出乎意料的是,现在已经有了真实的 Git 历史了,所以如果运行 git log 命令并指定最后那个 commit 对象的 SHA-1 便可以查看历史:

$ git log --stat 1a410e commit 1a410efbd13591db07496601ebc7a059dd55cfe9 Author: Scott Chacon Date: Fri May 22 18:15:24 2009 -0700 third commit bak/test.txt | 1 + 1 files changed, 1 insertions(+), 0 deletions(-) commit cac0cab538b970a37ea1e769cbbde608743bc96d Author: Scott Chacon Date: Fri May 22 18:14:29 2009 -0700 second commit new.txt | 1 + test.txt | 2 +- 2 files changed, 2 insertions(+), 1 deletions(-) commit fdf4fc3344e67ab068f836878b6c4951e3b15f3d Author: Scott Chacon Date: Fri May 22 18:09:34 2009 -0700 first commit test.txt | 1 + 1 files changed, 1 insertions(+), 0 deletions(-)   真棒。你刚刚通过使用低级操作而不是那些普通命令创建了一个 Git 历史。这基本上就是运行    git add 和 git commit 命令时 Git 进行的工作    ──保存修改了的文件的 blob,更新索引,创建 tree 对象,最后创建 commit 对象,这些 commit 对象指向了顶层 tree 对象以及先前的 commit 对象。这三类 Git 对象 ── blob,tree 以及 tree ── 都各自以文件的方式保存在.git/objects 目录下。以下所列是目前为止样例中的所有对象,每个对象后面的注释里标明了它们保存的内容:

$ find .git/objects -type f.git/objects/01/55eb4229851634a0f03eb265b69f5a2d56f341 # tree 2.git/objects/1a/410efbd13591db07496601ebc7a059dd55cfe9 # commit 3.git/objects/1f/7a7a472abf3dd9643fd615f6da379c4acb3e3a # test.txt v2.git/objects/3c/4e9cd789d88d8d89c1073707c3585e41b0e614 # tree 3.git/objects/83/baae61804e65cc73a7201a7252750c76066a30 # test.txt v1.git/objects/ca/c0cab538b970a37ea1e769cbbde608743bc96d # commit 2.git/objects/d6/70460b4b4aece5915caf5c68d12f560a9fe3e4 # 'test content'.git/objects/d8/329fc1cc938780ffdd9f94e0d364e0ea74f579 # tree 1.git/objects/fa/49b077972391ad58037050f2a75f74e3671e92 # new.txt.git/objects/fd/f4fc3344e67ab068f836878b6c4951e3b15f3d # commit 1如果你按照以上描述进行了操作,可以得到如图 9-3 所示的对象图。



图 9-3. Git 目录下的所有对象
对象存储
之前我提到当存储数据内容时,同时会有一个文件头被存储起来。我们花些时间来看看 Git 是如何存储对象的。你将看来如何通过 Ruby 脚本语言存储一个 blob 对象 (这里以字符串 “what is up, doc?” 为例) 。使用irb 命令进入 Ruby 交互式模式:

$ irb>> content = "what is up, doc?"=> "what is up, doc?"Git 以对象类型为起始内容构造一个文件头,本例中是一个 blob。然后添加一个空格,接着是数据内容的长度,最后是一个空字节 (null byte):

>> header = "blob #{content.length}\0"=> "blob 16\000"Git 将文件头与原始数据内容拼接起来,并计算拼接后的新内容的 SHA-1 校验和。可以在 Ruby 中使用 require 语句导入 SHA1 digest 库,然后调用Digest::SHA1.hexdigest() 方法计算字符串的 SHA-1 值:

>> store = header + content=> "blob 16\000what is up, doc?">> require 'digest/sha1'=> true>> sha1 = Digest::SHA1.hexdigest(store)=> "bd9dbf5aae1a3862dd1526723246b20206e5fc37"Git 用 zlib 对数据内容进行压缩,在 Ruby 中可以用 zlib 库来实现。首先需要导入该库,然后用 Zlib:eflate.deflate() 对数据进行压缩:

>> require 'zlib'=> true>> zlib_content = Zlib:eflate.deflate(store)=> "x\234K\312\311OR04c(\317H,Q\310,V(-\320QH\311O\266\a\000_\034\a\235"最后将用 zlib 压缩后的内容写入磁盘。需要指定保存对象的路径 (SHA-1 值的头两个字符作为子目录名称,剩余 38 个字符作为文件名保存至该子目录中)。在 Ruby 中,如果子目录不存在可以用FileUtils.mkdir_p() 函数创建它。接着用 File.open 方法打开文件,并用 write() 方法将之前压缩的内容写入该文件:

>> path = '.git/objects/' + sha1[0,2] + '/' + sha1[2,38]=> ".git/objects/bd/9dbf5aae1a3862dd1526723246b20206e5fc37">> require 'fileutils'=> true>> FileUtils.mkdir_p(File.dirname(path))=> ".git/objects/bd">> File.open(path, 'w') { |f| f.write zlib_content }=> 32这就行了 ── 你已经创建了一个正确的 blob 对象。所有的 Git 对象都以这种方式存储,惟一的区别是类型不同 ── 除了字符串 blob,文件头起始内容还可以是 commit 或 tree 。不过虽然 blob 几乎可以是任意内容,commit 和 tree 的数据却是有固定格式的。



9.3  Git References
你可以执行像 git log 1a410e 这样的命令来查看完整的历史,但是这样你就要记得 1a410e 是你最后一次提交,这样才能在提交历史中找到这些对象。你需要一个文件来用一个简单的名字来记录这些 SHA-1 值,这样你就可以用这些指针而不是原来的 SHA-1 值去检索了。

在 Git 中,我们称之为“引用”(references 或者 refs,译者注)。你可以在 .git/refs 目录下面找到这些包含 SHA-1 值的文件。在这个项目里,这个目录还没不包含任何文件,但是包含这样一个简单的结构:

$ find .git/refs.git/refs.git/refs/heads.git/refs/tags$ find .git/refs -type f$如果想要创建一个新的引用帮助你记住最后一次提交,技术上你可以这样做:

$ echo "1a410efbd13591db07496601ebc7a059dd55cfe9" > .git/refs/heads/master现在,你就可以在 Git 命令中使用你刚才创建的引用而不是 SHA-1 值:

$ git log --pretty=oneline  master1a410efbd13591db07496601ebc7a059dd55cfe9 third commitcac0cab538b970a37ea1e769cbbde608743bc96d second commitfdf4fc3344e67ab068f836878b6c4951e3b15f3d first commit当然,我们并不鼓励你直接修改这些引用文件。如果你确实需要更新一个引用,Git 提供了一个安全的命令 update-ref:

$ git update-ref refs/heads/master 1a410efbd13591db07496601ebc7a059dd55cfe9基本上 Git 中的一个分支其实就是一个指向某个工作版本一条 HEAD 记录的指针或引用。你可以用这条命令创建一个指向第二次提交的分支:

$ git update-ref refs/heads/test cac0ca这样你的分支将会只包含那次提交以及之前的工作:

$ git log --pretty=oneline testcac0cab538b970a37ea1e769cbbde608743bc96d second commitfdf4fc3344e67ab068f836878b6c4951e3b15f3d first commit现在,你的 Git 数据库应该看起来像图 9-4 一样。



图 9-4. 包含分支引用的 Git 目录对象
每当你执行 git branch (分支名称) 这样的命令,Git 基本上就是执行 update-ref 命令,把你现在所在分支中最后一次提交的 SHA-1 值,添加到你要创建的分支的引用。

HEAD 标记
现在的问题是,当你执行 git branch (分支名称) 这条命令的时候,Git 怎么知道最后一次提交的 SHA-1 值呢?答案就是 HEAD 文件。HEAD 文件是一个指向你当前所在分支的引用标识符。这样的引用标识符——它看起来并不像一个普通的引用——其实并不包含 SHA-1 值,而是一个指向另外一个引用的指针。如果你看一下这个文件,通常你将会看到这样的内容:

$ cat .git/HEADref: refs/heads/master如果你执行 git checkout test,Git 就会更新这个文件,看起来像这样:

$ cat .git/HEADref: refs/heads/test当你再执行 git commit 命令,它就创建了一个 commit 对象,把这个 commit 对象的父级设置为 HEAD 指向的引用的 SHA-1 值。

你也可以手动编辑这个文件,但是同样有一个更安全的方法可以这样做:symbolic-ref。你可以用下面这条命令读取 HEAD 的值:

$ git symbolic-ref HEADrefs/heads/master你也可以设置 HEAD 的值:

$ git symbolic-ref HEAD refs/heads/test$ cat .git/HEADref: refs/heads/test但是你不能设置成 refs 以外的形式:

$ git symbolic-ref HEAD testfatal: Refusing to point HEAD outside of refs/Tags
你刚刚已经重温过了 Git 的三个主要对象类型,现在这是第四种。Tag 对象非常像一个 commit 对象——包含一个标签,一组数据,一个消息和一个指针。最主要的区别就是 Tag 对象指向一个 commit 而不是一个 tree。它就像是一个分支引用,但是不会变化——永远指向同一个 commit,仅仅是提供一个更加友好的名字。

正如我们在第二章所讨论的,Tag 有两种类型:annotated 和 lightweight 。你可以类似下面这样的命令建立一个 lightweight tag:

$ git update-ref refs/tags/v1.0 cac0cab538b970a37ea1e769cbbde608743bc96d这就是 lightweight tag 的全部 —— 一个永远不会发生变化的分支。 annotated tag 要更复杂一点。如果你创建一个 annotated tag,Git 会创建一个 tag 对象,然后写入一个指向指向它而不是直接指向 commit 的 reference。你可以这样创建一个 annotated tag(-a 参数表明这是一个 annotated tag):

$ git tag -a v1.1 1a410efbd13591db07496601ebc7a059dd55cfe9 -m 'test tag'这是所创建对象的 SHA-1 值:

$ cat .git/refs/tags/v1.19585191f37f7b0fb9444f35a9bf50de191beadc2现在你可以运行 cat-file 命令检查这个 SHA-1 值:

$ git cat-file -p 9585191f37f7b0fb9444f35a9bf50de191beadc2 object 1a410efbd13591db07496601ebc7a059dd55cfe9 type commit tag v1.1 tagger Scott Chacon Sat May 23 16:48:58 2009 -0700 test tag值得注意的是这个对象指向你所标记的 commit 对象的 SHA-1 值。同时需要注意的是它并不是必须要指向一个 commit 对象;你可以标记任何 Git 对象。例如,在 Git 的源代码里,管理者添加了一个 GPG 公钥(这是一个 blob 对象)对它做了一个标签。你就可以运行:

$ git cat-file blob junio-gpg-pub来查看 Git 源代码仓库中的公钥. Linux kernel 也有一个不是指向 commit 对象的 tag —— 第一个 tag 是在导入源代码的时候创建的,它指向初始 tree (initial tree,译者注)。

Remotes
你将会看到的第四种 reference 是 remote reference(远程引用,译者注)。如果你添加了一个 remote 然后推送代码过去,Git 会把你最后一次推送到这个 remote 的每个分支的值都记录在refs/remotes 目录下。例如,你可以添加一个叫做 origin 的 remote 然后把你的 master 分支推送上去:

$ git remote add origin git@github.com:schacon/simplegit-progit.git$ git push origin masterCounting objects: 11, done.Compressing objects: 100% (5/5), done.Writing objects: 100% (7/7), 716 bytes, done.Total 7 (delta 2), reused 4 (delta 1)To git@github.com:schacon/simplegit-progit.git   a11bef0..ca82a6d  master -> master然后查看 refs/remotes/origin/master 这个文件,你就会发现 origin remote 中的master 分支就是你最后一次和服务器的通信。

$ cat .git/refs/remotes/origin/masterca82a6dff817ec66f44342007202690a93763949Remote 应用和分支主要区别在于他们是不能被 check out 的。Git 把他们当作是标记这些了这些分支在服务器上最后状态的一种书签。



9.4  Packfiles
我们再来看一下 test Git 仓库。目前为止,有 11 个对象 ── 4 个 blob,3 个 tree,3 个 commit 以及一个 tag:

$ find .git/objects -type f.git/objects/01/55eb4229851634a0f03eb265b69f5a2d56f341 # tree 2.git/objects/1a/410efbd13591db07496601ebc7a059dd55cfe9 # commit 3.git/objects/1f/7a7a472abf3dd9643fd615f6da379c4acb3e3a # test.txt v2.git/objects/3c/4e9cd789d88d8d89c1073707c3585e41b0e614 # tree 3.git/objects/83/baae61804e65cc73a7201a7252750c76066a30 # test.txt v1.git/objects/95/85191f37f7b0fb9444f35a9bf50de191beadc2 # tag.git/objects/ca/c0cab538b970a37ea1e769cbbde608743bc96d # commit 2.git/objects/d6/70460b4b4aece5915caf5c68d12f560a9fe3e4 # 'test content'.git/objects/d8/329fc1cc938780ffdd9f94e0d364e0ea74f579 # tree 1.git/objects/fa/49b077972391ad58037050f2a75f74e3671e92 # new.txt.git/objects/fd/f4fc3344e67ab068f836878b6c4951e3b15f3d # commit 1Git 用 zlib 压缩文件内容,因此这些文件并没有占用太多空间,所有文件加起来总共仅用了 925 字节。接下去你会添加一些大文件以演示 Git 的一个很有意思的功能。将你之前用到过的 Grit 库中的 repo.rb 文件加进去 ── 这个源代码文件大小约为 12K:

$ curl http://github.com/mojombo/grit/raw/master/lib/grit/repo.rb > repo.rb$ git add repo.rb$ git commit -m 'added repo.rb'[master 484a592] added repo.rb 3 files changed, 459 insertions(+), 2 deletions(-) delete mode 100644 bak/test.txt create mode 100644 repo.rb rewrite test.txt (100%)如果查看一下生成的 tree,可以看到 repo.rb 文件的 blob 对象的 SHA-1 值:

$ git cat-file -p master^{tree}100644 blob fa49b077972391ad58037050f2a75f74e3671e92      new.txt100644 blob 9bc1dc421dcd51b4ac296e3e5b6e2a99cf44391e      repo.rb100644 blob e3f094f522629ae358806b17daf78246c27c007b      test.txt然后可以用 git cat-file 命令查看这个对象有多大:

$ git cat-file -s 9bc1dc421dcd51b4ac296e3e5b6e2a99cf44391e12898稍微修改一下些文件,看会发生些什么:

$ echo '# testing' >> repo.rb$ git commit -am 'modified repo a bit'[master ab1afef] modified repo a bit 1 files changed, 1 insertions(+), 0 deletions(-)查看这个 commit 生成的 tree,可以看到一些有趣的东西:

$ git cat-file -p master^{tree}100644 blob fa49b077972391ad58037050f2a75f74e3671e92      new.txt100644 blob 05408d195263d853f09dca71d55116663690c27c      repo.rb100644 blob e3f094f522629ae358806b17daf78246c27c007b      test.txtblob 对象与之前的已经不同了。这说明虽然只是往一个 400 行的文件最后加入了一行内容,Git 却用一个全新的对象来保存新的文件内容:

$ git cat-file -s 05408d195263d853f09dca71d55116663690c27c12908你的磁盘上有了两个几乎完全相同的 12K 的对象。如果 Git 只完整保存其中一个,并保存另一个对象的差异内容,岂不更好?

事实上 Git 可以那样做。Git 往磁盘保存对象时默认使用的格式叫松散对象 (loose object) 格式。Git 时不时地将这些对象打包至一个叫 packfile 的二进制文件以节省空间并提高效率。当仓库中有太多的松散对象,或是手工调用git gc 命令,或推送至远程服务器时,Git 都会这样做。手工调用 git gc 命令让 Git 将库中对象打包并看会发生些什么:

$ git gcCounting objects: 17, done.Delta compression using 2 threads.Compressing objects: 100% (13/13), done.Writing objects: 100% (17/17), done.Total 17 (delta 1), reused 10 (delta 0)查看一下 objects 目录,会发现大部分对象都不在了,与此同时出现了两个新文件:

$ find .git/objects -type f.git/objects/71/08f7ecb345ee9d0084193f147cdad4d2998293.git/objects/d6/70460b4b4aece5915caf5c68d12f560a9fe3e4.git/objects/info/packs.git/objects/pack/pack-7a16e4488ae40c7d2bc56ea2bd43e25212a66c45.idx.git/objects/pack/pack-7a16e4488ae40c7d2bc56ea2bd43e25212a66c45.pack仍保留着的几个对象是未被任何 commit 引用的 blob ── 在此例中是你之前创建的 “what is up, doc?” 和 “test content” 这两个示例 blob。你从没将他们添加至任何 commit,所以 Git 认为它们是 “悬空” 的,不会将它们打包进 packfile 。

剩下的文件是新创建的 packfile 以及一个索引。packfile 文件包含了刚才从文件系统中移除的所有对象。索引文件包含了 packfile 的偏移信息,这样就可以快速定位任意一个指定对象。有意思的是运行gc 命令前磁盘上的对象大小约为 12K ,而这个新生成的 packfile 仅为 6K 大小。通过打包对象减少了一半磁盘使用空间。

Git 是如何做到这点的?Git 打包对象时,会查找命名及尺寸相近的文件,并只保存文件不同版本之间的差异内容。可以查看一下 packfile ,观察它是如何节省空间的。git verify-pack 命令用于显示已打包的内容:

$ git verify-pack -v \  .git/objects/pack/pack-7a16e4488ae40c7d2bc56ea2bd43e25212a66c45.idx0155eb4229851634a0f03eb265b69f5a2d56f341 tree   71 76 540005408d195263d853f09dca71d55116663690c27c blob   12908 3478 87409f01cea547666f58d6a8d809583841a7c6f0130 tree   106 107 50861a410efbd13591db07496601ebc7a059dd55cfe9 commit 225 151 3221f7a7a472abf3dd9643fd615f6da379c4acb3e3a blob   10 19 53813c4e9cd789d88d8d89c1073707c3585e41b0e614 tree   101 105 5211484a59275031909e19aadb7c92262719cfcdf19a commit 226 153 16983baae61804e65cc73a7201a7252750c76066a30 blob   10 19 53629585191f37f7b0fb9444f35a9bf50de191beadc2 tag    136 127 54769bc1dc421dcd51b4ac296e3e5b6e2a99cf44391e blob   7 18 5193 105408d195263d853f09dca71d55116663690c27c \  ab1afef80fac8e34258ff41fc1b867c702daa24b commit 232 157 12cac0cab538b970a37ea1e769cbbde608743bc96d commit 226 154 473d8329fc1cc938780ffdd9f94e0d364e0ea74f579 tree   36 46 5316e3f094f522629ae358806b17daf78246c27c007b blob   1486 734 4352f8f51d7d8a1760462eca26eebafde32087499533 tree   106 107 749fa49b077972391ad58037050f2a75f74e3671e92 blob   9 18 856fdf4fc3344e67ab068f836878b6c4951e3b15f3d commit 177 122 627chain length = 1: 1 objectpack-7a16e4488ae40c7d2bc56ea2bd43e25212a66c45.pack: ok如果你还记得的话, 9bc1d 这个 blob 是 repo.rb 文件的第一个版本,这个 blob 引用了 05408 这个 blob,即该文件的第二个版本。命令输出内容的第三列显示的是对象大小,可以看到05408 占用了 12K 空间,而 9bc1d 仅为 7 字节。非常有趣的是第二个版本才是完整保存文件内容的对象,而第一个版本是以差异方式保存的 ── 这是因为大部分情况下需要快速访问文件的最新版本。

最妙的是可以随时进行重新打包。Git 自动定期对仓库进行重新打包以节省空间。当然也可以手工运行 git gc 命令来这么做。



9.5  The Refspec
这本书读到这里,你已经使用过一些简单的远程分支到本地引用的映射方式了,这种映射可以更为复杂。 假设你像这样添加了一项远程仓库:

$ git remote add origin git@github.com:schacon/simplegit-progit.git它在你的 .git/config 文件中添加了一节,指定了远程的名称 (origin), 远程仓库的URL地址,和用于获取操作的 Refspec:

[remote "origin"]       url = git@github.com:schacon/simplegit-progit.git       fetch = +refs/heads/*:refs/remotes/origin/*Refspec 的格式是一个可选的 + 号,接着是 : 的格式,这里 是远端上的引用格式, 是将要记录在本地的引用格式。可选的 + 号告诉 Git 在即使不能快速演进的情况下,也去强制更新它。

缺省情况下 refspec 会被 git remote add 命令所自动生成, Git 会获取远端上 refs/heads/ 下面的所有引用,并将它写入到本地的refs/remotes/origin/. 所以,如果远端上有一个 master 分支,你在本地可以通过下面这种方式来访问它的历史记录:

$ git log origin/master$ git log remotes/origin/master$ git log refs/remotes/origin/master它们全是等价的,因为 Git 把它们都扩展成 refs/remotes/origin/master.

如果你想让 Git 每次只拉取远程的 master 分支,而不是远程的所有分支,你可以把 fetch 这一行修改成这样:

fetch = +refs/heads/master:refs/remotes/origin/master这是 git fetch 操作对这个远端的缺省 refspec 值。而如果你只想做一次该操作,也可以在命令行上指定这个 refspec. 如可以这样拉取远程的master 分支到本地的 origin/mymaster 分支:

$ git fetch origin master:refs/remotes/origin/mymaster你也可以在命令行上指定多个 refspec. 像这样可以一次获取远程的多个分支:

$ git fetch origin master:refs/remotes/origin/mymaster \   topic:refs/remotes/origin/topicFrom git@github.com:schacon/simplegit ! [rejected]        master     -> origin/mymaster  (non fast forward) * [new branch]      topic      -> origin/topic在这个例子中, master 分支因为不是一个可以快速演进的引用而拉取操作被拒绝。你可以在 refspec 之前使用一个 + 号来重载这种行为。

你也可以在配置文件中指定多个 refspec. 如你想在每次获取时都获取 master 和 experiment 分支,就添加两行:

[remote "origin"]       url = git@github.com:schacon/simplegit-progit.git       fetch = +refs/heads/master:refs/remotes/origin/master       fetch = +refs/heads/experiment:refs/remotes/origin/experiment但是这里不能使用部分通配符,像这样就是不合法的:

fetch = +refs/heads/qa*:refs/remotes/origin/qa*但无论如何,你可以使用命名空间来达到这个目的。如你有一个QA组,他们推送一系列分支,你想每次获取 master 分支和QA组的所有分支,你可以使用这样的配置段落:

[remote "origin"]       url = git@github.com:schacon/simplegit-progit.git       fetch = +refs/heads/master:refs/remotes/origin/master       fetch = +refs/heads/qa/*:refs/remotes/origin/qa/*如果你的工作流很复杂,有QA组推送的分支、开发人员推送的分支、和集成人员推送的分支,并且他们在远程分支上协作,你可以采用这种方式为他们创建各自的命名空间。

推送 Refspec
采用命名空间的方式确实很棒,但QA组成员第1次是如何将他们的分支推送到 qa/ 空间里面的呢?答案是你可以使用 refspec 来推送。

如果QA组成员想把他们的 master 分支推送到远程的 qa/master 分支上,可以这样运行:

$ git push origin master:refs/heads/qa/master如果他们想让 Git 每次运行 git push origin 时都这样自动推送,他们可以在配置文件中添加 push 值:

[remote "origin"]       url = git@github.com:schacon/simplegit-progit.git       fetch = +refs/heads/*:refs/remotes/origin/*       push = refs/heads/master:refs/heads/qa/master这样,就会让 git push origin 缺省就把本地的 master 分支推送到远程的 qa/master 分支上。

删除引用
你也可以使用 refspec 来删除远程的引用,是通过运行这样的命令:

$ git push origin :topic因为 refspec 的格式是 : , 通过把 部分留空的方式,这个意思是是把远程的topic 分支变成空,也就是删除它。



9.6  传输协议
Git 可以以两种主要的方式跨越两个仓库传输数据:基于HTTP协议之上,和 file://, ssh://, 和git:// 等智能传输协议。这一节带你快速浏览这两种主要的协议操作过程。

哑协议
Git 基于HTTP之上传输通常被称为哑协议,这是因为它在服务端不需要有针对 Git 特有的代码。这个获取过程仅仅是一系列GET请求,客户端可以假定服务端的Git仓库中的布局。让我们以 simplegit 库来看看http-fetch 的过程:

$ git clone http://github.com/schacon/simplegit-progit.git它做的第1件事情就是获取 info/refs 文件。这个文件是在服务端运行了 update-server-info 所生成的,这也解释了为什么在服务端要想使用HTTP传输,必须要开启post-receive 钩子:

=> GET info/refsca82a6dff817ec66f44342007202690a93763949     refs/heads/master现在你有一个远端引用和SHA值的列表。下一步是寻找HEAD引用,这样你就知道了在完成后,什么应该被检出到工作目录:

=> GET HEADref: refs/heads/master这说明在完成获取后,需要检出 master 分支。 这时,已经可以开始漫游操作了。因为你的起点是在 info/refs 文件中所提到的ca82a6 commit 对象,你的开始操作就是获取它:

=> GET objects/ca/82a6dff817ec66f44342007202690a93763949(179 bytes of binary data)然后你取回了这个对象 - 这在服务端是一个松散格式的对象,你使用的是静态的 HTTP GET 请求获取的。可以使用 zlib 解压缩它,去除其头部,查看它的 commmit 内容:

$ git cat-file -p ca82a6dff817ec66f44342007202690a93763949 tree cfda3bf379e4f8dba8717dee55aab78aef7f4daf parent 085bb3bcb608e1e8451d4b2432f8ecbe6306e7e7 author Scott Chacon 1205815931 -0700 committer Scott Chacon 1240030591 -0700 changed the version number  这样,就得到了两个需要进一步获取的对象 - cfda3b 是这个 commit 对象所对应的 tree 对象,和 085bb3 是它的父对象;

=> GET objects/08/5bb3bcb608e1e8451d4b2432f8ecbe6306e7e7(179 bytes of data)这样就取得了这它的下一步 commit 对象,再抓取 tree 对象:

=> GET objects/cf/da3bf379e4f8dba8717dee55aab78aef7f4daf(404 - Not Found)Oops - 看起来这个 tree 对象在服务端并不以松散格式对象存在,所以得到了404响应,代表在HTTP服务端没有找到该对象。这有好几个原因 - 这个对象可能在替代仓库里面,或者在打包文件里面, Git 会首先检查任何列出的替代仓库:

=> GET objects/info/http-alternates(empty file)如果这返回了几个替代仓库列表,那么它会去那些地方检查松散格式对象和文件 - 这是一种在软件分叉之间共享对象以节省磁盘的好方法。然而,在这个例子中,没有替代仓库。所以你所需要的对象肯定在某个打包文件中。要检查服务端有哪些打包格式文件,你需要获取objects/info/packs 文件,这里面包含有打包文件列表(是的,它也是被 update-server-info 所生成的);

=> GET objects/info/packsP pack-816a9b2334da9953e530f27bcac22082a9f5b835.pack这里服务端只有一个打包文件,所以你要的对象显然就在里面。但是你可以先检查它的索引文件以确认。这在服务端有多个打包文件时也很有用,因为这样就可以先检查你所需要的对象空间是在哪一个打包文件里面了:

=> GET objects/pack/pack-816a9b2334da9953e530f27bcac22082a9f5b835.idx(4k of binary data)现在你有了这个打包文件的索引,你可以看看你要的对象是否在里面 - 因为索引文件列出了这个打包文件所包含的所有对象的SHA值,和该对象存在于打包文件中的偏移量,所以你只需要简单地获取整个打包文件:

=> GET objects/pack/pack-816a9b2334da9953e530f27bcac22082a9f5b835.pack(13k of binary data)现在你也有了这个 tree 对象,你可以继续在 commit 对象上漫游。它们全部都在这个你已经下载到的打包文件里面,所以你不用继续向服务端请求更多下载了。 在这完成之后,由于下载开始时已探明HEAD引用是指向master 分支, Git 会将它检出到工作目录。

整个过程看起来就像这样:

$ git clone http://github.com/schacon/simplegit-progit.gitInitialized empty Git repository in /private/tmp/simplegit-progit/.git/got ca82a6dff817ec66f44342007202690a93763949walk ca82a6dff817ec66f44342007202690a93763949got 085bb3bcb608e1e8451d4b2432f8ecbe6306e7e7Getting alternates list for http://github.com/schacon/simplegit-progit.gitGetting pack list for http://github.com/schacon/simplegit-progit.gitGetting index for pack 816a9b2334da9953e530f27bcac22082a9f5b835Getting pack 816a9b2334da9953e530f27bcac22082a9f5b835 which contains cfda3bf379e4f8dba8717dee55aab78aef7f4dafwalk 085bb3bcb608e1e8451d4b2432f8ecbe6306e7e7walk a11bef06a3f659402fe7563abf99ad00de2209e6智能协议
这个HTTP方法是很简单但效率不是很高。使用智能协议是传送数据的更常用的方法。这些协议在远端都有Git智能型进程在服务 - 它可以读出本地数据并计算出客户端所需要的,并生成合适的数据给它,这有两类传输数据的进程:一对用于上传数据和一对用于下载。

上传数据
为了上传数据至远端, Git 使用 send-pack 和 receive-pack 进程。这个 send-pack 进程运行在客户端上,它连接至远端运行的 receive-pack 进程。

举例来说,你在你的项目上运行了 git push origin master, 并且 origin 被定义为一个使用SSH协议的URL。 Git 会使用send-pack 进程,它会启动一个基于SSH的连接到服务器。它尝试像这样透过SSH在服务端运行命令:

$ ssh -x git@github.com "git-receive-pack 'schacon/simplegit-progit.git'"005bca82a6dff817ec66f4437202690a93763949 refs/heads/master report-status delete-refs003e085bb3bcb608e1e84b2432f8ecbe6306e7e7 refs/heads/topic0000这里的 git-receive-pack 命令会立即对它所拥有的每一个引用响应一行 - 在这个例子中,只有 master 分支和它的SHA值。这里第1行也包含了服务端的能力列表(这里是report-status 和 delete-refs)。

每一行以4字节的十六进制开始,用于指定整行的长度。你看到第1行以005b开始,这在十六进制中表示91,意味着第1行有91字节长。下一行以003e起始,表示有62字节长,所以需要读剩下的62字节。再下一行是0000开始,表示服务器已完成了引用列表过程。

现在它知道了服务端的状态,你的 send-pack 进程会判断哪些 commit 是它所拥有但服务端没有的。针对每个引用,这次推送都会告诉对端的receive-pack 这个信息。举例说,如果你在更新 master 分支,并且增加 experiment 分支,这个send-pack 将会是像这样:

0085ca82a6dff817ec66f44342007202690a93763949  15027957951b64cf874c3557a0f3547bd83b3ff6 refs/heads/master report-status00670000000000000000000000000000000000000000 cdfdb42577e2506715f8cfeacdbabc092bf63e8d refs/heads/experiment0000这里的全’0’的SHA-1值表示之前没有过这个对象 - 因为你是在添加新的 experiment 引用。如果你在删除一个引用,你会看到相反的: 就是右边是全’0’。

Git 针对每个引用发送这样一行信息,就是旧的SHA值,新的SHA值,和将要更新的引用的名称。第1行还会包含有客户端的能力。下一步,客户端会发送一个所有那些服务端所没有的对象的一个打包文件。最后,服务端以成功(或者失败)来响应:

000Aunpack ok下载数据
当你在下载数据时, fetch-pack 和 upload-pack 进程就起作用了。客户端启动 fetch-pack 进程,连接至远端的 upload-pack 进程,以协商后续数据传输过程。

在远端仓库有不同的方式启动 upload-pack 进程。你可以使用与 receive-pack 相同的透过SSH管道的方式,也可以通过 Git 后台来启动这个进程,它默认监听在9418号端口上。这里fetch-pack 进程在连接后像这样向后台发送数据:

003fgit-upload-pack schacon/simplegit-progit.git\0host=myserver.com\0它也是以4字节指定后续字节长度的方式开始,然后是要运行的命令,和一个空字节,然后是服务端的主机名,再跟随一个最后的空字节。 Git 后台进程会检查这个命令是否可以运行,以及那个仓库是否存在,以及是否具有公开权限。如果所有检查都通过了,它会启动这个upload-pack 进程并将客户端的请求移交给它。

如果你透过SSH使用获取功能, fetch-pack 会像这样运行:

$ ssh -x git@github.com "git-upload-pack 'schacon/simplegit-progit.git'"不管哪种方式,在 fetch-pack 连接之后, upload-pack 都会以这种形式返回:

0088ca82a6dff817ec66f44342007202690a93763949 HEAD\0multi_ack thin-pack \  side-band side-band-64k ofs-delta shallow no-progress include-tag003fca82a6dff817ec66f44342007202690a93763949 refs/heads/master003e085bb3bcb608e1e8451d4b2432f8ecbe6306e7e7 refs/heads/topic0000这与 receive-pack 响应很类似,但是这里指的能力是不同的。而且它还会指出HEAD引用,让客户端可以检查是否是一份克 隆。

在这里, fetch-pack 进程检查它自己所拥有的对象和所有它需要的对象,通过发送 “want” 和所需对象的SHA值,发送 “have” 和所有它已拥有的对象的SHA值。在列表完成时,再发送 “done” 通知upload-pack 进程开始发送所需对象的打包文件。这个过程看起来像这样:

0054want ca82a6dff817ec66f44342007202690a93763949 ofs-delta0032have 085bb3bcb608e1e8451d4b2432f8ecbe6306e7e700000009done这是传输协议的一个很基础的例子,在更复杂的例子中,客户端可能会支持 multi_ack 或者 side-band 能力;但是这个例子中展示了智能协议的基本交互过程。

论坛徽章:
3
天秤座
日期:2013-12-27 13:44:58射手座
日期:2014-05-22 16:52:43天蝎座
日期:2014-08-13 16:03:21
33 [报告]
发表于 2014-05-22 18:03 |只看该作者
9.7  维护及数据恢复
你时不时的需要进行一些清理工作 ── 如减小一个仓库的大小,清理导入的库,或是恢复丢失的数据。本节将描述这类使用场景。

维护
Git 会不定时地自动运行称为 “auto gc” 的命令。大部分情况下该命令什么都不处理。不过要是存在太多松散对象 (loose object, 不在 packfile 中的对象) 或 packfile,Git 会进行调用git gc 命令。 gc 指垃圾收集 (garbage collect),此命令会做很多工作:收集所有松散对象并将它们存入 packfile,合并这些 packfile 进一个大的 packfile,然后将不被任何 commit 引用并且已存在一段时间 (数月) 的对象删除。

可以手工运行 auto gc 命令:

$ git gc --auto再次强调,这个命令一般什么都不干。如果有 7,000 个左右的松散对象或是 50 个以上的 packfile,Git 才会真正调用 gc 命令。可能通过修改配置中的gc.auto 和 gc.autopacklimit 来调整这两个阈值。

gc 还会将所有引用 (references) 并入一个单独文件。假设仓库中包含以下分支和标签:

$ find .git/refs -type f.git/refs/heads/experiment.git/refs/heads/master.git/refs/tags/v1.0.git/refs/tags/v1.1这时如果运行 git gc, refs 下的所有文件都会消失。Git 会将这些文件挪到 .git/packed-refs 文件中去以提高效率,该文件是这个样子的:

$ cat .git/packed-refs# pack-refs with: peeledcac0cab538b970a37ea1e769cbbde608743bc96d refs/heads/experimentab1afef80fac8e34258ff41fc1b867c702daa24b refs/heads/mastercac0cab538b970a37ea1e769cbbde608743bc96d refs/tags/v1.09585191f37f7b0fb9444f35a9bf50de191beadc2 refs/tags/v1.1^1a410efbd13591db07496601ebc7a059dd55cfe9当更新一个引用时,Git 不会修改这个文件,而是在 refs/heads 下写入一个新文件。当查找一个引用的 SHA 时,Git 首先在refs 目录下查找,如果未找到则到 packed-refs 文件中去查找。因此如果在 refs 目录下找不到一个引用,该引用可能存到packed-refs 文件中去了。

请留意文件最后以 ^ 开头的那一行。这表示该行上一行的那个标签是一个 annotated 标签,而该行正是那个标签所指向的 commit 。

数据恢复
在使用 Git 的过程中,有时会不小心丢失 commit 信息。这一般出现在以下情况下:强制删除了一个分支而后又想重新使用这个分支,hard-reset 了一个分支从而丢弃了分支的部分 commit。如果这真的发生了,有什么办法把丢失的 commit 找回来呢?

下面的示例演示了对 test 仓库主分支进行 hard-reset 到一个老版本的 commit 的操作,然后恢复丢失的 commit 。首先查看一下当前的仓库状态:

$ git log --pretty=onelineab1afef80fac8e34258ff41fc1b867c702daa24b modified repo a bit484a59275031909e19aadb7c92262719cfcdf19a added repo.rb1a410efbd13591db07496601ebc7a059dd55cfe9 third commitcac0cab538b970a37ea1e769cbbde608743bc96d second commitfdf4fc3344e67ab068f836878b6c4951e3b15f3d first commit接着将 master 分支移回至中间的一个 commit:

$ git reset --hard 1a410efbd13591db07496601ebc7a059dd55cfe9HEAD is now at 1a410ef third commit$ git log --pretty=oneline1a410efbd13591db07496601ebc7a059dd55cfe9 third commitcac0cab538b970a37ea1e769cbbde608743bc96d second commitfdf4fc3344e67ab068f836878b6c4951e3b15f3d first commit这样就丢弃了最新的两个 commit ── 包含这两个 commit 的分支不存在了。现在要做的是找出最新的那个 commit 的 SHA,然后添加一个指它它的分支。关键在于找出最新的 commit 的 SHA ── 你不大可能记住了这个 SHA,是吧?

通常最快捷的办法是使用 git reflog 工具。当你 (在一个仓库下) 工作时,Git 会在你每次修改了 HEAD 时悄悄地将改动记录下来。当你提交或修改分支时,reflog 就会更新。git update-ref 命令也可以更新 reflog,这是在本章前面的 “Git References” 部分我们使用该命令而不是手工将 SHA 值写入 ref 文件的理由。任何时间运行git reflog 命令可以查看当前的状态:

$ git reflog1a410ef HEAD@{0}: 1a410efbd13591db07496601ebc7a059dd55cfe9: updating HEADab1afef HEAD@{1}: ab1afef80fac8e34258ff41fc1b867c702daa24b: updating HEAD可以看到我们签出的两个 commit ,但没有更多的相关信息。运行 git log -g 会输出 reflog 的正常日志,从而显示更多有用信息:

$ git log -g commit 1a410efbd13591db07496601ebc7a059dd55cfe9 Reflog: HEAD@{0} (Scott Chacon ) Reflog message: updating HEAD Author: Scott Chacon Date: Fri May 22 18:22:37 2009 -0700 third commit commit ab1afef80fac8e34258ff41fc1b867c702daa24b Reflog: HEAD@{1} (Scott Chacon ) Reflog message: updating HEAD Author: Scott Chacon Date: Fri May 22 18:15:24 2009 -0700 modified repo a bit    看起来弄丢了的 commit 是底下那个,这样在那个 commit 上创建一个新分支就能把它恢复过来。比方说,可以在那个 commit (ab1afef) 上创建一个名为recover-branch 的分支:

$ git branch recover-branch ab1afef$ git log --pretty=oneline recover-branchab1afef80fac8e34258ff41fc1b867c702daa24b modified repo a bit484a59275031909e19aadb7c92262719cfcdf19a added repo.rb1a410efbd13591db07496601ebc7a059dd55cfe9 third commitcac0cab538b970a37ea1e769cbbde608743bc96d second commitfdf4fc3344e67ab068f836878b6c4951e3b15f3d first commit酷!这样有了一个跟原来 master 一样的 recover-branch 分支,最新的两个 commit 又找回来了。接着,假设引起 commit 丢失的原因并没有记录在 reflog 中 ── 可以通过删除recover-branch 和 reflog 来模拟这种情况。这样最新的两个 commit 不会被任何东西引用到:

$ git branch -D recover-branch$ rm -Rf .git/logs/因为 reflog 数据是保存在 .git/logs/ 目录下的,这样就没有 reflog 了。现在要怎样恢复 commit 呢?办法之一是使用git fsck 工具,该工具会检查仓库的数据完整性。如果指定 --ful 选项,该命令显示所有未被其他对象引用 (指向) 的所有对象:

$ git fsck --fulldangling blob d670460b4b4aece5915caf5c68d12f560a9fe3e4dangling commit ab1afef80fac8e34258ff41fc1b867c702daa24bdangling tree aea790b9a58f6cf6f2804eeac9f0abbe9631e4c9dangling blob 7108f7ecb345ee9d0084193f147cdad4d2998293本例中,可以从 dangling commit 找到丢失了的 commit。用相同的方法就可以恢复它,即创建一个指向该 SHA 的分支。

移除对象
Git 有许多过人之处,不过有一个功能有时却会带来问题:git clone 会将包含每一个文件的所有历史版本的整个项目下载下来。如果项目包含的仅仅是源代码的话这并没有什么坏处,毕竟 Git 可以非常高效地压缩此类数据。不过如果有人在某个时刻往项目中添加了一个非常大的文件,那们即便他在后来的提交中将此文件删掉了,所有的签出都会下载这个 大文件。因为历史记录中引用了这个文件,它会一直存在着。

当你将 Subversion 或 Perforce 仓库转换导入至 Git 时这会成为一个很严重的问题。在此类系统中,(签出时) 不会下载整个仓库历史,所以这种情形不大会有不良后果。如果你从其他系统导入了一个仓库,或是发觉一个仓库的尺寸远超出预计,可以用下面的方法找到并移除 大 (尺寸) 对象。

警告:此方法会**提交历史。为了移除对一个大文件的引用,从最早包含该引用的 tree 对象开始之后的所有 commit 对象都会被重写。如果在刚导入一个仓库并在其他人在此基础上开始工作之前这么做,那没有什么问题 ── 否则你不得不通知所有协作者 (贡献者) 去衍合你新修改的 commit 。

为了演示这点,往 test 仓库中加入一个大文件,然后在下次提交时将它删除,接着找到并将这个文件从仓库中永久删除。首先,加一个大文件进去:

$ curl http://kernel.org/pub/software/scm/git/git-1.6.3.1.tar.bz2 > git.tbz2$ git add git.tbz2$ git commit -am 'added git tarball'[master 6df7640] added git tarball 1 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 git.tbz2喔,你并不想往项目中加进一个这么大的 tar 包。最后还是去掉它:

$ git rm git.tbz2rm 'git.tbz2'$ git commit -m 'oops - removed large tarball'[master da3f30d] oops - removed large tarball 1 files changed, 0 insertions(+), 0 deletions(-) delete mode 100644 git.tbz2对仓库进行 gc 操作,并查看占用了空间:

$ git gcCounting objects: 21, done.Delta compression using 2 threads.Compressing objects: 100% (16/16), done.Writing objects: 100% (21/21), done.Total 21 (delta 3), reused 15 (delta 1)可以运行 count-objects 以查看使用了多少空间:

$ git count-objects -vcount: 4size: 16in-pack: 21packs: 1size-pack: 2016prune-packable: 0garbage: 0size-pack 是以千字节为单位表示的 packfiles 的大小,因此已经使用了 2MB 。而在这次提交之前仅用了 2K 左右 ── 显然在这次提交时删除文件并没有真正将其从历史记录中删除。每当有人复制这个仓库去取得这个小项目时,都不得不复制所有 2MB 数据,而这仅仅因为你曾经不小心加了个大文件。当我们来解决这个问题。

首先要找出这个文件。在本例中,你知道是哪个文件。假设你并不知道这一点,要如何找出哪个 (些) 文件占用了这么多的空间?如果运行 git gc,所有对象会存入一个 packfile 文件;运行另一个底层命令git verify-pack 以识别出大对象,对输出的第三列信息即文件大小进行排序,还可以将输出定向到 tail 命令,因为你只关心排在最后的那几个最大的文件:

$ git verify-pack -v .git/objects/pack/pack-3f8c0...bb.idx | sort -k 3 -n | tail -3e3f094f522629ae358806b17daf78246c27c007b blob   1486 734 466705408d195263d853f09dca71d55116663690c27c blob   12908 3478 11897a9eb2fba2b1811321254ac360970fc169ba2330 blob   2056716 2056872 5401最底下那个就是那个大文件:2MB 。要查看这到底是哪个文件,可以使用第 7 章中已经简单使用过的 rev-list 命令。若给 rev-list 命令传入 --objects 选项,它会列出所有 commit SHA 值,blob SHA 值及相应的文件路径。可以这样查看 blob 的文件名:

$ git rev-list --objects --all | grep 7a9eb2fb7a9eb2fba2b1811321254ac360970fc169ba2330 git.tbz2接下来要将该文件从历史记录的所有 tree 中移除。很容易找出哪些 commit 修改了这个文件:

$ git log --pretty=oneline -- git.tbz2da3f30d019005479c99eb4c3406225613985a1db oops - removed large tarball6df764092f3e7c8f5f94cbe08ee5cf42e92a0289 added git tarball必须重写从 6df76 开始的所有 commit 才能将文件从 Git 历史中完全移除。这么做需要用到第 6 章中用过的 filter-branch 命令:

$ git filter-branch --index-filter \   'git rm --cached --ignore-unmatch git.tbz2' -- 6df7640^..Rewrite 6df764092f3e7c8f5f94cbe08ee5cf42e92a0289 (1/2)rm 'git.tbz2'Rewrite da3f30d019005479c99eb4c3406225613985a1db (2/2)Ref 'refs/heads/master' was rewritten--index-filter 选项类似于第 6 章中使用的 --tree-filter 选项,但这里不是传入一个命令去修改磁盘上签出的文件,而是修改暂存区域或索引。不能用rm file 命令来删除一个特定文件,而是必须用 git rm --cached 来删除它 ── 即从索引而不是磁盘删除它。这样做是出于速度考虑 ── 由于 Git 在运行你的 filter 之前无需将所有版本签出到磁盘上,这个操作会快得多。也可以用--tree-filter 来完成相同的操作。git rm 的 --ignore-unmatch 选项指定当你试图删除的内容并不存在时不显示错误。最后,因为你清楚问题是从哪个 commit 开始的,使用filter-branch 重写自 6df7640 这个 commit 开始的所有历史记录。不这么做的话会重写所有历史记录,花费不必要的更多时间。

现在历史记录中已经不包含对那个文件的引用了。不过 reflog 以及运行 filter-branch 时 Git 往 .git/refs/original 添加的一些 refs 中仍有对它的引用,因此需要将这些引用删除并对仓库进行 repack 操作。在进行 repack 前需要将所有对这些 commits 的引用去除:

$ rm -Rf .git/refs/original$ rm -Rf .git/logs/$ git gcCounting objects: 19, done.Delta compression using 2 threads.Compressing objects: 100% (14/14), done.Writing objects: 100% (19/19), done.Total 19 (delta 3), reused 16 (delta 1)看一下节省了多少空间。

$ git count-objects -vcount: 8size: 2040in-pack: 19packs: 1size-pack: 7prune-packable: 0garbage: 0repack 后仓库的大小减小到了 7K ,远小于之前的 2MB 。从 size 值可以看出大文件对象还在松散对象中,其实并没有消失,不过这没有关系,重要的是在再进行推送或复制,这个对象不会再传送出去。如果真的要完全把这个对象删除,可以运行git prune --expire 命令。



9.8  总结
现在你应该对 Git 可以作什么相当了解了,并且在一定程度上也知道了 Git 是如何实现的。本章覆盖了许多 plumbing 命令 ── 这些命令比较底层,且比你在本书其他部分学到的 porcelain 命令要来得简单。从底层了解 Git 的工作原理可以帮助你更好地理解为何 Git 实现了目前的这些功能,也使你能够针对你的工作流写出自己的工具和脚本。

Git 作为一套 content-addressable 的文件系统,是一个非常强大的工具,而不仅仅只是一个 VCS 供人使用。希望借助于你新学到的 Git 内部原理的知识,你可以实现自己的有趣的应用,并以更高级便利的方式使用 Git。

论坛徽章:
3
天秤座
日期:2013-12-27 13:44:58射手座
日期:2014-05-22 16:52:43天蝎座
日期:2014-08-13 16:03:21
34 [报告]
发表于 2014-05-23 23:59 |只看该作者
watch命令可以间断性地运行某个应用程序,并显示输出。
语法watch  [-dhvt]  [-n <seconds>] [--differences[=cumulative]] [--help] [--interval=<seconds>] [--no-title] [--version] <com-mand>
参数选项-n或—interval
    watch缺省每2秒运行一下程序,可以用-n或–interval来指定间隔的时间。
-d或–differences
用-d或–differences 选项watch 会高亮显示变化的区域。而—cumulative  选项会把变动过的地方(不管最近的那次有没有变动)都高亮显示出来。
-t 或–no-title
-t 或–no-title 选项会关闭watch命令在顶部的时间间隔、命令、当前时间的输出。
样例


watch –differences=cumulative uptime
watch -t –differences=cumulative uptime

linux终端中输出彩色字体(C/SHELL)  这几天在用libvlc的时候看到它在terminal里面输出彩色字体觉得挺好玩的,以为是用ncurses实现的,后来一查原来用ANSI C的转义字符就可以实现,不过好现只在linux下有效吧, windows神马的貌似不行,把项目终端凌乱的输出信息整理了一下,关键字符也都用彩色显示,看上去舒服多了,写一下用法以防止以后忘了再去查。

先把控制码列出来(从网上搜来的):

\033[0m               关闭所有属性

\033[1m                       设置高亮度

\033[4m                       下划线

\033[5m                        闪烁

\033[7m                        反显

\033[8m                        消隐

\033[30m----\33[37m 设置前景色

\033[40m----\33[47m 设置背景色

\033[nA                        光标上移n行

\033[nB                       光标下移n行

\033[nC                       光标右移n行

\033[nD                       光标左移n行

\033[y;xH                     设置光标位置

\033[2J                        清屏

\033[K                         清除从光标到行尾的内容

\033[s                          保存光标位置

\033[u                          恢复光标位置

\033[?25l                      隐藏光标

\033[?25h                     显示光标

背景色:
40:黑 41:深红 42:绿 43:黄色 44:蓝色 45:紫色 46:深绿 47:白色
前景色:
30:黑 31:红 32:绿 33:黄 34:蓝色 35:紫色 36:深绿 37:白色

控制字符是打开某种样式,输出完成时需要再关闭样式才能使terminal恢复到原来状态,简单例子:

printf("\e[32m%s\e[0m\n", "hello world");

\033和\e是一回事,使用\e会更简单一些,输出为绿色字体,如下图:


\e[32m为打开绿色前景色样式,\e[0m为关闭所有样式,如果未关闭,则所有输出字体均为绿色前景色,如下代码:

         printf("\e[32m%s\e[0m\n", "hello world");

输出效果如下:


绿色高亮代码如下:

printf("\e[32m\e[1m%s\e[0m\n", "hello world");

输出效果如下:


另外光标移动的控制码在输出类似于下载进度的信息时用得到。

在shell中也可以直接用echo输出,需要加-e选项打开转义字符解释,如输出高亮的绿色字体为:

echo -e "\e[32m\e[1mhello world\e[0m"

其它的我也没怎么看,觉得也就改变字体颜色和移动光标位置能用得到,觉得挺好玩的就写下来以后忘了查一查。
linux常用命令  uname -a    查看内核版本      
ls -al    显示所有文件的属性
pwd         显示当前路径      
cd -    返回上一次目录     cd ~    返回主目录
date s      设置时间、日期         
cal      显示日历     cal 2006
bc          计算器具              
man  & info     帮助手册
locale     显示当前字体     locale -a    所有可用字体     /etc/sysconfig/i18n设置文件
LANG=en    使用英文字体           
sync       将数据同步写入硬盘      
shutdonw -h now & half & poweroff  关机
reboot     重启                  
startx  &  init 5   进入图形介面
/work  & ?work    向上、下查找文档内容
chgrp      改变档案群组  chgrp testing install.log   
chown     改变所属人   chown root:root install.log
chmod      改变属性     chmod 777 install.log     read=4  write=2  execute=1
cp   复制   cp filename
rm   删除文件  rm -rf filename   强制删除文件
rmdir   删除文件夹
mv  移动    mv 123.txt 222.txt  重命名
mkdir     创建文件夹
touch     创建文件  更新当前时间
cat       由第一行开始显示     cat |more  分页
nl        在内容前加行号
more  &  less   一面一面翻动
head -n filename   显示第N行内容
tail -n filename  显示后N行内容
od        显示非纯文档
df -h 显示分区空间
du  显示目录或文件的大小
fdisk   分区设置    fdisk -l /dev/hda  显示硬盘分区状态
mkfs    建立各种文件系统  mkfs -t ext3  /dev/ram15  
fsck    检查和修复LINUX档案
ln      硬链接   ln -s  软件链接
whereis   查找命令
locate    查找
find      查找   find / -name "***.***"
which     查看工具
whoami    显示当前用户
gcc -v    查看GCC版本
chattr +i filename  禁止删除   chattr -i filename  取消禁止
lsattr    显示隐藏档属性
updatedb  更新资料库
mke2fs    格式化   mkfs -t ext3
dd if=/etc/passwd ōf=/tmp/passwd.bak    备份
mount     列出系统所有的分区
mount -t iso9660 /dev/cdrom /mnt/cdrom   挂载光盘
mount -t vfat /dev/fd0 /mnt/floppy       挂载软盘
mount -t vfat -o iocharset=utf8,umask=000 /dev/hda2 /mnt/hda2   挂载fat32分区
mount -t ntfs -o nls=utf8,umask=000 /dev/hda3 /mnt/hda3         挂载ntfs分区
Linux-NTFS Project: http://linux-ntfs.sourceforge.net/
umount /mnt/hda3  缷载
ifconfig   显示或设置网络设备
service network restart   重启网卡
ifdown eth0  关闭网卡
ifup eth0    开启网卡
clear    清屏
history    历史记录       !55  执行第55个指令
stty   设置终端    stty -a
fdisk /mbr   删除GRUB
at     僅進行一次的工作排程
crontab   循環執行的例行性命令    [e]编辑,[l]显示,[r]删除任务
&       后台运行程序    tar -zxvf 123.tar.gz & --------->后台运行
jobs    观看后台暂停的程序   jobs -l
fg      将后台程序调到前台   fg n ------>n是数字,可以指定进行那个程序
bg      让工作在后台运行
kill    结束进程    kill -9 PID     [9]强制结束,[15]正常结束,[l]列出可用的kill信号
ps aux  查看后台程序  
top     查看后台程序   top -d 2    每两秒更新一次        top -d 2 -p10604   观看某个PID
        top -b -n 2 > /tmp/top.txt ----->將 top 的資訊進行 2 次,然後將結果輸出到 /tmp/top.txt   
pstree   以树状图显示程序    [A]以 ASCII 來連接, 列出PID, [p]列出帐号
killall   要刪除某個服務    killall -9 httpd
free      显示内存状态     free -m  -------->以M为单位显示
uptime    显示目前系统开机时间
netstat   显示网络状态    netstat -tulnp------>找出目前系統上已在監聽的網路連線及其 PID
dmesg     显示开机信息    demsg | more
nice      设置优先权      nice -n -5 vi & ----->用 root 給一個 nice 植為 -5 ,用於執行 vi
renice    调整已存在优先权
runlevel  显示目前的runlevel
depmod    分析可载入模块的相依性
lsmod     显示已载入系统的模块
modinfo   显示kernel模块的信息
insmod    载入模块
modprobe   自动处理可载入模块
rmmod     删除模块
chkconfig   检查,设置系统的各种服务     chkconfig --list ----->列出各项服务状态
ntsysv     设置系统的各种服务
cpio      备份文件


压缩命令:
*.Z      compress 程式壓縮的檔案;
*.bz2    bzip2 程式壓縮的檔案;
*.gz     gzip 程式壓縮的檔案;
*.tar    tar 程式打包的資料,並沒有壓縮過;
*.tar.gz tar 程式打包的檔案,其中並且經過 gzip 的壓縮
compress filename  压缩文件  加[-d]解压  uncompress
gzip filename   压缩  加[-d]解压  zcat 123.gz 查看压缩文件内容
bzip2 -z filename  压缩  加[-d]解压   bzcat filename.bz2  查看压缩文件内容
tar -cvf /home/123.tar /etc  打包,不压缩
tar -xvf 123.tar   解开包
tar -zxvf /home/123.tar.gz  以gzip解压
tar -jxvf /home/123.tar.bz2  以bzip2解压
tar -ztvf /tmp/etc.tar.gz   查看tar内容
cpio -covB  > [file|device]   份份
cpio -icduv < [file|device]   还原

vi一般用法
一般模式              编辑模式                  指令模式
h 左               a,i,r,o,A,I,R,O             :w 保存
j 下                进入编辑模式                :w! 强制保存
k 上                dd 删除光标当前行           :q! 不保存离开
l 右                ndd 删除n行                 :wq! 保存后离开
0 移动到行首        yy 复制当前行                :e! 还原原始档
$ 移动到行尾        nyy 复制n行                  :w filename 另存为
H 屏幕最上          p,P 粘贴                     :set nu 设置行号
M 屏幕中央          u  撤消                      :set nonu 取消行号
L 屏幕最下          [Ctrl]+r 重做上一个动作       ZZ 保存离开
G 档案最后一行      [ctrl]+z 暂停退出            :set nohlsearch   永久地关闭高亮显示
/work 向下搜索                                   :sp 同时打开两个文档
?work 向上搜索                                   [Ctrl]+w 两个文档设换
gg 移动到档案第一行                              :nohlsearch    暂时关闭高亮显示

认识SHELL
alias    显示当前所有的命令别名      alias lm="ls -al"   命令别名    unalias lm 取消命令别名
type      类似which
exprot    设置或显示环境变量
exprot PATH="$PATH":/sbin  添加/sbin入PATH路径
echo $PATH    显示PATH路径
bash      进入子程序
name=yang     设定变量
unset name    取消变量
echo $name    显示变量的内容
myname="$name its me"   &   myname='$name its me'     单引号时$name失去变量内容
ciw=/etc/sysconfig/network-scrīpts/     设置路径
env      列出所有环境变量
echo $RANDOM    显示随意产生的数
set      设置SHELL
PS1='[\u@\h \w \A #\#]\$ '     提示字元的設定
   [root@linux ~]# read [-pt] variable     -----------读取键盘输入的变量
   參數:
   -p  :後面可以接提示字元!
   -t  :後面可以接等待的『秒數!』
declare    声明 shell 变量
ulimit -a   显示所有限制资料
ls /tmp/yang && echo "exist" || echo "not exist"
意思是說,當 ls /tmp/yang 執行後,若正確,就執行echo "exist" ,若有問題,就執行echo "not exist"
echo $PATH | cut -d ':' -f 5       以:为分隔符,读取第5段内容
export | cut -c 10-20      读取第10到20个字节的内容
last | grep 'root'    搜索有root的一行,加[-v]反向搜索
cat /etc/passwd | sort    排序显示
cat /etc/passwd | wc      显示『行、字数、字节数』
正规表示法
[root@test root]# grep [-acinv] '搜尋字串' filename
       參數說明:
       -a :將 binary 檔案以 text 檔案的方式搜尋資料
       -c :計算找到 '搜尋字串' 的次數
       -i :忽略大小寫的不同,所以大小寫視為相同
       -n :順便輸出行號
       -v :反向選擇,亦即顯示出沒有 '搜尋字串' 內容的那一行!
grep -n 'the' 123.txt     搜索the字符 -----------搜尋特定字串      
grep -n 't[ea]st' 123.txt    搜索test或taste两个字符---------利用 [] 來搜尋集合字元
grep -n '[^g]oo' 123.txt     搜索前面不为g的oo-----------向選擇 [^]
grep -n '[0-9]' 123.txt  搜索有0-9的数字
grep -n '^the' 123.txt 搜索以the为行首-----------行首搜索^
grep -n '^[^a-zA-Z]' 123.txt  搜索不以英文字母开头
grep -n '[a-z]$' 123.txt    搜索以a-z结尾的行---------- 行尾搜索$
grep -n 'g..d' 123.txt     搜索开头g结尾d字符----------任意一個字元 .
grep -n 'ooo*' 123.txt     搜索至少有两个oo的字符---------重複字元 *
sed    文本流编辑器    利用脚本命令来处理文本文件
awd    模式扫描和处理语言
nl 123.txt | sed '2,5d'   删除第二到第五行的内容
diff     比较文件的差异
cmp      比较两个文件是否有差异
patch    修补文件
pr       要打印的文件格式化


帐号管理
/etc/passwd    系统帐号信息
/etc/shadow    帐号密码信息    经MD5 32位加密
     在密码栏前面加『 * 』『 ! 』禁止使用某帐号
/etc/group     系统群组信息
/etc/gshadow
newgrp    改变登陆组
useradd  &  adduser    建立新用户  ---------> useradd -m test  自动建立用户的登入目录
          useradd -m -g pgroup test --------->指定所属级
/etc/default/useradd   相关设定
/etc/login.defs       UID/GID 有关的設定
passwd    更改密码 -----------> passwd test
usermod   修改用户帐号
userdel   删除帐号 ----------->userdel -r test
chsh      更换登陆系统时使用的SHELL   [-l]显示可用的SHELL;[-s]修改自己的SHELL
chfn      改变finger指令显示的信息
finger    查找并显示用户信息
id        显示用户的ID ----------->  id test
groupadd   添加组
groupmod   与usermod类似
groupdel   删除组
su test    更改用户   su -    进入root,且使用root的环境变量
sudo       以其他身份来执行指令
visudo     编辑/etc/sudoers      加入一行『 test ALL=(ALL) ALL 』
           %wheel ALL = (ALL) ALL               系统里所有wheel群组的用户都可用sudo
           %wheel ALL = (ALL) NOPASSWD: ALL     wheel群组所有用户都不用密码NOPASSWD
       User_Alias ADMPW = vbird, dmtsai, vbird1, vbird3         加入ADMPW组
       ADMPW ALL = NOPASSWD: !/usr/bin/passwd, /usr/bin/passwd [A-Za-z]*, \
       !/usr/bin/passwd root      可以更改使用者密码,但不能更改root密码 (在指令前面加入 ! 代表不可)
PAM (Pluggable Authentication Modules, 嵌入式模組)
who & w     看谁在线                    
last        最近登陆主机的信息
lastlog     最近登入的時間    读取 /var/log/lastlog
talk        与其他用户交谈
write       发送信息    write test   [ctrl]+d 发送
mesg        设置终端机的写入权限    mesg n 禁止接收     mesg y
wall        向所有用户发送信息    wall this is q test
mail        写mail  
/etc/default/useradd    家目录默认设置
quota      显示磁盘已使用的空间与限制     quota -guvs ----->秀出目前 root 自己的 quota 限制值
           quota -vu   查询
quotacheck   检查磁盘的使用空间与限制     quotacheck -avug  ----->將所有的在 /etc/mtab 內,含有 quota 支援的 partition 進行掃瞄
             [-m] 强制扫描
     quota一定要是独立的分区,要有quota.user和quota.group两件文件,在/etc/fstab添加一句:
     /dev/hda3 /home ext3 defaults,usrquota,grpquota 1 2
     chmod 600 quota*         设置完成,重启生效
edquota    编辑用户或群组的quota  用户,[g]群组,[p]复制,[t]设置宽限期限
           edquota -a yang       edquota -p yang -u young ----->复制   
quotaon    开启磁盘空间限制     quotaon -auvg -------->启动所有的具有 quota 的 filesystem
quotaoff   关闭磁盘空间限制     quotaoff -a  -------->关闭了 quota 的限制
repquota -av     查閱系統內所有的具有 quota 的 filesystem 的限值狀態
Quota 从开始準備 filesystem 的支援到整個設定結束的主要的步驟大概是:
1、設定 partition 的 filesystem 支援 quota 參數:
由於 quota 必須要讓 partition 上面的 filesystem 支援才行,一般來說, 支援度最好的是 ext2/ext3 ,
其他的 filesystem 類型鳥哥我是沒有試過啦! 启动 filesystem 支援 quota 最简单就是编辑 /etc/fstab ,
使得準備要开放的 quota 磁碟可以支援 quota 囉;
2、建立 quota 記錄檔:
剛剛前面講過,整個 quota 進行磁碟限制值記錄的檔案是 aquota.user/aquota.group,
要建立這兩個檔案就必須要先利用 quotacheck 掃瞄才行喔!
3、编辑 quota 限制值資料:
再來就是使用 edquota 來编辑每個使用者或群組的可使用空間囉;
4、重新掃瞄與启动 quota :
設定好 quota 之後,建議可以再進行一次 quotacheck ,然後再以 quotaon 來启动吧!

开机流程简介
1、載入 BIOS 的硬體資訊,並取得第一個关机裝置的代號;
2、讀取第一個关机裝置的 MBR 的 boot Loader (亦即是 lilo, grub, spfdisk 等等) 的关机資訊;
3、載入 Kernel 作業系統核心資訊, Kernel 开始解壓縮,並且嘗試驅動所有硬體裝置;
4、Kernel 執行 init 程式並取得 run-level 資訊;
5、init 執行 /etc/rc.d/rc.sysinit 檔案;
6、启动核心的外掛模組 (/etc/modprobe.conf);
7、init 執行 run-level 的各個批次檔( scripts );
8、init 執行 /etc/rc.d/rc.local 檔案;
9、執行 /bin/login 程式,並等待使用者登入;
10、登入之後开始以 Shell 控管主机。
在/etc/rc.d/rc3.d內,以S开头的为开机启动,以K开头的为关闭,接着的数字代表执行顺序
GRUB vga设定
彩度\解析度  640x480  800x600  1024x768  1280x1024   bit
    256        769      771      773       775      8 bit
   32768       784      787      790       793     15 bit
   65536       785      788      791       794     16 bit
   16.8M       786      789      792       795     32 bit

./configure    检查系统信息       ./configure --help | more  帮助信息
make clean     清除之前留下的文件
make           编译
make install   安装
rpm -q  ----->查询是否安装             rpm -ql ------>查询该套件所有的目录
rpm -qi ----->查询套件的说明资料       rpm -qc[d] ----->设定档与说明档
rpm -ivh  ---->安装                    rpm -V  -------->查看套件有否更动过
rpm -e  ------>删除                    rpm -Uvh ------->升级安装
--nodeps ----->强行安装                --test ----->测试安装
du -sh /home/* 可以查看目前系统用户已经使用的空间,但其不是按大小顺序排列的
smbpassword -a 添加一个samba用户

论坛徽章:
3
天秤座
日期:2013-12-27 13:44:58射手座
日期:2014-05-22 16:52:43天蝎座
日期:2014-08-13 16:03:21
35 [报告]
发表于 2014-05-24 00:00 |只看该作者
配置linux登录欢迎信息
直接在/etc/motd文件中输入即可

命令:hostname   显示机器名
   修改机器名:修改文件/etc/HOSTNAME,修改后重启本地网络文件:/etc/init.d/boot.localnet start
              同时,也要将/etc/hosts文件中IP对应的机器名也修改一下
   或者使用 hostname <new hostname> 命令实时修改机器名(此时,还需要修改/etc/HOSTNAME 和 /etc/hosts文件,以便重启后还会生效)

命令:mutt   发送邮件
linux的配置:
1)通过windows的“ipconfig /all” 命令可以知道linux服务器当前的DNS服务器
2)通过yast命令的“Network Services/DNS and Host Name/”,
        修改域名为“huawei”,“Name Server 1/Name Server 2”为DNS服务器IP地址
      或者直接修改/etc/resolv.conf文件,其格式类似如下:
        nameserver 202.96.128.86
        nameserver 202.96.64.68
        search huawei
3)执行“/etc/rc.d/postfix start”命令
命令格式:
echo "邮件内容" | mutt -s "邮件标题"  -a "附件1" -a "附件2" zhuchunjian@huawei.com jihongyi@huawei.com

江西局点部署iptv_check,按照操作指导添加DNS并启动邮件发送功能后,还是发不了邮件,
后来跟现场用服研究了下,是交换机策略问题,需要放开这两个应用的端口,
这在其他局点也可能会碰到,最好在安装文档中说明下。

======================================================

在交换机上做的安全策略

rule 5 permit udp source-port eq dns destination 115.153.255.87 0

rule 10 permit tcp source-port eq smtp destination 115.153.255.87 0


命令:vi 编辑文件
        有时候vi会core,则删除~/.viminfo文件就可能解决,并用 "killall -9 vim; killall -9 vi" 杀掉已挂起的vi进程
        ctrl+v 进入列模式
        fx     表示查找,在当前行中向右搜素字符‘x’并定位到该字符出现的第一个位置。“;”重复该命令。 “,”重复该命令,但向左搜索
        Fx     同fx,只是方向相反。
        tx     表示to,同fx,只是光标定位在该字符的前一个位置。
        Tx     同tx,只是方向相反。
        H      (Home)光标定位到当前屏幕的最上方;    M (Middle)光标定位到屏幕的中间;   L (Last)光标定位到屏幕的最下方
        Ctrl+d 屏幕向下滚动半屏          Ctrl+u 屏幕向上滚动半屏
        Ctrl+f 屏幕向下滚动一屏          Ctrl+b 屏幕向上滚动一半屏
        Ctrl+e 向上滚动一行,光标行不变(光标到达屏幕的最上方,光标行才会变化)
        Ctrl+y 向下滚动一行,光标行不变(光标到达屏幕的最下方,光标行才会变化)
        zz     将当前光标行置于屏幕中间
        zt     将当前光标行置于屏幕最上方
        zb     将当前光标行置于屏幕最下方
        打开一个比较长的文档,跟我做 zfG , 现在是不是全部文章都折叠成一行,高亮显示了?
        这里 zf 是创建一个 folder,G 是移动到文件尾部,这样也就全都装进来了,也可以用其他的移动手段,呵呵
        然后 zo 就是打开折叠文本,zc 是再把它们折叠起来。如果有很多折叠文本,用zr 就把它们全部打开了,zm 是把它们全部折叠。如果有嵌套的折叠文本,可以用zR 和 zM 一次完                成打开和关闭。zn 是关闭折叠功能,zN 是重新打开折叠功能,zi是在两者间切换。
        折叠成一行的文本可以在 visual 模式下被剪切、复制、粘贴,很方便。

        50%    表示定位到当前文件的50%处,50表示百分比。
        30G    表示定位到当前文件的第30行。
        gg     定位到第一行,同1G                     G   定位到文件最后一行,同100%
        Ctrl+g 显示文件名,以及光标位置(g也可以大写)
        
        %      括弧匹配
        *      在某个word处,按*表示以当前word为关键字,进行全字匹配搜索,并定位到下一个出现的位置。
        3*     表示定位到下面第3个出现的位置
        g*     表示当前word可以包含在其他word中(即,非全字匹配),也可以用“3g*”定位到第3个出现的位置
        #      同*,只是搜索方向为向上

        v或V   进入visual模式,此时,o命令表示跳转到选择文本的另一头(other end),O命令在左右两角移动
        
        yw     复制一个单词到寄存器中;
        yy     复制一行到寄存器中;        p  从当前寄存器中粘贴
        "xyy   复制一行到寄存器x中;       "xp从寄存器x中粘贴

        :iab <缩写> <实际字符串>        定义缩写字符(iabbrev);                   :abbreviate  显示所有的缩写
        :abclear   清除所有缩写
        
        :e!    放弃当前所有的编辑,并重新加载该文件的原始内容
        :set number           显示行号;   :set nonumber  关闭行号
        :set ruler            在右下角显示关闭位置
        :set ic               忽略大小写   :set noic      取消忽略大小写
        :set hlsearch         高亮显示     :set nohlsearch取消高亮显示
        :set incsearch        增量搜索
        :set nowrapscan       非折叠搜索
        :set shiftwidth=4    设置自动缩进 4 个空格, 当然要设自动缩进先.
        :set sts=4           即设置 softtabstop 为 4. 输入 tab 后就跳了 4 格.
        :set tabstop=4       实际的 tab 即为 4 个空格, 而不是缺省的 8 个.
        :set expandtab       在输入 tab 后, vim 用恰当的空格来填充这个 tab.
        :set paste           进入粘贴模式,粘贴的内容将不会缩进
        :next         下一个文件;        :prev  上一个文件;        :args  文件列表
   宏:
        q{register}        开始录制宏,录制结束时按q退出
        @{register}        运行宏
   标记:
        ``(2个反撇号)        跳回到上次光标的位置
        Ctrl+i               跳回到上次更新的位置
        m{mark}              设置标签;                `{mark} (反撇号)跳到标签出;        :marks    显示所有标签

命令:du 查看目录大小
        du -sk .    显示单位为KB
        du -sh .    显示单位会自动调整
        du -sh *    显示当前目录下的所有文件和目录大小

命令:find  查找
        find命令参数中的数字n含义: +n  表示 “> n”; -n 表示 “< n”;  n 表示 “= n”
        如, find . -mmin +2  表示查找当前目录下、修改时间大于2分钟的文件(即,2分钟之前的文件)
             find . -mmin -2  表示查找当前目录下、修改时间小于2分钟的文件(即,2分钟之后的文件)
        -amin n     文件访问时间在n 分钟前
        -atime n    文件访问时间在n 天前
        -mmin n     文件修改时间在n 分钟前
        -mtime n    文件修改时间在n 天前
        -size n[bckw]     文件大小,b 表示单位为block(块,512字节),默认单位;
                                    c 表示单位为字节; k 表示单位为KB;  w 表示单位为2个字节
        -type c     指定文件类型,c取值: d 表示目录; f 表示普通文件; l 表示link文件; s 表示sock; p 表示pipe

        find命令中的条件默认是“与”(-a)的关系,如果需要“或”的关系,则使用-o:
                find . \( -name "*.txt" -o -name "*.csv" \) -a -type f  查找当前目录下的txt或者csv文件
        find . -mtime +5 -name "*.log" -exec tar --remove-files -rf logs.tar {} \;   查找当前目录下、5天前的log文件,并打包
        find . -path "./dir1/dir2/*" -maxdepth 3          只查找./dir1/dir2/目录下的内容,不包括其子目录的内容。
        find . -name "*.csv" -exec bash -c "cat {} >  {}.txt" \;        # exec中使用重定向
        find /home/huawei/mdn2000/rrs/logs/agent/run -printf "%f\n"     # 只打印最后的文件名(不包括路径)
        find . -name "*.sinf" -printf "%p,%Ax %AT\n" |sort -t, -k2r | head -1  # 查找当前目录下最新的*.sinf文件



命令:mount  挂载存储
格式: mount -a [-fv] [-t vfstype] [-n] [-rw] [-F] <device> <dir>
        mount -o loop <iso_file> <dest_dir>        解开iso文件到<dest_dir>目录下
        mount --bind <src_dir> <dest_dir>          mount本地目录
                /etc/fstab:   /mnt/mydir  /home/hms/data/c  auto bind 0 0
        mount -t smbfs //IP/share_dir <dest_dir> -o username=zcj        mount Windows共享目录(回车后需要输入密码)

命令:iptables linux配置防火墙
        iptables -L 显示当前配置;        iptables -F 清空当前所有配置;
        iptables -A INPUT -s 10.164.79.205 -j DROP        限制特定的IP访问本机
        iptables -A INPUT -s 10.168.67.0/24 -j DROP       限定IP段
        iptables -A INPUT -d 10.137.13.77 -p udp -j REJECT
        iptables -A INPUT -p tcp --sport 554 --dport 554 -j REJECT        限制特定端口访问本机

命令cpio  cpio文件操作
        cpio -idF test.cpio        解压

命令:lsof (list opened files)   列举系统中已经被打开的文件
        lsof -n                 显示结果时,不将IP转换为hostname
        lsof -P                 显示结果时,不将Port转换为services名
        lsof -i[46] [protocol][@hostaddr][:port]     用以显示符合条件的进程情况
                4    表示IPv4; 6 表示IPv6
                protocol   表示协议:TCP 或 UDP
                hostaddr   表示主机地址
                port       表示端口号,可以有多个(以逗号分隔)
       示例:      lsof -ni @125.88.104.19:21,22   显示“与125.88.104.19的21或22端口”存在连接的进程信息
        lsof -p <pid>           显示进程<pid>打开的所有文件信息
        lsof <file_name>        显示打开<file_name>文件的所有进程
        lsof +d <dir>           显示<dir>目录下被打开的文件(不会搜索子目录)
        lsof +D <dir>           显示<dir>目录下被打开的文件(会搜索子目录)
        lsof -c <proc_name>     显示<proc_name>进程打开的文件

命令:time 打印程序运行的耗时
TIMEFORMAT="" time ./testprogram
输出:
0.00user 0.00system 0:12.62elapsed 0%CPU (0avgtext+0avgdata 5792maxresident)k
0inputs+8outputs (0major+4060minor)pagefaults 0swaps


命令:date  时间显示与设置
        date MMDDhhmm[[cc]YY][.ss]        设置时间,如date 12171830.00 设置当前时间为12月17日18点30分0秒(年份不变)
        date '+%Y-%m-%d %H:%M:%S.%N' 或者 date '+%F %X.%N'
               年 月 日 时 分 秒 纳秒
        date --date '2 days ago' +%F       获取2天前的日期
        date --date '2 days' +%F           获取2天后的日期
  指定特定日期的格式:  date -d 'string'
        其中,string由以下几个部分组成(各个部分以空格分隔):
            1,calendar date time  表示日期,有多种格式,但用格式 yyyy-mm-dd 即可。
            2,time of day         表示时间,格式:HH:MM[:SS[.XXXXXX]][am|pm][SHHMM],其中,S表示+或-,HH和MM分别表示小时,分钟
                                       如,12:20+0210 表示10:10 ,12:20-0210表示 14:30
            3,time zone           表示时区,如UTC,CST等
            4,day of the week     表示星期几
            5,relative            调整日期,格式: [+|-]整数 单位 [ago],  或者直接用如下字符串:yesterday,tomorrow,now,today,this
                                     单位有:失真的单位(year,month)精确的单位(fortnight(2周),week,day,hour,minute(min),second(sec))
                                     这些单位后可以加(s),也可以不加
            6,pure numbers        精确的date信息,当“calendar date time”未指定时,则日期从此处读取,格式:YYYYMMDD
                                                   当“time of day”未指定时,则时间从此处读取,格式:HHMM

  将指定日期转换为秒:    date -d '2008-10-12' +%s              # 结果为:2008-10-12与1970-01-01的时间差(单位:秒)  
  获取2009-11-12的后3天的日期:  date -d '2009-11-12 UTC 3 days'  +%F             # days 可以用hours,seconds,minutes
  获取2009-11-12的前3天的日期:  date -d '2009-11-12 UTC -3 days' +%F             # days 可以用hours,seconds,minutes
  获取timestamp时间对应的当前日期:time=1331974800
                                   diff=$(echo "$(date +%s) - $time"|bc)
                                   date -d "$diff seconds ago" +%F.%X

命令: 时区的概念
1,不管通过任何渠道我们想要同步系统的时间,通常提供方只会给出UTC+0的时间值而不会提供时区(因为它不知道你在哪里).所以当我们设置系统时间的时候,设置好时区是首先要做的工作
2,linux系统设置时区(有两种方法):
    1)系统预先编译了很多timezone文件,存放在/usr/share/zoneinfo目录下
       可以拷贝自己所在城市的timezone文件到 /etc/localtime
       也可以建一个链接: ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
    2)设置TZ环境变量: TZ='Asia/Beijing'; export TZ (该变量会覆盖/etc/localtime)
        如果不知道如何设置TZ变量值,可以使用tzselect命令选择


/etc/sysconfig/clock



命令: tethereal,tcpdump      抓包命令
        tethereal -ni bond0 host 10.164.79.105 and port 554
        tcpdump   -i any    host 10.164.79.105
       tcpdump -X -s 0 'dst port 554 and ip[2:2] > 60'            ip[2:2] 表示ip报文的第2个字节开始,取2个字节的值

tcpdump -i any  dst host 125.88.104.10 and ! \( 125.88.104.6 or 125.88.104.24 \) and dst port 60000
  类型的关键字: host,net,port
  传输的方向:   src,dst,dst or src, dst and src
  协议:        tcp,udp,ip,arp,rarp
  逻辑运算符:  and,&& ; or ,|| ; not ,!,


命令:echo   显示颜色
        echo -e "\e[背景色;前景色;1m字符串\e[m"
        背景色:40 黑;41 深红;42 绿;43 黄;44 蓝;45 紫;46 深绿;47 白;
        前景色:30 黑;31 红;  32 绿;33 黄;34 蓝;35 紫;36 深绿;37 白;

命令:crontab  配置定时任务
        每个用户都有独立的表格,在/var/spool/cron/tabs/目录下,以用户名命名的文件中
        crontab文件格式如下:(有6个域,以空格分隔)

分钟数
小时数
天数
月数
星期数
命令
范围
0-59
0-23
1-31
1-12
0-7(0和7表示星期天)


        时间域可以的格式:
        1),逗号分隔的列表: 如,分钟数域指定了0,1,2,则表示第0,1,2分钟时执行该命令
        2),范围:           如,分钟数域指定了0-4,则表示第0,1,2,3,4分钟时执行该命令
        3),每隔一段时间:   如,分钟数域指定了*/30,则表示每隔30分钟执行该命令
        4),组合:           如,分钟数域指定了0-4,8-12/2,则表示第0,2,4,8,10,12分钟时执行该命令
  注意:定时任务的命令中不能使用环境变量(除了$HOME,$USER)
        查看当前用户设置的定时任务:        crontab -l
        清除所有的定时任务:                crontab -r        
        手工修改定时任务:                  crontab -e        
        将定时任务存放到临时文件中,然后导入: crontab <临时文件>
        重启定时任务:                      rccron restart

命令:sort    排序
    sort -t, -k 1rn -k2,3
    -t  指定域分隔符,默认分隔符为空格
    -k  指定按第几列排序,r表示倒排,n表示按数字排列

命令:ls   列出文件
        ls -S 按文件大小倒序排列(-r 表示倒序排列)
        ls -t 按修改时间倒序排列

命令:uniq    唯一
        必须先排序,才能使用该命令
        uniq -c         将每一项出现的次数显示在前面

命令:tr   删除字符
        小写转大写        tr "[:lower:]" "[:upper:]"        或 tr "[a-z]" "[A-Z]"
        删除字符          tr -d "字符"
        删除重复字符,只保留第一个        tr -s "字符"
        删除文件中的^M    tr -s "[\r]" "[\n]" file

命令:snmpwalk   snmp查看OID值
    snmpwalk -v 3 -l authPriv -u p2eAy1H0MqSbGT6oDuzXC3Wv -a MD5 -A oRghaPqum1v7ZCHKxFey3sl5 -x DES -X oRghaPqum1v7ZCHKxFey3sl5 124.92.253.45 1.3.6.1.4.1.2011.20.3.12.1.6.0
    snmpwalk -v 2 -c public 125.88.105.225:161 1.3.6.1.2.1.2.2.1.5

命令:tar   打包,解压
        c 表示创建; x 表示解压; t 表示查看;
        tar -zcvf mytar.tar.gz myfiles/*                打包并压缩
        tar -zcvf mytar.tar.gz -X temp_file myfiles/*   打包(不包括temp_file文件中列出的文件)并压缩
        tar -zcvf mytar.tar.gz --exclude=abc/* .        打包当前目录下所有文件(但不包括abc目录下的文件)
        tar -zxvf mytar.tar.gz -T temp_file             temp_file文件中包含的文件都会被解压
        tar -zxvf mytar.tar.gz filename1 filename2 ...  解压mytar.tar.gz 包中指定的文件:filename1,filename2...

        tar -C/home/zcj -zcvf mem_check.tar.gz mem_check/        将当前目录下的mem_check打包,并将包保存到/home/zcj目录下
        tar -C/home/zcj -zxvf mem_check.tar.gz          将当前目录下的mem_check.tar.gz包解压到/home/zcj目录下

命令:diff    比较差异
        diff -y file1 file2 [-W120]    并排(-y)显示比较结果,每行最多显示120个字符
                结果说明:  < 表示只位于file1中
                            > 表示只位于file2中
                            | 数据不一致
        其他参数: -i 忽略大小写;        -E 忽略tab键;         -b 忽略空格;        -B 忽略空行;     -w  忽略所有空格;
                -r 比较目录时,递归子目录
                -q 只显示文件是否一致
                -d  或者 --suppress-common-lines(与-y配合)  只显示差异行
    sdiff命令相当于 “diff -y”命令

命令:LVS      LVS相关命令
    crm_mon -i 3  隔3秒刷新一次
    ipvsadm       查看路由信息,正常情况下,只有在一个RRS中会看到路由信息
    ipvsadm -C    清楚当前路由信息
   增加路由(在有虚拟IP的机器中执行):ipvsadm -a -t <虚拟IP>:554 -r <实际ip> -g -w 5

    rcheartbeat start 启动
    在/etc/ha.d/ha.cf 文件中找ucast可以查看心跳IP

命令:VCS          VCS相关命令
    清除出错的资源:   hagrp -clear db2-rg -sys mdndb1
                其中,db2-rg 表示资源名;  mdndb1 表示节点名
    清除Admin_wait状态: hagrp -clearadminwait db2-rg -sys mdndb1
    强制启动节点:       hasys -force mdndb1

命令:ntp           时间同步配置
    通常情况下,在设置的初始,在5至10分钟有内6次交换。 一旦同步后,每10分钟与服务器时间进行一次同步
    1)配置/etc/ntp.conf文件,只要存在如下项就可以了:
        server 125.88.104.19 prefer
        server 125.88.104.20
        fudge 127.127.1.0 stratum 4       # 设置本地时间源的层数为4,最大为15层,16表示不可访问
        driftfile /var/lib/ntp/drift/ntp.drift
        logfile   /var/log/ntp
    2)chmod 666 /var/lib/ntp/drift/ntp.drift
    3)如果存在/etc/init.d/xntpd文件,则用此文件启动ntp服务: /etc/init.d/xntpd start
                否则, rcntp start 启动
    4)查询ntp状态: ntpq -p,结果类似如下:
     remote           refid      st t when poll reach   delay   offset  jitter
==============================================================================
*125.88.104.19   202.96.168.10    2 u   10   64  377    1.339    0.953   0.266
+125.88.104.20   202.96.168.10    2 u    6   64  377    1.311    0.155   0.440
        *       主ntp服务器地址
        +       备ntp服务器地址
        remote  表示上层ntp服务器的地址
        refid   表示上层ntp服务器引用的地址
        st      表示ntp服务器的层数
        t       取值含义:u: unicast or manycast client, b: broadcast or multicast client, l: local (reference clock), s: symmetric (peer),
                          A: manycast server, B: broadcast server, M: multicast server
        when    当when==poll时,系统将与NTP服务器进行同步
        poll    表示同步间隔(秒),一开始该值比较小(同步频率高),当时间趋于稳定后,该值会扩大(同步频率降低)
        reach   表示与NTP Server同步的次数(8进制)
        delay   延误值,表示与上层服务器联系所花的时间,单位毫秒(0.001秒)
        offset  偏差值,表示与上层服务器的时间偏长,单位毫秒
        jitter  抖动值,这是一个用来做统计的值.它统计了在特定个连续的连接数里offset的分布情况.简单地说这个数值的绝对值越小,主机的时间就越精确
   5)如果时间相差很大(超过1000秒),则需要先通过如下方式同步一下,否则ntp无法进行同步:
     /etc/init.d/xntpd stop  停止ntp服务
     ntpdate -b 125.88.104.19 强制同步

论坛徽章:
3
天秤座
日期:2013-12-27 13:44:58射手座
日期:2014-05-22 16:52:43天蝎座
日期:2014-08-13 16:03:21
36 [报告]
发表于 2014-05-24 00:01 |只看该作者
命令:samba          samba配置
   1)在/etc/samba/smb.conf文件中增加:
   [home]
   comment = Home Directiories
   valid users = root
   path = /home

   read only = No
   2)smbpasswd修改密码
      如果提示“Failed to find entry for user root.”,则执行“smbpasswd -a root”,即,添加root用户并设置其密码
   3)rcsmb restart 重启服务

命令:CFS+2300            相关命令
    更换mount路径(从d盘更换为e盘)的步骤:(只需要在CFS集群中的任一台服务器中执行即可)
    1)卸载现有的d盘:  cfsumount /home/hms/data/d
    2)检查现有的mount点关联关系:  cfsmntadm display  结果类似如下:
  QY-BY1-S9-HMU1:~ # cfsmntadm display
  Cluster Configuration for Node: QY-BY1-S10-HMU2
  MOUNT POINT        TYPE      SHARED VOLUME     DISK GROUP       STATUS
  /home/hms/data/d Regular    dbvol            dbdg             MOUNTED
    3)删除现有的d盘: cfsmntadm delete /home/hms/data/d
    4)添加新mount点e盘: cfsmntadm add dbdg dbvol /home/hms/data/e
                          dbdg 指第二步中的“DISK GROUP”; dbvol指第二步中的“SHARED VOLUME”
    5)挂载新mount点: cfsmount /home/hms/data/e

命令:ifconfig         增加虚拟ip
   ifconfig eth6:1 192.168.3.49 netmask 255.255.255.0
   ifconfig  eth1 192.168.0.6 netmask 255.255.255.0 up
   ifconfig eth0 up
   ifconfig eth0 down

命令:ethtool   网卡信息查看
        ethtool eth0         查看网卡信息

命令:top       非交互式执行
   top -b -n 1        :-b 表示非交互式, -n 1 表示只显示一次
   top -p <pid>      只显示指定进程的数据

命令:xxd,od         十六进制查看
        xxd
        od

命令:mknod         建立块专用或字符专用文件   
mknod - 建立块专用或字符专用文件   
总览
mknod [options] name {bc} major minor
mknod [options] name p   
GNU 选项(缩写):
[-m mode] [--help] [--version] [--]   
描述
mknod 用指定名称产生一个FIFO(命名管道),字符专用或块专用文件。
文件系统中的一个专用文件存贮着三种信息(布朗型、整型、整型)。布朗型在字符文件与块文件之间作出选择,两个整型是主、次设备号。
通常,一个专用文件并不在磁盘上占用空间,仅仅是为操作系统提供交流,而不是为数据存贮服务。一般地,专用文件会指向一个硬件设备(如:磁盘、磁带、打印机、虚拟控制台)或者操作系统提供的服务(如:/dev/null, /dev/random)。
块文件通常类似于磁盘设备(在数据可以被访问的地方赋予一个块号,意味着同时设定了一个块缓存)。所有其他设备都是字符文件。(以前,两种文件类型间是有差别的。比如:字符文件I/O没有缓存,而块文件则有。)
mknod命令就是用来产生这种类型文件的。
以下参数指定了所产生文件的类型:
p    FIFO型
b    块文件
c    字符文件
GNU版本还允许使用u('unbufferd'非缓冲化),以保持与C语言的一致。
当创建一个块文件或字符文件时,主、次设备号必须在文件类型参数后给出。(十进制或八进制以0开头;GNU 版本还允许使用以0x开头的十六进制)缺省地,所产生的文件模式为0666('a+rw')。   
选项
-m mode, --mode=mode 为新建立的文件设定模式,就象应用命令chmod一样,以后仍然使用缺省模式建立新目录。
1   3   是主设备号1,次设备号3

linux中 /dev/null 被删除后恢复: mknod -m 666 /dev/null c 1 3

命令:watch     自动刷新某一命令的结果
    watch -n 2 -d "netstat -anp | grep  "121.11.155.42:554" | sort -k 3 -r"
    -n 2 表示每隔2秒刷新一次
    -d   表示每次刷新后,如果数据数据发生变化,则高亮显示差异
    双引号内表示每次刷新所执行的命令

命令:locale           locale配置
  locale -a         列出所有locale名称
  LC_ALL=zh_CN locale -ck LC_TIME        查询中文的日期时间格式

命令:  cat << EOF        cat命令
cat << 'E'OF   # 定界符以任何形式的引号(单引号,双引号都可以)括起来,则shell不会处理接下来的内容(主要是变量替换等)
hello $somebody
$(echo "hello"
EOF
结果打印:
hello $somebody
$(echo "hello"

命令:getconf         获取操作系统的参数
        getconf ARG_MAX    获取命令行参数的最大个数
        getconf LONG_BIT   获取系统位数

命令:cut
        cut -d, -f 1 test_file
    截取test_file文件中特定的列,
        -d    指定列分隔符
        -f    指定获取哪些列,可以指定多列(以逗号分隔),也可以指定列范围(以横杆表示)
              如果某一行没有分隔符,则不管指定获取哪些列,该行都会全部打印(除非指定了-s选项)
              如果某一行中没有指定的列(有分隔符),则该行打印空行

命令:bc            计算器
    bc命令中有四个特殊变量:
          scale         指定小数点后的位数,默认为0        
          ibase,obase   指定输入输出的进制,默认为10
          last          代表上次打印的值
    bc命令中的函数:
        length(expr)    返回expr表达式(或数字)的长度(不包括小数点)
        scale(expr)     返回expr表达式(或数字)小数点后的长度
   示例:
    echo "scale=2;2/3" |bc                返回: 0.66
    echo "scale(2.00500)" |bc             返回:5
    echo "length(2.00500)"|bc             返回:6

命令:expect            
    #!/usr/bin/expect -f
    set timeout 30                # 变量赋值
    spawn ssh root@12.33.44.55    # 执行某个命令,以便下面的expect命令等待结果
    expect "password:"            # 期望某个值的出现
    send "pppppp\r"               # 发送某个字符串
    expect "]*"
    send "ssh weiqiong@C\r"
    expect "password:"
    send "pppppp\r"
    interact                      # 可以进入交互界面
    if { $timeout == 2 } {        # if 语句,语句体的左{ 必须与if语句在同一行
    }
命令行方式:
        expect -c "set timeout 5; spawn -noecho ssh 121.10.175.10 echo; expect timeout { send_user \"\n\"; exit 1 } ; exit 0"
################
## 输入yes的expect脚本
#!/usr/bin/expect -f
set devip [lindex $argv 0]
set timeout 3
spawn ssh $devip "echo" > /dev/null
while 1 {
    expect {
        -nocase -re "(yes/no)" {
            send -- "yes\r"
            break
        }
        eof {
          break
        }
        timeout {
            exit 1
        }
    }
}

命令:perl
1,perl 超时判断
#!/usr/bin/perl
eval { # eval 相当于异常捕捉机制: eval块中的代码如有错误,或执行die语句,都会被eval捕捉,并保存在$@变量中
    local $SIG{ALRM} = sub { die "alarm" }; # 定义ALRM信号的处理函数
    alarm 2;                                  # 设置2秒超时
    `ssh 125.88.105.99 echo`;                 # 如果该命令超时,则执行$SIG{ALRM} 中定义的函数,并且退出当前eval子句
    alarm 0;        # 如果超时,则该语句不会被执行,直接执行eval块后面的语句
};
        # 如果超时,则变量$@的值为“alarm”
print "hello world";

2,perl 多线程
#!/usr/bin/perl
my $maxchild=20;
foreach $item (1..500) {
    while ( `ps -ef|grep $0|wc -l` > $maxchild) { select undef,undef,undef,0.1; };

    if ($PID=fork()){
        print "Starting Sub_ProcessPID\n";
    } else {
        print "I will handle dataitem\n";
        sleep 1;
        exit 1;
    };
}

命令:chpasswd            自动修改密码
    echo "user_name:new_passwd" | chpasswd

命令:grep         查找字符串
   选项:
        -c  计数
        -i  忽略大小写
        -n  显示行号
        -v  只显示不匹配的行
        -w  按单词搜索
   正则表达式:
        grep 中可以使用正则表达式,但不能使用\(\),\{\}
        egrep 新增正则表达式:
        +        匹配一个或多个前驱字符
        ?        匹配零个或一个前驱字符
        xxx|xxx  或
        ()       组字符

命令:sed           文本编辑
   选项:  -e   允许多次编辑
           -n   禁止默认输出
           -f   将sed命令放置到文件中,然后使用此选项导入该命令文件
           -i[subFix]   直接在文件中修改,如果指定了subFix,则同时生成后缀为subFix的备份文件。如,sed -ibak 's###g' file         

   命令:  d    删除行
           p    打印行
           r    读取一个文件的内容
           s    替换,s字符后遇到的第一个字符就是s命令的分隔符
                可以带如下标志:
                g    全局替换; p  打印行;      
           !    把命令应用到除了选出的行以外的其他所有行
   示例:
        sed -ibak '3r append.txt' file         # 读取append.
        只打印包含north的行:  sed -n '/north/p' file
        删除第3到最后一行:    sed -n '3,$d'    file                 # 如果不加-n选项的话,结果将会打印1,2两行的内容
        替换所有west为north:      sed -n 's/west/north/g'  file     # 如果不加g的话,则每行只替换第一个west
        找到某行,并替换其中的ip: sed  '/masterrelayip/s#[0-9\.]\{1,\}#$newip#' file    # $newip是一个变量
        每行最后两个数字后追加.5:  sed -n 's/[0-9][0-9]$/&.5/' file  # & 匹配前面找到的内容,可以用\&来匹配&字符
        在某一行之后添加内容:sed -i '/string_tobe_find/a\ string_tobe_appended' file
        在最后一行之后添加内容:sed -i '$ a\ string_tobe_appended' file
        在某一行之前添加内容:sed -i '/string_tobe_find/i\ string_tobe_appended' file
        寻找Hello ABC,并将ABC替换为World:
                         sed -n 's/\(Hello \)ABC/\1World/g'  file    # \1 匹配前面第一个\(\)中的内容,最多可以引用9个\(\)中的内容
        sed -ibak 's###g' file          直接在文件中修改,同时生成后缀为bak的备份文件
        sed '/SQL>/d;/^$/d; s/,/#/g; s/^[ ]*//;s/[ ]*%[ ]*/,/g' temp_mem_edsinfo.txt


命令:awk,nawk                 awk语言
   格式:  awk -F"[分隔符]" -v myvar1=$SHELL_VAR1 -v myvar2=$SHELL_VAR2 'BEGIN{} pattern {} END{}' datafile
   内置变量:
           ARGC            命令行中待处理文件的个数
           ARGIND          当前正在处理文件在命令行数组中的索引(从1开始)
           ARGV            命令行中待处理文件名的数组
           FILENAME        当前输入文件名
           FNR             当前文件的行号
           NR              当前已处理的行号,如果只处理一个文件则,NR等于FNR
           NF              当前记录域个数
           FS              输入域分隔符,默认为一个空格,可以通过-F选项指定
           OFS             输出域分隔符,默认为一个空格
           OFMT            数值输出格式(与printf中的格式一致,如:OFMT="%.2f";)
           RS              输入记录分隔符
           ORS             输出记录分隔符
           RSTART          match函数匹配的串偏移量
           RLENGTH         match函数匹配的串长度
           IGNORECASE      是否区分大小写,0表示区分;1表示不区分
   语句:
        if (条件) {}
        else if (条件) {}
        else {}
        while(条件) {}
        for (value in array){}
        for (i=0; i< 10 ;i++) {}
        循环中使用的:break    continue
        next 语句: 从输入文件中读取下一行,并从awk命令表顶部重新开始执行
        nextfile: 终止当前输入文件的处理,从下一个输入文件进行处理
        exit 语句: 终止awk程序
        delete arr[n]  删除数组的第n个元素
        delete arr     删除整个数组(有的awk不支持这种方式)
        split("",arr)  同样,也可以删除arr数组(当awk不支持delete arr时,可以使用这种方式)
        位运算:  and(v1,v2)    or(v1,v2)    lshift(val,count)    rshift(val,count)  xor(v1,v2)   compl(val)
   函数:  print    "info...."            
           printf  "格式说明符\n",变量1,变量2...                 # \n表示换行
                        格式说明符:  %c  字符; %s 字符串; %o 八进制值; %d 十进制值;%x  十六进制值;  
                                      %e  科学计数法的浮点数; %f 浮点数;  %g 自动选择%e或%f占用空间小的来显示
                        修饰符:  - 左对齐(默认右对齐)
                                  #整数在用八进制显示时有0前缀,十六进制显示时有0x前缀
                                  + 整数有符号显示(即正负号)
                                  0 显示的值用0补,而不是默认的空格
                  如: awk '{printf "%-15s,%20s", $1,$2}'    #  第一列左对齐,总宽15个字符;第二列右对齐,总宽20个字符
          var = sprintf("格式说明符\n",变量1,变量2..)       与printf类似,只是结果不是打印出来,而是可以保存到某个变量中
          sub (搜索表达式, 替换字符串 [, 目标字符串])  #  在“目标字符串”中,查找第一个“搜索表达式”,并替换为“替换字符串”
                                                       # 如果没有指定“目标字符串”,则“目标字符串”为$0
          gsub 与sub函数类似,只是会进行全局替换
          index(string, substring)        返回string字符串中substring开始的位置(从1开始计),未找到则返回0
          length(string)                  返回string字符串的长度
          substr(string, start [,length]) 返回string字符串 start开始,length长度的子字符串,如果未指定length,则返回start开始的所有字符串
          match(string, regularExpr)      在string字符串中匹配regularExpr,返回值为子字符串开始位置的索引,如果未找到,则返回0
                                          内置变量RSTART为子串的起始位置,RLENGTH未子串的长度
match($0,/[0-9\.]*/)
          split(string ,arrayName [,fieldSeparator])  返回数组长度。按照fieldSeparator来分解string字符串,结果保存到arrayName的数组中(该数组的序号从1开始计算)
                                                      默认分格符为:空
          int(expr)                       求整,直接把小数点后的内容去掉
          srand(expr)                     初始化rand()用
          rand()                          返回[0,1)之间的随机数,示例:awk -F"," 'BEGIN{srand(systime() );} {print rand();}'
          tolower(str)                    将字符串转换为小写
          toupper(str)                    将字符串转换为大写
          strtonum(str)                   将字符串转换为数字,如果字符串前为0x,则表示将十六进制字符串转换为数字
          strftime(format[,timestamp])    格式化时间,formart格式同date命令。timestamp表示自1970年1月1日以来经过的秒数,如未指定,则指当前时间。
          systime()                       返回自1970年1月1日以来经过的时间(按秒计算)
    自定义函数:
        awk '{ print "sum =",SquareSum($1,$2) }
        function SquareSum(x,y) { sum=x*x+y*y ; return sum } ' grade.txt
输出单引号
echo "a" |awk '{print "'\''" $1"'\''"}'
    echo "a" |awk '{print "\47"$1"\47"}'

grep plan * | grep name | awk -F":" '{file=$1;sub(".*name=\"","";sub("\".*",""; if (file != $0".plan"
{
    sub(".plan","",file);
    print "sed -ibak @/plan.*name/s#name=\"" $0 "\"#name=\"" file "\"#@ " file".plan";
} }' | tr '@' "'"

// 分析begin/end行的耗时,文件内容类似如下:
2012-11-01 11:00:01,187 DEBUG [T=937][com.huawei.iptv.om.app.icheck.ds.perfstat.AnalysisPerfPackage.analysisPerf() 199] entryataPackage [dn=NE=2100117, measUnitKey=。。。。
2012-11-01 11:00:01,187 DEBUG [T=937][com.huawei.iptv.om.app.icheck.ds.perfstat.AnalysisPerfPackage.analysisPerf() 222] exitataPackage [dn=NE=2100117, measUnitKey=。。。。
2012-11-01 11:00:01,187 DEBUG [T=937][com.huawei.iptv.om.app.icheck.ds.perfstat.AnalysisPerfPackage.analysisPerf() 199] entryataPackage [dn=NE=2100112, measUnitKey=。。。。
2012-11-01 11:00:01,188 DEBUG [T=937][com.huawei.iptv.om.app.icheck.ds.perfstat.AnalysisPerfPackage.analysisPerf() 222] exitataPackage [dn=NE=2100112, measUnitKey=。。。。
grep analysisPerf iptv_20121031200245427.log |awk '{print $1,$2,$6,$7}' |awk '
function time_diff(begin,end) {
    sub(",",":",begin);
    sub(",",":",end);
    split(begin,arrBegin,":";
    split(end,arrEnd,":";
    endMS = arrEnd[1] * 3600 * 1000 + arrEnd[2]*60*1000 + arrEnd[3]* 1000 + arrEnd[4] ;
    beginMS = arrBegin[1] * 3600 * 1000 + arrBegin[2]*60*1000 + arrBegin[3]* 1000 + arrBegin[4] ;
    return endMS - beginMS;
}
{
if ($3 == "exitataPackage"{
    print $3,$4,lastTime[$4], $2, time_diff(lastTime[$4],$2);
} else {
    lastTime[$4]=$2;
}
}'

命令:ps     查看某个进程的启动时间
        ps -A -ouid,pid,stime,etime,args
   输出格式:UID PID STIME ELAPSED COMMAND
          ELAPSED表示该进程从启动到当前的时间差,格式 dd-hh24:mi:ss

示例,获取mmserver进程的启动时间:

1,先获取进程运行时间,单位为秒:
elapse=$(ps -A -ouname,pid,stime,etime,args | grep mmserver | grep -v grep | awk 'NR==1{
    dd=0;time=$4;len = split($4,arr,"-";
    if (len > 1){    dd = arr[1];    time = arr[2];}
    split(time,arr,":";
    hour = arr[1];minute = arr[2];second = arr[3];
    print dd * 24 * 3600 + hour * 3600 + minute * 60 + second;
}')
2,再根据当前时间,就可以计算出该进程的启动时间了:
start_time=$(date -d "$elapse seconds ago" "+%F %X")

命令:ps 非终端登陆时,默认结果显示宽度为90,这样就导致CMD显示不全
        可以添加w选项,使得宽度增加。
        如果用ww选项,则宽度没有限制

命令:查看某个进程的线程信息: ps cu -Lp <pid>
USER       PID   LWP %CPU NLWP %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
i2kuser  24071 24071  0.0  502  7.7 6090640 1903356 ?     Sl   Aug27   0:00 java
i2kuser  24071 24072  0.0  502  7.7 6090640 1903356 ?     Sl   Aug27   0:01 java
i2kuser  24071 24073  0.0  502  7.7 6090640 1903356 ?     Sl   Aug27   0:20 java
......



命令:split   分解文件
   split -b 2m myfile                  # 将myfile文件分解为2m的大小

命令:md5sum
        md5sum file1 [file2 ...]  >  my_md5_files.md5          # 生成md5文件
        md5sum -c my_md5_files.md5                             # 校验md5文件

命令:dmidecode 识别单板
linux:/home # dmidecode | grep Product
        Product Name: Seabream
        Product Name: MLB1218   // 这是R2单板

R2PLUS-XXX:/home # dmidecode | grep Product
        Product Name: Tionesta
        Product Name: CN21HCSA  // 这是R2+单板

ATAE-QDSA:~ # dmidecode | grep Product
        Product Name: OSTA2.0
        Product Name: CN21QDSA  // 这是ATAE板载盘单板


命令:free

free -m
             total       used       free     shared    buffers     cached
Mem:          7991       7946         45          0        111       5404
-/+ buffers/cache:       2430       5560
Swap:         8197        200       7996
第一行:标题行
第二行:total (7991MB):总内存,表示物理总内存大小。
        used (7946MB):已用内存,表示总计分配给缓存(包含buffers 与cache )使用的数量,但其中可能部分缓存并未实际使用。
        free (45MB):未用内存,表示未分配的内存大小。
        shared(0):共享内存,一般系统不会用到
        buffers(111MB): 系统分配但未被使用的buffers 数量。
        cached(5404MB): 系统分配但未被使用的cache 数量
第三行:used(2430MB): 实际内存使用大小 = 第二行的(Used - buffers - cached)
       free(5560MB): 实际空闲内存大小 = 第二行的(free + buffers + cached)
第四行:total(8197MB):总交换空间大小
        used(200MB):   已经使用的交换空间大小
        free(7996MB):  未使用的交换空间大小

buffer与cache的区别:
   buffer是用来给块设备的缓存,主要记录文件系统的元数据,如目录里有什么,权限等。
   cache是用来给文件的缓存,主要记录文件的内容。


建立信任关系
假设需要在机器A中建立与机器B的信任关系,使得在机器A中不需要输入密码,就可以直接ssh到机器B:
1,在机器A中执行:“ ssh-keygen -t rsa ”(然后全部使用默认值)
   此时,将在~/.ssh/目录下生成两个文件:id_rsa;id_rsa.pub
2,将上一步生成的id_rsa.pub文件内容追加到机器B ~root/.ssh/authorized_keys文件中



/proc/sys/net/ipv4/conf/all/arp_ignore
arp_ignore - INTEGER Define different modes for sending replies in response to received ARP requests that resolve local target IP addresses: 0 - (default): reply for any local target IP address, configured on any interface
           1 - reply only if the target IP address is local address configured on the incoming interface
           2 - reply only if the target IP address is local address configured on the incoming interface and both with the sender's IP address are part from same subnet on this interface
           3 - do not reply for local addresses configured with scope host, only resolutions for global and link addresses are replied
           4-7 - reserved
           8 - do not reply for all local addresses The max value from conf/{all,interface}/arp_ignore is used when ARP request is received on the {interface}


tc命令
在bond0上配置流量整形:
tc qdisc add dev bond0 root tbf rate 2000mbit burst 2000kb limit 50mb
删除bond0上的流量整形:
tc qdisc del dev bond0 root
查询:
tc qdisc


rpm 命令

安装                 rpm -ivh  <rpm 包名>
卸载                 rpm -evh  <rpm 安装名>
查询                 rpm -q <rpm 安装名>    或者 rpm -qa 查询所有的安装包
查询包对应的安装文件  rpm -ql <rpm 安装名>

chkconfig命令
chkconfig [--add][--del][--list][系统服务] 或 chkconfig [--level <等级代号>][系统服务][on/off/reset]


curl 查看某个网址的访问时间
curl -o /dev/null -sG -w %{time_connect}:%{time_starttransfer}:%{time_total} "http://125.88.66.53/graph_view.php?action=tree&tree_id=1&leaf_id=17"
        time_connect:        建立到服务器的 TCP 连接所用的时间
        time_starttransfer:  在发出请求之后,Web 服务器返回数据的第一个字节所用的时间
        time_total:          完成请求所用的时间

ping 命令
  以指定IP去ping设备:ping -I 172.23.10.66 172.23.2.138

patch 命令
   1、生成patch文件
        diff -Nuar include/top_graph_header.php_old include/top_graph_header.php > top_graph_header4iptv.patch
   2、使用patch命令安装补丁
        

blockdev命令
  blockdev --getsize /dev/raw/raw1
  获取裸设备的大小,返回值单位:块(512Byte)

raw命令
raw -qa 查看所有裸设备的绑定号,如:
MEM2:/dev/mapper # raw -qa
/dev/raw/raw1:        bound to major 253, minor 0
/dev/raw/raw2:        bound to major 253, minor 1
/dev/raw/raw3:        bound to major 253, minor 2
然后用ls -l 命令查看逻辑卷,就可以知道逻辑卷对应哪个裸设备,如:
MEM2:/dev/mapper # ls -l oramem_dg-lv_*
brw-rw---- 1 oracle oinstall 253,  0 Oct 13 16:22 oramem_dg-lv_systemtbs
brw-rw---- 1 oracle oinstall 253,  1 Oct 13 16:22 oramem_dg-lv_sysauxtbs
brw-rw---- 1 oracle oinstall 253,  2 Oct 13 16:22 oramem_dg-lv_usertbs

根据绑定号(253,0),就可以知道逻辑卷oramem_dg-lv_systemtbs对应裸设备/dev/raw/raw1


ftp非交互方式
ftp -vni $ftp_ip << EOF > temp_ftp_file
    user $ftp_user $ftp_pwd
    cd $ftp_path
    mkdir ${db_path}
    cd ${db_path}
    binary
    put ${task_item}.tgz
    bye
EOF



pure-ftp
  pure-ftp 服务器默认IP为主机名,这样会导致客户端登陆时提示“425 Sorry, invalid address given”
  因此,需要在ftp服务器中修改一下 /etc/xinetd.d/pure-ftpd文件,修改其中的server_args配置项(增加-H参数): server_args = -H

  然后,重启ftp: /etc/init.d/xinetd restart

screen命令
  screen -ls 查看所有的session
  screen -r sessionID  attach指定的session
  screen -d sessionID  detache指定的session
  在screen窗口中的命令:
      ctrl+a d  退出窗口(screen继续运行)
      exit      退出screen


strace
使用strace跟踪进程执行和文件写相关的系统调用
strace -e trace=file,write,writev,fcntl,lseek,pwrite,writev, -f -p <pid>

iostat

Device:            tps   Blk_read/s   Blk_wrtn/s   Blk_read   Blk_wrtn
sda               0.58         9.95        37.47    6737006   25377400
tps :每秒进程下发的IO读、写请求数量
Blk_read/s: 每秒读扇区数量(一扇区为512bytes)

更详细的io统计信息(-x选项) :  iostat -x -k -d 1
Device:         rrqm/s   wrqm/s     r/s     w/s    rkB/s    wkB/s avgrq-sz avgqu-sz   await  svctm  %util
sda               0.00  9915.00    1.00   90.00     4.00 34360.00   755.25    11.79  120.57   6.33  57.60
rrqm/s: 每秒对该设备的读请求被合并次数,文件系统会对读取同块(block)的请求进行合并
wrqm/s: 每秒对该设备的写请求被合并次数
r/s: 每秒完成的读次数
w/s: 每秒完成的写次数
rkB/s: 每秒读数据量(kB为单位)
wkB/s: 每秒写数据量(kB为单位)
avgrq-sz:平均每次IO操作的数据量(扇区数为单位)
avgqu-sz: 平均等待处理的IO请求队列长度
await: 平均每次IO请求等待时间(包括等待时间和处理时间,毫秒为单位)
svctm: 平均每次IO请求的处理时间(毫秒为单位)
%util: 采用周期内用于IO操作的时间比率,即IO队列非空的时间比率,util = (r/s+w/s) * (svctm/1000)

pidstat
cpu使用情况统计(-u)
使用-u选项,pidstat将显示各活动进程的cpu使用统计,执行"pidstat -u”与单独执行"pidstat”的效果一样。

内存使用情况统计(-r)
pidstat -r -p 13084 1
15:08:18          PID  minflt/s  majflt/s     VSZ    RSS   %MEM  Command
15:08:19        13084 133835.00      0.00 15720284 15716896  96.26  mmmm
•minflt/s: 每秒次缺页错误次数(minor page faults),次缺页错误次数意即虚拟内存地址映射成物理内存地址产生的page fault次数
•majflt/s: 每秒主缺页错误次数(major page faults),当虚拟内存地址映射成物理内存地址时,相应的page在swap中,这样的page fault为major page fault,一般在内存使用紧张时产生
•VSZ: 该进程使用的虚拟内存(以kB为单位)
•RSS: 该进程使用的物理内存(以kB为单位)
•%MEM: 该进程使用内存的百分比
•Command: 拉起进程对应的命令


netstat -nap  命令
显示数据类似如下:
Proto Recv-Q Send-Q Local Address           Foreign Address         State       PID/Program name
tcp        0      0 10.137.13.121:35765     0.0.0.0:*               LISTEN      21914/java

主要字段解释:
Recv-Q      数据已经在本地(LocalAddress)接收缓冲,但是还没有recv().
Send-Q      对方(Foreign Address)没有收到的数据或者说没有Ack的,还是本地缓冲区.

CLOSE_WAIT

    对方主动关闭连接或者网络异常导致连接中断,这时我方的状态会变成CLOSE_WAIT 此时我方要调用close()来使得连接正确关闭

TIME_WAIT

    我方主动调用close()断开连接,收到对方确认后状态变为TIME_WAIT。TCP协议规定TIME_WAIT状态会一直持续2MSL(即两倍的分段最大生存期),以此来确保旧的连接状态不会对新连接产生影响。处于TIME_WAIT状态的连接占用的资源不会被内核释放,所以作为服务器,在可能的情况下,尽量不要主动断开连接,以减少TIME_WAIT状态造成的资源浪费。

    目前有一种避免TIME_WAIT资源浪费的方法,就是关闭socket的LINGER选项。但这种做法是TCP协议不推荐使用的,在某些情况下这个操作可能会带来错误。

/proc/sys/net/ipv4/tcp_fin_timeout
如 果套接字由本端要求关闭,这个参数决定了它保持在FIN-WAIT-2 状态的时间。对端可以出错并永远不关闭连接,甚至意外当机。缺省值是60 秒。2.2 内核的通常值是180 秒,你可以按这个设置,但要记住的是,即使你的机器是一个轻载的WEB 服务器,也有因为大量的死套接字而内存溢出的风险,FIN- WAIT-2 的危险性比FIN-WAIT-1 要小,因为它最多只能吃掉1.5K 内存,但是它们的生存期长些。参见tcp_max_orphans



/proc/sys/net/ipv4/tcp_keepalive_time
当keepalive 起用的时候,TCP 发送keepalive 消息的频度。缺省是2 小时。
/proc/sys/net/ipv4/tcp_keepalive_intvl
当探测没有确认时,重新发送探测的频度。缺省是75 秒。
/proc/sys/net/ipv4/tcp_keepalive_probes
在认定连接失效之前,发送多少个TCP 的keepalive 探测包。缺省值是9 。这个值乘以tcp_keepalive_intvl 之后决定了,一个连接发送了keepalive 之后可以有多少时间没有回应。




dd 命令

模拟一个15G(30000000*512Byte)的文件(zcj_test):  dd if=/dev/zero of=zcj_test count=30000000

论坛徽章:
3
天秤座
日期:2013-12-27 13:44:58射手座
日期:2014-05-22 16:52:43天蝎座
日期:2014-08-13 16:03:21
37 [报告]
发表于 2014-05-24 00:08 |只看该作者
系统运行状况相关的Shell命令:  1.  Linux的实时监测命令(watch):
    watch 是一个非常实用的命令,可以帮你实时监测一个命令的运行结果,省得一遍又一遍的手动运行。该命令最为常用的两个选项是-d和-n,其中-n表示间隔多少秒 执行一次"command",-d表示高亮发生变化的位置。下面列举几个在watch中常用的实时监视命令:
    /> watch -d -n 1 'who'   #每隔一秒执行一次who命令,以监视服务器当前用户登录的状况
    Every 1.0s: who       Sat Nov 12 12:37:18 2011
   
    stephen  tty1           2011-11-11 17:38 (:0)
    stephen  pts/0         2011-11-11 17:39 (:0.0)
    root       pts/1         2011-11-12 10:01 (192.168.149.1)
    root       pts/2         2011-11-12 11:41 (192.168.149.1)
    root       pts/3         2011-11-12 12:11 (192.168.149.1)
    stephen  pts/4         2011-11-12 12:22 (:0.0)
    此时通过其他Linux客户端工具以root的身份登录当前Linux服务器,再观察watch命令的运行变化。
    Every 1.0s: who       Sat Nov 12 12:41:09 2011
   
    stephen  tty1          2011-11-11 17:38 (:0)
    stephen  pts/0        2011-11-11 17:39 (:0.0)
    root       pts/1        2011-11-12 10:01 (192.168.149.1)
    root       pts/2        2011-11-12 11:41 (192.168.149.1)
    root       pts/3        2011-11-12 12:40 (192.168.149.1)
    stephen  pts/4        2011-11-12 12:22 (:0.0)
    root       pts/5        2011-11-12 12:41 (192.168.149.1)
    最后一行中被高亮的用户为新登录的root用户。此时按CTRL + C可以退出正在执行的watch监控进程。
   
    #watch可以同时运行多个命令,命令间用分号分隔。
    #以下命令监控磁盘的使用状况,以及当前目录下文件的变化状况,包括文件的新增、删除和文件修改日期的更新等。
    /> watch -d -n 1 'df -h; ls -l'
    Every 1.0s: df -h; ls -l     Sat Nov 12 12:55:00 2011
   
    Filesystem            Size  Used Avail Use% Mounted on
    /dev/sda1             5.8G  3.3G  2.2G  61% /
    tmpfs                 504M  420K  504M   1% /dev/shm
    total 20
    -rw-r--r--. 1 root root 10530 Nov 11 23:08 test.tar.bz2
    -rw-r--r--. 1 root root   183 Nov 11 08:02 users
    -rw-r--r--. 1 root root   279 Nov 11 08:45 users2
    此时通过另一个Linux控制台窗口,在watch监视的目录下,如/home/stephen/test,执行下面的命令
    /> touch aa         #在执行该命令之后,另一个执行watch命令的控制台将有如下变化
    Every 1.0s: df -h; ls -l                                Sat Nov 12 12:57:08 2011
   
    Filesystem            Size  Used Avail Use% Mounted on
    /dev/sda1             5.8G  3.3G  2.2G  61% /
    tmpfs                 504M  420K  504M   1% /dev/shm
    total 20
    -rw-r--r--. 1 root root        0 Nov 12 12:56 aa
    -rw-r--r--. 1 root root        0 Nov 12 10:02 datafile3
    -rw-r--r--. 1 root root 10530 Nov 11 23:08 test.tar.bz2
    -rw-r--r--. 1 root root     183 Nov 11 08:02 users
    -rw-r--r--. 1 root root     279 Nov 11 08:45 users2
    其中黄色高亮的部分,为touch aa命令执行之后watch输出的高亮变化部分。
   
    2.  查看当前系统内存使用状况(free):
    free命令有以下几个常用选项:

选项 说明
-b 以字节为单位显示数据。
-k 以千字节(KB)为单位显示数据(缺省值)。
-m 以兆(MB)为单位显示数据。
-s delay 该选项将使free持续不断的刷新,每次刷新之间的间隔为delay指定的秒数,如果含有小数点,将精确到毫秒,如0.5为500毫秒,1为一秒。

    free命令输出的表格中包含以下几列:

列名 说明
total 总计物理内存的大小。
used 已使用的内存数量。
free 可用的内存数量。
Shared 多个进程共享的内存总额。
Buffers/cached 磁盘缓存的大小。


    见以下具体示例和输出说明:
    /> free -k
                        total         used          free     shared    buffers     cached
    Mem:       1031320     671776     359544          0      88796     352564
    -/+ buffers/cache:      230416     800904
    Swap:        204792              0     204792
    对于free命令的输出,我们只需关注红色高亮的输出行和绿色高亮的输出行,见如下具体解释:
    红色输出行:该行是从操作系统的角度来看待输出数据的,used(671776)表示内核(Kernel)+Applications+buffers+cached。free(359544)表示系统还有多少内存可供使用。
    绿色输出行:该行则是从应用程序的角度来看输出数据的。其free = 操作系统used + buffers + cached,既:
    800904 = 359544 + 88796 + 352564
    /> free -m
                      total        used        free      shared    buffers     cached
    Mem:          1007         656        351            0         86            344
    -/+ buffers/cache:        225        782
    Swap:          199             0        199
    /> free -k -s 1.5  #以千字节(KB)为单位显示数据,同时每隔1.5刷新输出一次,直到按CTRL+C退出
                      total        used       free     shared    buffers     cached
    Mem:          1007         655        351          0           86        344
    -/+ buffers/cache:        224        782
    Swap:          199             0        199

                      total        used       free     shared    buffers     cached
    Mem:          1007         655        351          0           86        344
    -/+ buffers/cache:        224        782
    Swap:          199             0        199

    3.  CPU的实时监控工具(mpstat):
    该命令主要用于报告当前系统中所有CPU的实时运行状况。
    #该命令将每隔2秒输出一次CPU的当前运行状况信息,一共输出5次,如果没有第二个数字参数,mpstat将每隔两秒执行一次,直到按CTRL+C退出。
    /> mpstat 2 5  
    Linux 2.6.32-71.el6.i686 (Stephen-PC)   11/12/2011      _i686_  (1 CPU)

    04:03:00 PM  CPU    %usr   %nice    %sys %iowait    %irq   %soft  %steal  %guest   %idle
    04:03:02 PM  all    0.00    0.00    0.50    0.00    0.00    0.00    0.00    0.00   99.50
    04:03:04 PM  all    0.00    0.00    0.00    0.00    0.00    0.00    0.00    0.00  100.00
    04:03:06 PM  all    0.00    0.00    0.00    0.00    0.00    0.00    0.00    0.00  100.00
    04:03:08 PM  all    0.00    0.00    0.00    0.00    0.00    0.00    0.00    0.00  100.00
    04:03:10 PM  all    0.00    0.00    0.00    0.00    0.00    0.00    0.00    0.00  100.00
    Average:       all    0.00    0.00    0.10    0.00    0.00    0.00    0.00    0.00   99.90

    第一行的末尾给出了当前系统中CPU的数量。后面的表格中则输出了系统当前CPU的使用状况,以下为每列的含义:

列名 说明
%user 在internal时间段里,用户态的CPU时间(%),不包含nice值为负进程  (usr/total)*100
%nice 在internal时间段里,nice值为负进程的CPU时间(%)   (nice/total)*100
%sys 在internal时间段里,内核时间(%)       (system/total)*100
%iowait 在internal时间段里,硬盘IO等待时间(%) (iowait/total)*100
%irq 在internal时间段里,硬中断时间(%)     (irq/total)*100
%soft 在internal时间段里,软中断时间(%)     (softirq/total)*100
%idle 在internal时间段里,CPU除去等待磁盘IO操作外的因为任何原因而空闲的时间闲置时间(%) (idle/total)*100

    计算公式:
    total_cur=user+system+nice+idle+iowait+irq+softirq
    total_pre=pre_user+ pre_system+ pre_nice+ pre_idle+ pre_iowait+ pre_irq+ pre_softirq
    user=user_cur – user_pre
    total=total_cur-total_pre
    其中_cur 表示当前值,_pre表示interval时间前的值。上表中的所有值可取到两位小数点。   

    /> mpstat -P ALL 2 3  #-P ALL表示打印所有CPU的数据,这里也可以打印指定编号的CPU数据,如-P 0(CPU的编号是0开始的)
    Linux 2.6.32-71.el6.i686 (Stephen-PC)   11/12/2011      _i686_  (1 CPU)

    04:12:54 PM  CPU    %usr   %nice    %sys %iowait    %irq   %soft  %steal  %guest   %idle
    04:12:56 PM    all      0.00      0.00     0.50    0.00      0.00    0.00    0.00      0.00     99.50
    04:12:56 PM      0     0.00      0.00     0.50    0.00      0.00    0.00    0.00      0.00     99.50

    04:12:56 PM  CPU    %usr   %nice    %sys %iowait    %irq   %soft  %steal  %guest   %idle
    04:12:58 PM    all     0.00      0.00     0.00    0.00      0.00    0.00    0.00      0.00    100.00
    04:12:58 PM     0     0.00      0.00     0.00    0.00      0.00    0.00    0.00      0.00    100.00

    04:12:58 PM  CPU    %usr   %nice    %sys %iowait    %irq   %soft  %steal  %guest   %idle
    04:13:00 PM    all      0.00     0.00    0.00    0.00      0.00    0.00     0.00      0.00    100.00
    04:13:00 PM     0      0.00     0.00    0.00    0.00      0.00    0.00     0.00      0.00    100.00

    Average:       CPU    %usr   %nice    %sys %iowait    %irq   %soft  %steal  %guest   %idle
    Average:         all      0.00     0.00    0.17    0.00      0.00    0.00     0.00      0.00     99.83
    Average:          0      0.00     0.00    0.17    0.00      0.00    0.00     0.00      0.00     99.83

    4.  虚拟内存的实时监控工具(vmstat):
    vmstat命令用来获得UNIX系统有关进程、虚存、页面交换空间及CPU活动的信息。这些信息反映了系统的负载情况。vmstat首次运行时显示自系统启动开始的各项统计信息,之后运行vmstat将显示自上次运行该命令以后的统计信息。用户可以通过指定统计的次数和时间来获得所需的统计信息。
    /> vmstat 1 3    #这是vmstat最为常用的方式,其含义为每隔1秒输出一条,一共输出3条后程序退出。
    procs  -----------memory----------   ---swap-- -----io---- --system-- -----cpu-----
     r  b   swpd      free      buff   cache   si   so     bi    bo     in   cs  us  sy id  wa st
     0  0        0 531760  67284 231212  108  0     0  260   111  148  1   5 86   8  0
     0  0        0 531752  67284 231212    0    0     0     0     33   57   0   1 99   0  0
     0  0        0 531752  67284 231212    0    0     0     0     40   73   0   0 100 0  0

    /> vmstat 1       #其含义为每隔1秒输出一条,直到按CTRL+C后退出。

    下面将给出输出表格中每一列的含义说明:
    有关进程的信息有:(procs)
    r:  在就绪状态等待的进程数。
    b: 在等待状态等待的进程数。   
    有关内存的信息有:(memory)
    swpd:  正在使用的swap大小,单位为KB。
    free:    空闲的内存空间。
    buff:    已使用的buff大小,对块设备的读写进行缓冲。
    cache: 已使用的cache大小,文件系统的cache。
    有关页面交换空间的信息有:(swap)
    si:  交换内存使用,由磁盘调入内存。
    so: 交换内存使用,由内存调入磁盘。  
    有关IO块设备的信息有:(io)
    bi:  从块设备读入的数据总量(读磁盘) (KB/s)
    bo: 写入到块设备的数据总理(写磁盘) (KB/s)   
    有关故障的信息有:(system)
    in: 在指定时间内的每秒中断次数。
    sy: 在指定时间内每秒系统调用次数。
    cs: 在指定时间内每秒上下文切换的次数。   
    有关CPU的信息有:(cpu)
    us:  在指定时间间隔内CPU在用户态的利用率。
    sy:  在指定时间间隔内CPU在核心态的利用率。
    id:  在指定时间间隔内CPU空闲时间比。
    wa: 在指定时间间隔内CPU因为等待I/O而空闲的时间比。   
    vmstat 可以用来确定一个系统的工作是受限于CPU还是受限于内存:如果CPU的sy和us值相加的百分比接近100%,或者运行队列(r)中等待的进程数总是不等于0,且经常大于4,同时id也经常小于40,则该系统受限于CPU;如果bi、bo的值总是不等于0,则该系统受限于内存。

    5.  设备IO负载的实时监控工具(iostat):
    iostat主要用于监控系统设备的IO负载情况,iostat首次运行时显示自系统启动开始的各项统计信息,之后运行iostat将显示自上次运行该命令以后的统计信息。用户可以通过指定统计的次数和时间来获得所需的统计信息。
    其中该命令中最为常用的使用方式如下:
    /> iostat -d 1 3    #仅显示设备的IO负载,其中每隔1秒刷新并输出结果一次,输出3次后iostat退出。
    Linux 2.6.32-71.el6.i686 (Stephen-PC)   11/16/2011      _i686_  (1 CPU)

    Device:            tps   Blk_read/s   Blk_wrtn/s   Blk_read   Blk_wrtn
    sda                 5.35       258.39        26.19     538210      54560

    Device:            tps   Blk_read/s   Blk_wrtn/s   Blk_read   Blk_wrtn
    sda                 0.00         0.00         0.00                  0          0

    Device:            tps   Blk_read/s   Blk_wrtn/s   Blk_read   Blk_wrtn
    sda                 0.00         0.00         0.00                  0          0

    Device:            tps   Blk_read/s   Blk_wrtn/s   Blk_read   Blk_wrtn
    sda                 0.00         0.00         0.00                  0          0
    /> iostat -d 1  #和上面的命令一样,也是每隔1秒刷新并输出一次,但是该命令将一直输出,直到按CTRL+C退出。
    下面将给出输出表格中每列的含义:

列名 说明
Blk_read/s 每秒块(扇区)读取的数量。
Blk_wrtn/s 每秒块(扇区)写入的数量。
Blk_read 总共块(扇区)读取的数量。
Blk_wrtn 总共块(扇区)写入的数量。

    iostat还有一个比较常用的选项-x,该选项将用于显示和io相关的扩展数据。
    /> iostat -dx 1 3
    Device:  rrqm/s wrqm/s  r/s   w/s  rsec/s wsec/s avgrq-sz avgqu-sz   await  svctm  %util
    sda            5.27   1.31 2.82 1.14 189.49  19.50    52.75     0.53     133.04  10.74   4.26

    Device:  rrqm/s wrqm/s  r/s   w/s  rsec/s wsec/s avgrq-sz avgqu-sz   await  svctm  %util
    sda            0.00   0.00 0.00 0.00   0.00   0.00        0.00     0.00         0.00   0.00   0.00

    Device:  rrqm/s wrqm/s  r/s   w/s  rsec/s wsec/s avgrq-sz avgqu-sz   await  svctm  %util
    sda            0.00   0.00 0.00 0.00   0.00   0.00        0.00     0.00         0.00   0.00   0.00
    还可以在命令行参数中指定要监控的设备名,如:
    /> iostat -dx sda 1 3   #指定监控的设备名称为sda,该命令的输出结果和上面命令完全相同。

    下面给出扩展选项输出的表格中每列的含义:

列名 说明
rrqm/s 队列中每秒钟合并的读请求数量
wrqm/s 队列中每秒钟合并的写请求数量
r/s 每秒钟完成的读请求数量
w/s 每秒钟完成的写请求数量
rsec/s 每秒钟读取的扇区数量
wsec/s 每秒钟写入的扇区数量
avgrq-sz 平均请求扇区的大小
avgqu-sz 平均请求队列的长度
await 平均每次请求的等待时间
util 设备的利用率

    下面是关键列的解释:
    util是设备的利用率。如果它接近100%,通常说明设备能力趋于饱和。
    await是平均每次请求的等待时间。这个时间包括了队列时间和服务时间,也就是说,一般情况下,await大于svctm,它们的差值越小,则说明队列时间越短,反之差值越大,队列时间越长,说明系统出了问题。
    avgqu-sz是平均请求队列的长度。毫无疑问,队列长度越短越好。                 

     6.  当前运行进程的实时监控工具(pidstat):
     pidstat主要用于监控全部或指定进程占用系统资源的情况,如CPU,内存、设备IO、任务切换、线程等。pidstat首次运行时显示自系统启动开始的各项统计信息,之后运行pidstat将显示自上次运行该命令以后的统计信息。用户可以通过指定统计的次数和时间来获得所需的统计信息。
    在正常的使用,通常都是通过在命令行选项中指定待监控的pid,之后再通过其他具体的参数来监控与该pid相关系统资源信息。

选项 说明
-l 显示该进程和CPU相关的信息(command列中可以显示命令的完整路径名和命令的参数)。
-d 显示该进程和设备IO相关的信息。
-r 显示该进程和内存相关的信息。
-w 显示该进程和任务时间片切换相关的信息。
-t 显示在该进程内正在运行的线程相关的信息。
-p 后面紧跟着带监控的进程id或ALL(表示所有进程),如不指定该选项,将监控当前系统正在运行的所有进程。

    #监控pid为1(init)的进程的CPU资源使用情况,其中每隔2秒刷新并输出一次,3次后程序退出。
    /> pidstat -p 1 2 3 -l
    07:18:58 AM       PID    %usr %system  %guest    %CPU   CPU  Command
    07:18:59 AM         1    0.00    0.00    0.00    0.00     0  /sbin/init
    07:19:00 AM         1    0.00    0.00    0.00    0.00     0  /sbin/init
    07:19:01 AM         1    0.00    0.00    0.00    0.00     0  /sbin/init
    Average:               1    0.00    0.00    0.00    0.00     -  /sbin/init
    %usr:      该进程在用户态的CPU使用率。
    %system:该进程在内核态(系统级)的CPU使用率。
    %CPU:     该进程的总CPU使用率,如果在SMP环境下,该值将除以CPU的数量,以表示每CPU的数据。
    CPU:         该进程所依附的CPU编号(0表示第一个CPU)。

    #监控pid为1(init)的进程的设备IO资源负载情况,其中每隔2秒刷新并输出一次,3次后程序退出。
    /> pidstat -p 1 2 3 -d   
    07:24:49 AM       PID   kB_rd/s   kB_wr/s kB_ccwr/s  Command
    07:24:51 AM         1      0.00      0.00      0.00  init
    07:24:53 AM         1      0.00      0.00      0.00  init
    07:24:55 AM         1      0.00      0.00      0.00  init
    Average:               1      0.00      0.00      0.00  init
    kB_rd/s:   该进程每秒的字节读取数量(KB)。
    kB_wr/s:   该进程每秒的字节写出数量(KB)。
    kB_ccwr/s: 该进程每秒取消磁盘写入的数量(KB)。

    #监控pid为1(init)的进程的内存使用情况,其中每隔2秒刷新并输出一次,3次后程序退出。
    /> pidstat -p 1 2 3 -r
    07:29:56 AM       PID  minflt/s  majflt/s     VSZ    RSS   %MEM  Command
    07:29:58 AM         1      0.00      0.00    2828   1368   0.13  init
    07:30:00 AM         1      0.00      0.00    2828   1368   0.13  init
    07:30:02 AM         1      0.00      0.00    2828   1368   0.13  init
    Average:               1      0.00      0.00    2828   1368   0.13  init
    %MEM:  该进程的内存使用百分比。

    #监控pid为1(init)的进程任务切换情况,其中每隔2秒刷新并输出一次,3次后程序退出。
    /> pidstat -p 1 2 3 -w
    07:32:15 AM       PID   cswch/s nvcswch/s  Command
    07:32:17 AM         1      0.00      0.00  init
    07:32:19 AM         1      0.00      0.00  init
    07:32:21 AM         1      0.00      0.00  init
    Average:            1      0.00      0.00  init
    cswch/s:    每秒任务主动(自愿的)切换上下文的次数。主动切换是指当某一任务处于阻塞等待时,将主动让出自己的CPU资源。
    nvcswch/s: 每秒任务被动(不自愿的)切换上下文的次数。被动切换是指CPU分配给某一任务的时间片已经用完,因此将强迫该进程让出CPU的执行权。

    #监控pid为1(init)的进程及其内部线程的内存(r选项)使用情况,其中每隔2秒刷新并输出一次,3次后程序退出。需要说明的是,如果-t选项后面不加任何其他选项,缺省监控的为CPU资源。结果中黄色高亮的部分表示进程和其内部线程是树状结构的显示方式。
    /> pidstat -p 1 2 3 -tr
    Linux 2.6.32-71.el6.i686 (Stephen-PC)   11/16/2011      _i686_  (1 CPU)

    07:37:04 AM      TGID       TID  minflt/s  majflt/s     VSZ    RSS   %MEM  Command
    07:37:06 AM         1         -      0.00      0.00        2828   1368      0.13  init
    07:37:06 AM         -         1      0.00      0.00        2828   1368      0.13  |__init

    07:37:06 AM      TGID       TID  minflt/s  majflt/s     VSZ    RSS   %MEM  Command
    07:37:08 AM         1         -      0.00      0.00        2828   1368      0.13  init
    07:37:08 AM         -         1      0.00      0.00        2828   1368      0.13  |__init

    07:37:08 AM      TGID       TID  minflt/s  majflt/s     VSZ    RSS   %MEM  Command
    07:37:10 AM         1         -      0.00      0.00        2828   1368      0.13  init
    07:37:10 AM         -         1      0.00      0.00        2828   1368      0.13  |__init

    Average:         TGID       TID  minflt/s  majflt/s     VSZ    RSS   %MEM  Command
    Average:            1         -      0.00      0.00        2828   1368      0.13  init
    Average:            -         1      0.00      0.00        2828   1368      0.13  |__init
    TGID: 线程组ID。
    TID: 线程ID。  

    以上监控不同资源的选项可以同时存在,这样就将在一次输出中输出多种资源的使用情况,如:pidstat -p 1 -dr。

    7.  报告磁盘空间使用状况(df):
    该命令最为常用的选项就是-h,该选项将智能的输出数据单位,以便使输出的结果更具可读性。
    /> df -h
    Filesystem             Size  Used   Avail Use% Mounted on
    /dev/sda1             5.8G  3.3G  2.2G  61%   /
    tmpfs                  504M  260K  504M   1%  /dev/shm

    8.  评估磁盘的使用状况(du):

选项 说明
-a 包括了所有的文件,而不只是目录。
-b 以字节为计算单位。
-k 以千字节(KB)为计算单位。
-m 以兆字节(MB)为计算单位。
-h 使输出的信息更易于阅读。
-s 只显示工作目录所占总空间。
--exclude=PATTERN 排除掉符合样式的文件,Pattern就是普通的Shell样式,?表示任何一个字符,*表示任意多个字符。
--max-depth=N 从当前目录算起,目录深度大于N的子目录将不被计算,该选项不能和s选项同时存在。



    #仅显示子一级目录的信息。
    /> du --max-depth=1 -h
    246M    ./stephen
    246M    .   
    /> du -sh ./*   #获取当前目录下所有子目录所占用的磁盘空间大小。
    352K    ./MemcachedTest
    132K    ./Test
    33M     ./thirdparty   
    #在当前目录下,排除目录名模式为Te*的子目录(./Test),输出其他子目录占用的磁盘空间大小。
    /> du --exclude=Te* -sh ./*  
    352K    ./MemcachedTest
    33M     ./thirdparty

论坛徽章:
3
天秤座
日期:2013-12-27 13:44:58射手座
日期:2014-05-22 16:52:43天蝎座
日期:2014-08-13 16:03:21
38 [报告]
发表于 2014-05-24 00:10 |只看该作者
Linux Shell 命令行编辑  
前言
快速编辑 *nux 的初学者说最烦就是 Shell 的快捷键,也许这样再看全文会更有趣。

其实,命令行适应了,可能比图形界面更有效率。至少对我来说是这样,我现在一看见那些所谓的“慢 Linux /Unix 这类从内核得到整体架构,再到哪怕是最小的一个应用小软件都以文本来支撑的系统,没有娴熟的命令行技巧确实是玩不转的。希望本文能对你提高命令行使用效率有帮助。

但是由于Shell 的主流版本也有好几个,所以,本文所说的内容,可能和你的系统有出入,但是思想是一样的,在你自己的平台上摸索一下,你也会找到你的平台太下编辑命令行的技巧和规律。

另外, VIM, Emacs 的快捷键是相通的,所以,熟练使用 *nux 下的其他软件有很好的启示作用。

命令行的技巧除了本文提到的,还有很多,你可以自己慢慢积累,收集和体会。当然如果你经常需要输入很繁琐的命令,那么建议你自己写 function, alias 等技巧来实现。

我目前使用的系统配置

内核: Gentoo Linux -- 2005.1;
Shell 版本: Gnome -- 2.10.1; gnome-terminal -- 2.10.0;

现在就开始吧

一、自动补齐:
这个技巧很多人都应该会了,就是当输入命令,目录或者是文件名的时候按 charactor ,再按
按[Ctrl + r], [Ctrl + p], [Ctrl + n]
[Ctrl] 键的同时(reverse-i-search), 此时你尝试一下输入你以前输入过的命令,当你每输入一个字符的时候,终端都会滚动显示你的历史命令。当显示到你想找的合适的历史命令的时候,直接 [Ctrl + p] 或[Ctrl + r ] (接着输入[Ctrl + c]
Unix 初学者会习惯性地按

四、光标跳转快捷键:
为了方便大家记忆,加点英语助记语在后面
[Ctrl+ w] 向后删除一个字,用来对付刚刚输入的错误字很有用
[Ctrl+ l] 刷新屏幕(stty:终端相关命令)
[Ctrl+ u] 从光标当前位置删除所有字符至行首
[Ctrl+ k] 从光标当前位置删除所有字符至行尾
[Ctrl+ d] 删除光标当前位置的字符
[Ctrl+ y] 粘贴最后一个被删除的字

[Alt + l] lower case (current word)
[Alt+ u] upper case (current word)
[Alt+ d] 删除从光标当前位置,到当前字的结尾字符

六、配置提示;
如果你是用 gnome-teminal ,上面的 Gnome 的窗口快捷键有冲突。

那么你需要做如下配置:

在 "Edit" -] "Keyboard Shortcuts ..."打开 KDE 下应该怎么配 KDE 的朋友补充一下,我很久没用
2~echo
$echo "hello, world." [Enter]

我们先输入 [Ctrl + r]
我们试试找出历史命令[e],[c],[h]这三个键,这个历史命令大概已经找到了,[Enter]就会再一次执行这个命令,但我们现在来练习一下命令行的编辑。[Ctrl+ a]
echo "hello,world.",并且将光标定位到行首,此时,光标应该在 e 字符上高亮。
第四步: echo, 并且光标仍然在行首,终端显示为:

$ "hello,world."

"printf"

我们尝试一下用 printf 来替代 echo,输入 f 字符后面高亮。[Ctrl+ e]
光标跳转到命令行尾部。[Ctrl+ b]
光标后退一个字符,此时光标应处于后双引号 "\n"
[\][n] ,此时的终端显示应该为:

$ printf"hello, world.\n"

可以


KeyFunction
Ctrl-c         Kill foreground process
Ctrl-z          Suspend foreground process
Ctrl-d         Terminate input, or exitshell
Ctrl-s          Suspend output
Ctrl-q         Resume output
Ctrl-o         Discard output
Ctrl-l          Clearscreen
控制字符都是可以用(stty命令)更改的。
可以用stty -a看看终端配置。
每个程序员都应该知道的8个Linux命令
每个程序员,在职业生涯的某个时刻,总会发现自己需要知道一些Linux方面的知识。我并不是说你应该成为一个Linux专家,我的意思是,当面对linux命令行任务时,你应该能很熟练的完成。事实上,学会了下面8个命令,我基本上能完成任何需要完成的任务。

注意:下面的每个命令都有十分丰富的文档说明。这篇文章并不是来详尽的展示每个命令的各种功用的。我在这里要讲的是这几个最常用的命令的最常见用法。如果你对linux命令并不是很了解,你想找一些这方面的资料学习,那这篇文章将会给你一个基本的指导。



让我们从处理一些数据开始。假设我们有两个文件,分别记录的订单清单和订单处理结果。

123456789 order.out.log  8:22:19 111, 1, Patterns of Enterprise Architecture, Kindle edition, 39.99  8:23:45 112, 1, Joy of Clojure, Hardcover, 29.99  8:24:19 113, -1, Patterns of Enterprise Architecture, Kindle edition, 39.99  order.in.log  8:22:20 111, Order Complete  8:23:50 112, Order sent to fulfillment  8:24:20 113, Refund sent to processing


cat

cat – 连接文件,并输出结果

cat 命令非常的简单,你从下面的例子可以看到。

1234 jfields$ cat order.out.log 8:22:19 111, 1, Patterns of Enterprise Architecture, Kindle edition, 39.998:23:45 112, 1, Joy of Clojure, Hardcover, 29.998:24:19 113, -1, Patterns of Enterprise Architecture, Kindle edition, 39.99
就像它的说明描述的,你可以用它来连接多个文件。

1234567 jfields$ cat order.* 8:22:20 111, Order Complete8:23:50 112, Order sent to fulfillment8:24:20 113, Refund sent to processing8:22:19 111, 1, Patterns of Enterprise Architecture, Kindle edition, 39.998:23:45 112, 1, Joy of Clojure, Hardcover, 29.998:24:19 113, -1, Patterns of Enterprise Architecture, Kindle edition, 39.99
如果你想看这些log文件的内容,你可以把它们连接起来并输出到标准输出上,就是上面的例子展示的。这很有用,但输出的内容可以更有逻辑些。



sort

sort – 文件里的文字按行排序

此时sort命令显然是你最佳的选择。

1234567 jfields$ cat order.* | sort8:22:19 111, 1, Patterns of Enterprise Architecture, Kindle edition, 39.998:22:20 111, Order Complete8:23:45 112, 1, Joy of Clojure, Hardcover, 29.998:23:50 112, Order sent to fulfillment8:24:19 113, -1, Patterns of Enterprise Architecture, Kindle edition, 39.998:24:20 113, Refund sent to processing
就像上面例子显示的,文件里的数据已经经过排序。对于一些小文件,你可以读取整个文件来处理它们,然而,真正的log文件通常有大量的内容,你不能不考虑这个情况。此时你应该考虑过滤出某些内容,把cat、sort后的内容通过管道传递给过滤工具。



grep

grep, egrep, fgrep – 打印出匹配条件的文字行

假设我们只对Patterns of Enterprise Architecture这本书的订单感兴趣。使用grep,我们能限制只输出含有Patterns字符的订单。

123 jfields$ cat order.* | sort | grep Patterns8:22:19 111, 1, Patterns of Enterprise Architecture, Kindle edition, 39.998:24:19 113, -1, Patterns of Enterprise Architecture, Kindle edition, 39.99
假设退款订单113出了一些问题,你希望查看所有相关订单——你又需要使用grep了。

123 jfields$ cat order.* | sort | grep ":\d\d 113, "8:24:19 113, -1, Patterns of Enterprise Architecture, Kindle edition, 39.998:24:20 113, Refund sent to processing
你会发现在grep上的匹配模式除了“113”外还有一些其它的东西。这是因为113还可以匹配上书目或价格,加上额外的字符后,我们可以精确的搜索到我们想要的东西。

现在我们已经知道了退货的详细信息,我们还想知道日销售和退款总额。但我们只关心Patterns of Enterprise Architecture这本书的信息,而且只关心数量和价格。我现在要做到是切除我们不关心的任何信息。



cut

cut – 删除文件中字符行上的某些区域

又要使用grep,我们用grep过滤出我们想要的行。有了我们想要的行信息,我们就可以把它们切成小段,删除不需要的部分数据。

1234567 jfields$ cat order.* | sort | grep Patterns8:22:19 111, 1, Patterns of Enterprise Architecture, Kindle edition, 39.998:24:19 113, -1, Patterns of Enterprise Architecture, Kindle edition, 39.99 jfields$ cat order.* | sort | grep Patterns | cut -d"," -f2,5 1, 39.99 -1, 39.99
现在,我们把数据缩减为我们计算想要的形式,把这些数据粘贴到Excel里立刻就能得到结果了。

cut是用来消减信息、简化任务的,但对于输出内容,我们通常会有更复杂的形式。假设我们还需要知道订单的ID,这样可以用来关联相关的其他信息。我们用cut可以获得ID信息,但我们希望把ID放到行的最后,用单引号包上。



sed

sed – 一个流编辑器。它是用来在输入流上执行基本的文本变换。

下面的例子展示了如何用sed命令变换我们的文件行,之后我们在再用cut移除无用的信息。

123456789 jfields$ cat order.* | sort | grep Patterns \>| sed s/"[0-9\:]* \([0-9]*\)\, \(.*\)"/"\2, '\1'"/1, Patterns of Enterprise Architecture, Kindle edition, 39.99, '111'-1, Patterns of Enterprise Architecture, Kindle edition, 39.99, '113' lmp-jfields01:~ jfields$ cat order.* | sort | grep Patterns \>| sed s/"[0-9\:]* \([0-9]*\)\, \(.*\)"/"\2, '\1'"/ | cut -d"," -f1,4,51, 39.99, '111'-1, 39.99, '113'
我们对例子中使用的正则表达式多说几句,不过也没有什么复杂的。正则表达式做了下面几种事情

1、 删除时间戳

2、 捕捉订单号

3、 删除订单号后的逗号和空格

4、 捕捉余下的行信息

里面的引号和反斜杠有点乱,但使用命令行时必须要用到这些。

一旦捕捉到了我们想要的数据,我们可以使用 \1 & \2 来存储它们,并把它们输出成我们想要的格式。我们还在其中加入了要求的单引号,为了保持格式统一,我们还加入了逗号。最后,用cut命令把不必要的数据删除。

现在我们有麻烦了。我们上面已经演示了如何把log文件消减成更简洁的订单形式,但我们的财务部门需要知道订单里一共有哪些书。



uniq

uniq – 删除重复的行

下面的例子展示了如何过滤出跟书相关的交易,删除不需要的信息,获得一个不重复的信息。

123 jfields$ cat order.out.log | grep "\(Kindle\|Hardcover\)" | cut -d"," -f3 | sort | uniq -c   1  Joy of Clojure   2  Patterns of Enterprise Architecture
看起来这是一个很简单的任务。

这都是很好用的命令,但前提是你要能找到你想要的文件。有时候你会发现一些文件藏在很深的文件夹里,你根本不知道它们在哪。但如果你是知道你要寻找的文件的名字的话,这对你就不是个问题了。



find

find – 在文件目录中搜索文件

在上面的例子中我们处理了order.in.log和order.out.log这两个文件。这两个文件放在我的home目录里的。下面了例子将向大家展示如何在一个很深的目录结构里找到这样的文件。

123 jfields$ find /Users -name "order*"Users/jfields/order.in.logUsers/jfields/order.out.log
find命令有很多其它的参数,但99%的时间里我只需要这一个就够了。

简单的一行,你就能找到你想要的文件,然后你可以用cat查看它,用cut修剪它。但文件很小时,你用管道把它们输出到屏幕上是可以的,但当文件大到超出屏幕时,你也许应该用管道把它们输出给less命令。



less

less – 在文件里向前或向后移动

让我们再回到简单的 cat | sort 例子中来,下面的命令就是将经过合并、排序后的内容输出到less命令里。在 less 命令,使用“/”来执行向前搜索,使用“?”命令执行向后搜索。搜索条件是一个正则表达式。

1 jfields$ cat order* | sort | less
如果你在 less 命令里使用 /113.*,所有113订单的信息都会高亮。你也可以试试?.*112,所有跟订单112相关的时间戳都会高亮。最后你可以用 ‘q’ 来退出less命令。

linux里有很丰富的各种命令,有些是很难用的。然而,学会了前面说的这8个命令,你已经能处理大量的log分析任务了,完全不需要用脚本语言写程序来处理它们。

论坛徽章:
3
天秤座
日期:2013-12-27 13:44:58射手座
日期:2014-05-22 16:52:43天蝎座
日期:2014-08-13 16:03:21
39 [报告]
发表于 2014-05-24 00:10 |只看该作者
linux目录架构
/       根目录
/bin         常用的命令   binary   file   的目錄
/boot       存放系统启动时必须读取的档案,包括核心   (kernel)   在内
          /boot/grub/menu.lst       GRUB设置
          /boot/vmlinuz       内核
          /boot/initrd           核心解壓縮所需   RAM   Disk
/dev         系统周边设备           
/etc         系统相关设定文件
          /etc/DIR_COLORS       设定颜色
          /etc/HOSTNAME       设定用户的节点名
          /etc/NETWORKING       只有YES标明网络存在
          /etc/host.conf   文件说明用户的系统如何查询节点名
          /etc/hosts   设定用户自已的IP与名字的对应表
          /etc/hosts.allow   设置允许使用inetd的机器使用   
          /etc/hosts.deny   设置不允许使用inetd的机器使用
          /etc/hosts.equiv   设置远端机不用密码
          /etc/inetd.conf   设定系统网络守护进程inetd的配置
          /etc/gateways   设定路由器
          /etc/protocols   设定系统支持的协议
          /etc/named.boot   设定本机为名字服务器的配置文件
          /etc/sysconfig/network-scripts/ifcfg-eth0       设置IP
          /etc/resolv.conf         设置DNS     
          /etc/X11     X   Window的配置文件,xorg.conf   或   XF86Config   這兩個   X   Server   的設定檔
          /etc/fstab         记录开机要mount的文件系统
          /etc/inittab   设定系统启动时init进程将把系统设置成什么样的runlevel
          /etc/issue   记录用户登录前显示的信息
          /etc/group   设定用户的组名与相关信息
          /etc/passwd   帐号信息
          /etc/shadow   密码信息
          /etc/sudoers   可以sudo命令的配置文件
          /etc/securetty   设定哪些终端可以让root登录
          /etc/login.defs   所有用户登录时的缺省配置
          /etc/exports   设定NFS系统用的
          /etc/init.d/       所有服務的預設啟動   script   都是放在這裡的,例如要啟動或者關閉
          /etc/xinetd.d/     這就是所謂的   super   daemon   管理的各項服務的設定檔目錄
          /etc/modprobe.conf       内核模块额外参数设定
          /etc/syslog.conf       日志设置文件
/home       使用者家目录
/lib         系统会使用到的函数库
          /lib/modules       kernel   的相关模块
          /var/lib/rpm       rpm套件安装处   
/lost+found         系統不正常產生錯誤時,會將一些遺失的片段放置於此目錄下
/mnt           外设的挂载点
/media       与/mnt类似
/opt           主机额外安装的软件
/proc         虚拟目录,是内存的映射
            /proc/version       内核版本
              /proc/sys/kernel       系统内核功能
/root         系统管理员的家目录
/sbin         系统管理员才能执行的指令
/srv           一些服務啟動之後,這些服務所需要取用的資料目錄
/tmp           一般使用者或者是正在執行的程序暫時放置檔案的地方
/usr           最大的目录,存许应用程序和文件
        /usr/X11R6:       X-Window目录   
        /usr/src:         Linux源代码
        /usr/include:系统头文件
        /usr/openwin   存放SUN的OpenWin   
        /usr/man   在线使用手册
        /usr/bin                       使用者可執行的   binary   file   的目錄
        /usr/local/bin           使用者可執行的   binary   file   的目錄
        /usr/lib                       系统会使用到的函数库
        /usr/local/lib           系统会使用到的函数库
        /usr/sbin                     系统管理员才能执行的指令
        /usr/local/sbin         系统管理员才能执行的指令
/var       日志文件
        /var/log/secure         記錄登入系統存取資料的檔案,例如   pop3,   ssh,   telnet,   ftp   等都會記錄在此檔案中
        /var/log/wtmp             記錄登入者的訊息資料,   last
        /var/log/messages     幾乎系統發生的錯誤訊息
        /var/log/boot.log     記錄開機或者是一些服務啟動的時候,所顯示的啟動或關閉訊息
        /var/log/maillog       紀錄郵件存取或往來(   sendmail   與   pop3   )的使用者記錄
        /var/log/cron             記錄   crontab   這個例行**的內容
        /var/log/httpd,   /var/log/news,   /var/log/mysqld.log,   /var/log/samba,   /var/log/procmail.log:
        分別是幾個不同的網路服務的記錄檔


一些常用的基本命令:
uname   -a         查看内核版本               
ls   -al         显示所有文件的属性
pwd                   显示当前路径                 
cd   -         返回上一次目录           cd   ~         返回主目录
date   s             设置时间、日期                     
cal             显示日历           cal   2006
bc                     计算器具                              
man     &   info           帮助手册
locale           显示当前字体           locale   -a         所有可用字体           /etc/sysconfig/i18n设置文件
LANG=en         使用英文字体                        
sync               将数据同步写入硬盘                 
shutdonw   -h   now   &   half   &   poweroff     关机
reboot           重启                                       
startx     &     init   5       进入图形介面
/work     &   ?work         向上、下查找文档内容
chgrp             改变档案群组     chgrp   testing   install.log         
chown           改变所属人       chown   root:root   install.log
chmod             改变属性           chmod   777   install.log           read=4     write=2     execute=1
cp       复制       cp   filename
rm       删除文件     rm   -rf   filename       强制删除文件
rmdir       删除文件夹
mv     移动         mv   123.txt   222.txt     重命名
mkdir           创建文件夹
touch           创建文件     更新当前时间
cat               由第一行开始显示           cat   |more     分页
nl                 在内容前加行号
more     &     less       一面一面翻动
head   -n   filename       显示第N行内容
tail   -n   filename     显示后N行内容
od                 显示非纯文档
df   -h   显示分区空间
du     显示目录或文件的大小
fdisk       分区设置         fdisk   -l   /dev/hda     显示硬盘分区状态
mkfs         建立各种文件系统     mkfs   -t   ext3     /dev/ram15      
fsck         检查和修复LINUX档案
ln             硬链接       ln   -s     软件链接
whereis       查找命令
locate         查找
find             查找       find   /   -name   "***.*** "
which           查看工具
whoami         显示当前用户
gcc   -v         查看GCC版本
chattr   +i   filename     禁止删除       chattr   -i   filename     取消禁止
lsattr         显示隐藏档属性
updatedb     更新资料库
mke2fs         格式化       mkfs   -t   ext3   
dd   if=/etc/passwd   of=/tmp/passwd.bak         备份
mount           列出系统所有的分区
mount   -t   iso9660   /dev/cdrom   /mnt/cdrom       挂载光盘
mount   -t   vfat   /dev/fd0   /mnt/floppy               挂载软盘
mount   -t   vfat   -o   iocharset=utf8,umask=000   /dev/hda2   /mnt/hda2       挂载fat32分区
mount   -t   ntfs   -o   nls=utf8,umask=000   /dev/hda3   /mnt/hda3                   挂载ntfs分区
Linux-NTFS   Project:   http://linux-ntfs.sourceforge.net/
umount   /mnt/hda3     缷载
ifconfig       显示或设置网络设备
service   network   restart       重启网卡     
ifdown   eth0     关闭网卡
ifup   eth0         开启网卡
clear         清屏
history         历史记录               !55     执行第55个指令
stty       设置终端         stty   -a
fdisk   /mbr       删除GRUB
at           僅進行一次的工作排程
crontab       循環執行的例行性命令         [e]编辑,[l]显示,[r]删除任务
&               后台运行程序         tar   -zxvf   123.tar.gz   &   ---------> 后台运行
jobs         观看后台暂停的程序       jobs   -l
fg             将后台程序调到前台       fg   n   ------> n是数字,可以指定进行那个程序
bg             让工作在后台运行
kill         结束进程         kill   -9   PID           [9]强制结束,[15]正常结束,[l]列出可用的kill信号
ps   aux     查看后台程序      
top           查看后台程序       top   -d   2         每两秒更新一次                 top   -d   2   -p10604       观看某个PID
                top   -b   -n   2   >   /tmp/top.txt   -----> 將   top   的資訊進行   2   次,然後將結果輸出到   /tmp/top.txt         
pstree       以树状图显示程序         [A]以   ASCII   來連接,   列出PID,   [p]列出帐号
killall       要刪除某個服務         killall   -9   httpd
free             显示内存状态           free   -m     --------> 以M为单位显示
uptime         显示目前系统开机时间
netstat       显示网络状态         netstat   -tulnp------> 找出目前系統上已在監聽的網路連線及其   PID
dmesg           显示开机信息         demsg   |   more
nice             设置优先权             nice   -n   -5   vi   &   -----> 用   root   給一個   nice   植為   -5   ,用於執行   vi   
renice         调整已存在优先权
runlevel     显示目前的runlevel
depmod         分析可载入模块的相依性
lsmod           显示已载入系统的模块
modinfo       显示kernel模块的信息
insmod         载入模块
modprobe       自动处理可载入模块
rmmod           删除模块
chkconfig       检查,设置系统的各种服务           chkconfig   --list   -----> 列出各项服务状态
ntsysv           设置系统的各种服务
cpio             备份文件

压缩命令:
  *.Z             compress   程式壓縮的檔案;   
  *.bz2         bzip2   程式壓縮的檔案;   
  *.gz           gzip   程式壓縮的檔案;   
打包:*.tar         tar   程式打包的資料,並沒有壓縮過;   
  *.tar.gz   tar   程式打包的檔案,其中並且經過   gzip   的壓縮
compress   filename     压缩文件     加[-d]解压     uncompress
gzip   filename       压缩     加[-d]解压     zcat   123.gz   查看压缩文件内容
bzip2   -z   filename     压缩     加[-d]解压       bzcat   filename.bz2     查看压缩文件内容

tar   -cvf   /home/123.tar   /etc     打包,不压缩
tar   -zcvf  /home/123.tar.gz   /etc     打包,不压缩
tar   -xvf   123.tar       解开包
tar   -zxvf   /home/123.tar.gz     以gzip解压
tar   -jxvf   /home/123.tar.bz2     以bzip2解压
tar   -ztvf   /tmp/etc.tar.gz       查看tar内容
cpio   -covB     >   [file|device]       份份
cpio   -icduv   <   [file|device]       还原

vi一般用法
一般模式                             编辑模式                                     指令模式
h   左                               a,i,r,o,A,I,R,O                           :w   保存
j   下                                 进入编辑模式                                 :w!   强制保存
k   上                                 dd   删除光标当前行                       :q!   不保存离开
l   右                                 ndd   删除n行                                   :wq!   保存后离开
0   移动到行首                 yy   复制当前行                                 :e!   还原原始档
$   移动到行尾                 nyy   复制n行                                     :w   filename   另存为
H   屏幕最上                     p,P   粘贴                                           :set   nu   设置行号
M   屏幕中央                     u     撤消                                             :set   nonu   取消行号
L   屏幕最下                     [Ctrl]+r   重做上一个动作               ZZ   保存离开
G   档案最后一行             [ctrl]+z   暂停退出                         :set   nohlsearch       永久地关闭高亮显示
/work   向下搜索                                                                       :sp   同时打开两个文档   
?work   向上搜索                                                                       [Ctrl]+w   两个文档设换
gg   移动到档案第一行                                                             :nohlsearch         暂时关闭高亮显示


认识SHELL
alias         显示当前所有的命令别名             alias   lm= "ls   -al "       命令别名         unalias   lm   取消命令别名
type             类似which
exprot         设置或显示环境变量
exprot   PATH= "$PATH ":/sbin     添加/sbin入PATH路径
echo   $PATH         显示PATH路径
bash             进入子程序
name=yang           设定变量
unset   name         取消变量
echo   $name         显示变量的内容
myname= "$name   its   me "       &       myname= '$name   its   me '           单引号时$name失去变量内容
ciw=/etc/sysconfig/network-scripts/           设置路径
env             列出所有环境变量
echo   $RANDOM         显示随意产生的数
set             设置SHELL
PS1= '[\u@\h   \w   \A   #\#]\$   '           提示字元的設定
      [root@linux   ~]#   read   [-pt]   variable           -----------读取键盘输入的变量
      參數:
      -p     :後面可以接提示字元!
      -t     :後面可以接等待的『秒數!』
declare         声明   shell   变量
ulimit   -a       显示所有限制资料
  ls   /tmp/yang   &&   echo   "exist "   ||   echo   "not   exist "
  意思是說,當   ls   /tmp/yang   執行後,若正確,就執行echo   "exist "   ,若有問題,就執行echo   "not   exist "   
  echo   $PATH   |   cut   -d   ': '   -f   5               以:为分隔符,读取第5段内容
  export   |   cut   -c   10-20             读取第10到20个字节的内容
  last   |   grep   'root '         搜索有root的一行,加[-v]反向搜索
  cat   /etc/passwd   |   sort         排序显示
  cat   /etc/passwd   |   wc             显示『行、字数、字节数』
正规表示法
[root@test   root]#   grep   [-acinv]   '搜尋字串 '   filename
              參數說明:
              -a   :將   binary   檔案以   text   檔案的方式搜尋資料
              -c   :計算找到   '搜尋字串 '   的次數
              -i   :忽略大小寫的不同,所以大小寫視為相同
              -n   :順便輸出行號
              -v   :反向選擇,亦即顯示出沒有   '搜尋字串 '   內容的那一行!
  grep   -n   'the '   123.txt           搜索the字符   -----------搜尋特定字串               
  grep   -n   't[ea]st '   123.txt         搜索test或taste两个字符---------利用   []   來搜尋集合字元
  grep   -n   '[^g]oo '   123.txt           搜索前面不为g的oo-----------向選擇   [^]   
  grep   -n   '[0-9] '   123.txt     搜索有0-9的数字
  grep   -n   '^the '   123.txt   搜索以the为行首-----------行首搜索^
  grep   -n   '^[^a-zA-Z] '   123.txt     搜索不以英文字母开头
  grep   -n   '[a-z]$ '   123.txt         搜索以a-z结尾的行----------   行尾搜索$
  grep   -n   'g..d '   123.txt           搜索开头g结尾d字符----------任意一個字元   .   
  grep   -n   'ooo* '   123.txt           搜索至少有两个oo的字符---------重複字元   *
sed         文本流编辑器         利用脚本命令来处理文本文件
awd         模式扫描和处理语言
  nl   123.txt   |   sed   '2,5d '       删除第二到第五行的内容
diff           比较文件的差异
cmp             比较两个文件是否有差异
patch         修补文件
pr               要打印的文件格式化


帐号管理
/etc/passwd         系统帐号信息
/etc/shadow         帐号密码信息         经MD5   32位加密
          在密码栏前面加『   *   』『   !   』禁止使用某帐号
/etc/group           系统群组信息
/etc/gshadow
newgrp         改变登陆组
useradd     &     adduser         建立新用户     --------->   useradd   -m   test     自动建立用户的登入目录
                    useradd   -m   -g   pgroup   test   ---------> 指定所属级
/etc/default/useradd       相关设定
/etc/login.defs               UID/GID   有關的設定
passwd         更改密码   ----------->   passwd   test
usermod       修改用户帐号
userdel       删除帐号   -----------> userdel   -r   test
chsh             更换登陆系统时使用的SHELL       [-l]显示可用的SHELL;[-s]修改自己的SHELL
chfn             改变finger指令显示的信息
finger         查找并显示用户信息
id                 显示用户的ID   ----------->     id   test
groupadd       添加组
groupmod       与usermod类似
groupdel       删除组
su   test         更改用户       su   -         进入root,且使用root的环境变量
sudo               以其他身份来执行指令
visudo           编辑/etc/sudoers             加入一行『   test   ALL=(ALL)   ALL   』
                      %wheel   ALL   =   (ALL)   ALL                               系统里所有wheel群组的用户都可用sudo
                      %wheel   ALL   =   (ALL)   NOPASSWD:   ALL           wheel群组所有用户都不用密码NOPASSWD
              User_Alias   ADMPW   =   vbird,   dmtsai,   vbird1,   vbird3                   加入ADMPW组
              ADMPW   ALL   =   NOPASSWD:   !/usr/bin/passwd,   /usr/bin/passwd   [A-Za-z]*,   \
              !/usr/bin/passwd   root             可以更改使用者密码,但不能更改root密码   (在指令前面加入   !   代表不可)
PAM   (Pluggable   Authentication   Modules,   嵌入式模組)
who   &   w           看谁在线                                          
last                 最近登陆主机的信息
lastlog           最近登入的時間         读取   /var/log/lastlog   
talk                 与其他用户交谈
write               发送信息         write   test       [ctrl]+d   发送
mesg                 设置终端机的写入权限         mesg   n   禁止接收           mesg   y   
wall                 向所有用户发送信息         wall   this   is   q   test
mail                 写mail      
/etc/default/useradd         家目录默认设置
quota             显示磁盘已使用的空间与限制           quota   -guvs   -----> 秀出目前   root   自己的   quota   限制值
                      quota   -vu       查询
quotacheck       检查磁盘的使用空间与限制           quotacheck   -avug     -----> 將所有的在   /etc/mtab   內,含有   quota   支援的   partition   進行掃瞄
                          [-m]   强制扫描     
          quota一定要是独立的分区,要有quota.user和quota.group两件文件,在/etc/fstab添加一句:
          /dev/hda3   /home   ext3   defaults,usrquota,grpquota   1   2
          chmod   600   quota*                   设置完成,重启生效
edquota         编辑用户或群组的quota     用户,[g]群组,[p]复制,[t]设置宽限期限   
                      edquota   -a   yang               edquota   -p   yang   -u   young   -----> 复制         
quotaon         开启磁盘空间限制           quotaon   -auvg   --------> 啟動所有的具有   quota   的   filesystem
quotaoff       关闭磁盘空间限制           quotaoff   -a     --------> 關閉了   quota   的限制
repquota   -av           查閱系統內所有的具有   quota   的   filesystem   的限值狀態
Quota   從開始準備   filesystem   的支援到整個設定結束的主要的步驟大概是:
1、設定   partition   的   filesystem   支援   quota   參數:
由於   quota   必須要讓   partition   上面的   filesystem   支援才行,一般來說,   支援度最好的是   ext2/ext3   ,
其他的   filesystem   類型鳥哥我是沒有試過啦!   啟動   filesystem   支援   quota   最簡單就是編輯   /etc/fstab   ,
使得準備要開放的   quota   磁碟可以支援   quota   囉;
2、建立   quota   記錄檔:
剛剛前面講過,整個   quota   進行磁碟限制值記錄的檔案是   aquota.user/aquota.group,   
要建立這兩個檔案就必須要先利用   quotacheck   掃瞄才行喔!
3、編輯   quota   限制值資料:
再來就是使用   edquota   來編輯每個使用者或群組的可使用空間囉;
4、重新掃瞄與啟動   quota   :
設定好   quota   之後,建議可以再進行一次   quotacheck   ,然後再以   quotaon   來啟動吧!

开机流程简介
1、載入   BIOS   的硬體資訊,並取得第一個開機裝置的代號;   
2、讀取第一個開機裝置的   MBR   的   boot   Loader   (亦即是   lilo,   grub,   spfdisk   等等)   的開機資訊;   
3、載入   Kernel   作業系統核心資訊,   Kernel   開始解壓縮,並且嘗試驅動所有硬體裝置;   
4、Kernel   執行   init   程式並取得   run-level   資訊;   
5、init   執行   /etc/rc.d/rc.sysinit   檔案;   
6、啟動核心的外掛模組   (/etc/modprobe.conf);   
7、init   執行   run-level   的各個批次檔(   Scripts   );   
8、init   執行   /etc/rc.d/rc.local   檔案;   
9、執行   /bin/login   程式,並等待使用者登入;   
10、登入之後開始以   Shell   控管主機。   
在/etc/rc.d/rc3.d內,以S开头的为开机启动,以K开头的为关闭,接着的数字代表执行顺序
GRUB   vga设定
彩度\解析度     640x480     800x600     1024x768     1280x1024       bit   
        256                 769             771             773               775             8   bit   
      32768               784             787             790               793           15   bit   
      65536               785             788             791               794           16   bit   
      16.8M               786             789             792               795           32   bit   

./configure         检查系统信息               ./configure   --help   |   more     帮助信息
make   clean           清除之前留下的文件
make                       编译
make   install       安装
rpm   -q     -----> 查询是否安装                           rpm   -ql   ------> 查询该套件所有的目录
rpm   -qi   -----> 查询套件的说明资料               rpm   -qc[d]   -----> 设定档与说明档
rpm   -ivh     ----> 安装                                         rpm   -V     --------> 查看套件有否更动过
rpm   -e     ------> 删除                                         rpm   -Uvh   -------> 升级安装     
--nodeps   -----> 强行安装                                 --test   -----> 测试安装

查找端口:
netstat -anp | grep 7161
udp        0      0 10.168.25.74:27161      0.0.0.0:*                           32543/oamagent
查找进程:
ps -ef | grep 32543
oamjyy   32543 32485  0 Jan29 ?        00:00:08 oamagent

date 01091414 设置时间为:1月9日14点14分
date 0109:   设置时间为:1点09分

论坛徽章:
3
天秤座
日期:2013-12-27 13:44:58射手座
日期:2014-05-22 16:52:43天蝎座
日期:2014-08-13 16:03:21
40 [报告]
发表于 2014-05-24 00:11 |只看该作者
linux系统性能评估与优化  一、影响Linux服务器性能的因素

1. 操作系统级



&Oslash;       CPU

&Oslash;       内存

&Oslash;       磁盘I/O带宽

&Oslash;       网络I/O带宽



2.程序应用级



二、系统性能评估标准


影响性能因素
评判标准



糟糕

CPU
user% + sys%<70%
user% + sys%= 85%
user% + sys% >=90%

内存
Swap In  (si)=0

Swap Out(so)=0
Per CPU with 10 page/s
More Swap In & Swap Out

磁盘
iowait % < 20%
iowait % =35%
iowait % >= 50%




  

其中:

       %user:表示CPU处在用户模式下的时间百分比。

       %sys:表示CPU处在系统模式下的时间百分比。

       %iowait:表示CPU等待输入输出完成时间的百分比。

       swap in:即si,表示虚拟内存的页导入,即从SWAP DISK交换到RAM

       swap out:即so,表示虚拟内存的页导出,即从RAM交换到SWAP DISK。



三、系统性能分析工具



1.常用系统命令

Vmstat、sar、iostat、netstat、free、ps、top等



2.常用组合方式

• 用vmstat、sar、iostat检测是否是CPU瓶颈

• 用free、vmstat检测是否是内存瓶颈

• 用iostat检测是否是磁盘I/O瓶颈

• 用netstat检测是否是网络带宽瓶颈



四、Linux性能评估与优化



1. 系统整体性能评估(uptime命令)



[root@web1 ~]# uptime

16:38:00 up 118 days, 3:01, 5 users, load average: 1.22, 1.02, 0.91

这里需要注意的是:load average这个输出值,这三个值的大小一般不能大于系统CPU的个数,例如,本输出中系统有8个CPU,如果load average的三个值长期大于8时,说明CPU很繁忙,负载很高,可能会影响系统性能,但是偶尔大于8时,倒不用担心,一般不会影响系统性能。相反,如果load average的输出值小于CPU的个数,则表示CPU还有空闲的时间片,比如本例中的输出,CPU是非常空闲的。



1 cpu性能评估
Cpu是影响Linux性能的主要因素之一,下面先介绍几个查看CPU性能的命令。
1.1 vmstat命令
该命令可以显示关于系统各种资源之间相关性能的简要信息,这里我们主要用它来看CPU的一个负载情况。
下面是vmstat命令在某个系统的输出结果:
[root@node1 ~]# vmstat 2 3
procs -----------memory----------  ---swap--  -----io---- --system--  -----cpu------
r  b   swpd   free   buff  cache   si   so    bi    bo    in    cs    us sy  id  wa st
0  0    0    162240   8304  67032   0    0    13    21   1007   23     0  1  98  0  0
0  0    0    162240   8304  67032   0    0     1     0   1010   20     0  1  100 0  0
0  0    0    162240   8304  67032   0    0     1     1   1009   18     0  1  99  0  0
对上面每项的输出解释如下:
? procs
? r列表示运行和等待cpu时间片的进程数,这个值如果长期大于系统CPU的个数,说明CPU不足,需要增加CPU。
? b列表示在等待资源的进程数,比如正在等待I/O、或者内存交换等。
? memory
? swpd列表示切换到内存交换区的内存数量(以k为单位)。如果swpd的值不为0,或者比较大,只要si、so的值长期为0,这种情况下一般不用担心,不会影响系统性能。
? free列表示当前空闲的物理内存数量(以k为单位)
? buff列表示buffers cache的内存数量,一般对块设备的读写才需要缓冲。
? cache列表示page cached的内存数量,一般作为文件系统cached,频繁访问的文件都会被cached,如果cache值较大,说明cached的文件数较多,如果此时IO中bi比较小,说明文件系统效率比较好。
? swap
? si列表示由磁盘调入内存,也就是内存进入内存交换区的数量。
? so列表示由内存调入磁盘,也就是内存交换区进入内存的数量。
一般情况下,si、so的值都为0,如果si、so的值长期不为0,则表示系统内存不足。需要增加系统内存。
? IO项显示磁盘读写状况
? Bi列表示从块设备读入数据的总量(即读磁盘)(每秒kb)。
? Bo列表示写入到块设备的数据总量(即写磁盘)(每秒kb)
这里我们设置的bi+bo参考值为1000,如果超过1000,而且wa值较大,则表示系统磁盘IO有问题,应该考虑提高磁盘的读写性能。
? system 显示采集间隔内发生的中断数
? in列表示在某一时间间隔中观测到的每秒设备中断数。
? cs列表示每秒产生的上下文切换次数。
上面这2个值越大,会看到由内核消耗的CPU时间会越多。
? CPU项显示了CPU的使用状态,此列是我们关注的重点。
? us列显示了用户进程消耗的CPU 时间百分比。us的值比较高时,说明用户进程消耗的cpu时间多,但是如果长期大于50%,就需要考虑优化程序或算法。
? sy列显示了内核进程消耗的CPU时间百分比。Sy的值较高时,说明内核消耗的CPU资源很多。
根据经验,us+sy的参考值为80%,如果us+sy大于 80%说明可能存在CPU资源不足。
? id 列显示了CPU处在空闲状态的时间百分比。
? wa列显示了IO等待所占用的CPU时间百分比。wa值越高,说明IO等待越严重,根据经验,wa的参考值为20%,如果wa超过20%,说明IO等待严重,引起IO等待的原因可能是磁盘大量随机读写造成的,也可能是磁盘或者磁盘控制器的带宽瓶颈造成的(主要是块操作)。
综上所述,在对CPU的评估中,需要重点注意的是procs项r列的值和CPU项中us、sy和id列的值。


1.2  sar命令
检查CPU性能的第二个工具是sar,sar功能很强大,可以对系统的每个方面进行单独的统计,但是使用sar命令会增加系统开销,不过这些开销是可以评估的,对系统的统计结果不会有很大影响。
下面是sar命令对某个系统的CPU统计输出:
[root@webserver ~]# sar -u 3 5
Linux 2.6.9-42.ELsmp (webserver)        11/28/2008      _i686_  (8 CPU)

11:41:24 AM     CPU     %user     %nice   %system   %iowait    %steal     %idle
11:41:27 AM     all      0.88      0.00      0.29      0.00      0.00     98.83
11:41:30 AM     all      0.13      0.00      0.17      0.21      0.00     99.50
11:41:33 AM     all      0.04      0.00      0.04      0.00      0.00     99.92
11:41:36 AM     all      0.29      0.00      0.13      0.00      0.00     99.58
11:41:39 AM     all      0.38      0.00      0.17      0.04      0.00     99.41
Average:        all      0.34      0.00      0.16      0.05      0.00     99.45
对上面每项的输出解释如下:
? %user列显示了用户进程消耗的CPU 时间百分比。
? %nice列显示了运行正常进程所消耗的CPU 时间百分比。
? %system列显示了系统进程消耗的CPU时间百分比。
? %iowait列显示了IO等待所占用的CPU时间百分比
? %steal列显示了在内存相对紧张的环境下pagein强制对不同的页面进行的steal操作 。
? %idle列显示了CPU处在空闲状态的时间百分比。
这个输出是对系统整体CPU使用状况的统计,每项的输出都非常直观,并且最后一行Average是个汇总行,是上面统计信息的一个平均值。
需要注意的一点是:第一行的统计信息中包含了sar本身的统计消耗,所以%user列的值会偏高一点,不过,这不会对统计结果产生多大影响。
在一个多CPU的系统中,如果程序使用了单线程,会出现这么一个现象,CPU的整体使用率不高,但是系统应用却响应缓慢,这可能是由于程序使用单线程的原因,单线程只使用一个CPU,导致这个CPU占用率为100%,无法处理其它请求,而其它的CPU却闲置,这就导致 了整体CPU使用率不高,而应用缓慢 现象的发生 。
针对这个问题,可以对系统的每个CPU分开查询,统计每个CPU的使用情况:
[root@webserver ~]# sar -P 0 3 5
Linux 2.6.9-42.ELsmp (webserver)        11/29/2008      _i686_  (8 CPU)

06:29:33 PM     CPU     %user     %nice   %system   %iowait    %steal     %idle
06:29:36 PM       0      3.00      0.00      0.33      0.00      0.00     96.67
06:29:39 PM       0      0.67      0.00      0.33      0.00      0.00     99.00
06:29:42 PM       0      0.00      0.00      0.33      0.00      0.00     99.67
06:29:45 PM       0      0.67      0.00      0.33      0.00      0.00     99.00
06:29:48 PM       0      1.00      0.00      0.33      0.33      0.00     98.34
Average:          0      1.07      0.00      0.33      0.07      0.00     98.53
这个输出是对系统的第一颗CPU的信息统计,需要注意的是,sar中对CPU的计数是从0开始的,因此,“sar -P 0 3 5”表示对系统的第一颗CPU进行信息统计,“sar -P 4 3 5”则表示对系统的第五颗CPU进行统计。依次类推。可以看出,上面的系统有八颗CPU。


1.3 iostat命令
iostat指令主要用于统计磁盘IO状态,但是也能查看CPU的使用信息,它的局限性是只能显示系统所有CPU的平均信息,看下面的一个输出:
[root@webserver ~]# iostat  -c
Linux 2.6.9-42.ELsmp (webserver)        11/29/2008      _i686_  (8 CPU)

avg-cpu:  %user   %nice   %system  %iowait  %steal   %idle
           2.52    0.00    0.30     0.24     0.00    96.96
在这里,使用了“-c”参数,只显示系统CPU的统计信息,输出中每项代表的含义与sar命令的输出项完全相同,不再详述。


1.4 uptime

命令
uptime是监控系统性能最常用的一个命令,主要用来统计系统当前的运行状况,输出的信息依次为:系统现在的时间、系统从上次开机到现在运行了多长时间、系统目前有多少登陆用户、系统在一分钟内、五分钟内、十五分钟内的平均负载。看下面的一个输出:
[root@webserver ~]# uptime
18:52:11 up 27 days, 19:44,  2 users,  load average: 0.12, 0.08, 0.08
这里需要注意的是load average这个输出值,这三个值的大小一般不能大于系统CPU的个数,例如,本输出中系统有8个CPU,如果load average的三个值长期大于8时,说明CPU很繁忙,负载很高,可能会影响系统性能,但是偶尔大于8时,倒不用担心,一般不会影响系统性能。相反,如果load average的输出值小于CPU的个数,则表示CPU还有空闲的时间片,比如本例中的输出,CPU是非常空闲的。


1.5

本节小结
       上面介绍了检查CPU使用状况的四个命令,通过这些命令需要了解的是:系统CPU是否出现性能瓶颈,也就是说,以上这些命令只能查看CPU是否繁忙,负载是否过大,但是无法知道CPU为何负载过大,因而,判断系统CPU出现问题后,要结合top、ps等命令进一步检查是由那些进程导致CPU负载过大的。引起CPU资源紧缺的原因可能是应用程序不合理造成的,也可能是硬件资源匮乏引起的,所以,要具体问题具体分析,或者优化应用程序,或者增加系统CPU资源。


2 内存性能评估
      内存的管理和优化是系统性能优化的一个重要部分,内存资源的充足与否直接影响应用系统的使用性能,在进行内存优化之前,一定要熟悉linux的内存管理机制,这一点我们在前面的章节已经有深入讲述,本节的重点是如何通过系统命令监控linux系统的内存使用状况。
2.1 free 命令
free是监控linux内存使用状况最常用的指令,看下面的一个输出:
[root@webserver ~]# free -m
             total       used       free     shared    buffers     cached
Mem:          8111       7185        925          0        243       6299
-/+ buffers/cache:        643       7468
Swap:         8189          0       8189
  “free –m”表示以M为单位查看内存使用情况,在这个输出中,重点关注的应该是free列与cached列的输出值,由输出可知,此系统共8G内存,系统空闲内存还有925M,其中,Buffer Cache占用了243M,Page Cache占用了6299M,由此可知系统缓存了很多的文件和目录,而对于应用程序来说,可以使用的内存还有7468M,当然这个7468M包含了Buffer Cache和Page Cache的值。在swap项可以看出,交换分区还未使用。所以从应用的角度来说,此系统内存资源还非常充足。
    一般有这样一个经验公式:应用程序可用内存/系统物理内存>70%时,表示系统内存资源非常充足,不影响系统性能,应用程序可用内存/系统物理内存<20%时,表示系统内存资源紧缺,需要增加系统内存,20%<应用程序可用内存/系统物理内存<70%时,表示系统内存资源基本能满足应用需求,暂时不影响系统性能。
  free命令还可以适时的监控内存的使用状况,使用“-s”参数可以在指定的时间段内不间断的监控内存的使用情况:
[root@webserver ~]# free -b -s 5
total       used       free     shared    buffers     cached
Mem:    8505901056 7528706048  977195008          0  260112384 6601158656
-/+ buffers/cache:  667435008 7838466048
Swap:   8587149312     163840 8586985472

             total       used       free     shared    buffers     cached
Mem:    8505901056 7526936576  978964480          0  260128768 6601142272
-/+ buffers/cache:  665665536 7840235520
Swap:   8587149312     163840 8586985472

             total       used       free     shared    buffers     cached
Mem:    8505901056 7523987456  981913600          0  260141056 6601129984
-/+ buffers/cache:  662716416 7843184640
Swap:   8587149312     163840 8586985472
  其中,“-b”表示以千字节(也就是1024字节为单位)来显示内存使用情况。


2.2 通过watch与free相结合动态监控内存状况
watch是一个非常有用的命令,几乎每个linux发行版都带有这个工具,通过watch,可以动态的监控命令的运行结果,省去手动执行的麻烦。
  可以在watch后面跟上需要运行的命令,watch就会自动重复去运行这个命令,默认是2秒钟执行一次,并把执行的结果更新在屏幕上。例如:
[root@webserver ~]# watch -n 3 -d free
Every 3.0s: free                                   Sun Nov 30 16:23:20 2008

             total       used       free     shared    buffers     cached
Mem:       8306544    7349548     956996          0     203296    6500024
-/+ buffers/cache:     646228    7660316
Swap:      8385888        160    8385728
其中,“-n”指定重复执行的时间,“-d”表示高亮显示变动。


2.3 vmstat

命令监控内存
vmstat命令在监控系统内存方面功能强大,请看下面的一个输出:
procs  -----------memory----------  ---swap--  -----io---- --system--   ----cpu----
r  b   swpd    free buff    cache   si   so    bi    bo    in    cs    us sy id   wa
0  0  906440  22796 155616 1325496  340  180    2     4     1     4    80  0  10  10
0  0  906440  42796 155616 1325496  320  289    0    54    1095  287   70  15  0  15
0  0  906440  42884 155624 1325748  236  387    2   102    1064   276  78  2   5  15
对于内存的监控,在vmstat中重点关注的是swpd、si和so行,从这个输出可以看出,此系统内存资源紧缺,swpd占用了900M左右内存,si和so占用很大,而由于系统内存的紧缺,导致出现15%左右的系统等待,此时增加系统的内存是必须要做的。


2.4 sar -r命令组合
sar命令也可以监控linux的内存使用状况,可以通过“sar –r”组合查看系统内存和交换空间的使用率。请看下面的一个输出:
[root@webserver ~]# sar -r 2 3
Linux 2.6.9-42.ELsmp (webserver)        11/30/2008      _i686_  (8 CPU)

09:57:33 PM kbmemfree kbmemused  %memused kbbuffers  kbcached  kbcommit   %commit
09:57:35 PM    897988   7408556     89.19    249428   6496532    786556      4.71
09:57:37 PM    898564   7407980     89.18    249428   6496532    784276      4.70
09:57:39 PM    899196   7407348     89.17    249440   6496520    782132      4.69
Average:       898583   7407961     89.18    249432   6496528    784321      4.70
其中:
Kbmemfree表示空闲物理内存大小,kbmemused表示已使用的物理内存空间大小,%memused表示已使用内存占总内存大小的百分比,kbbuffers和kbcached分别表示Buffer Cache和Page Cache的大小,kbcommit和%commit分别表示应用程序当前使用的内存大小和使用百分比。
可以看出sar的输出其实与free的输出完全对应,不过sar更加人性化,不但给出了内存使用量,还给出了内存使用的百分比以及统计的平均值。从%commit项可知,此系统目前内存资源充足。


2.5  本节小结
上面介绍了内存监控常用的几个指令以及一些经验规则,其实现在的系统在内存方面出现的瓶颈已经很少,因为内存价格很低,充足的内存已经完全能满足应用程序和系统本身的需要,如果系统在内存方面出现瓶颈,很大的可能是应用程序本身的问题造成的。



3 磁盘I/O性能评估
在对磁盘I/O性能做评估之前,必须知道的几个方面是:
? 熟悉RAID存储方式,可以根据应用的不同,选择不同的RAID方式,例如,如果一个应用经常有大量的读操作,可以选择RAID5方式构建磁盘阵列存储数据,如果应用有大量的、频繁的写操作,可以选择raid0存取方式,如果应用对数据安全要求很高,同时对读写也有要求的话,可以考虑raid01存取方式等等。
? 尽可能用内存的读写代替直接磁盘I/O,使频繁访问的文件或数据放入内存中进行操作处理,因为内存读写操作比直接磁盘读写的效率要高千倍。
? 将经常进行读写的文件与长期不变的文件独立出来,分别放置到不同的磁盘设备上。
? 对于写操作频繁的数据,可以考虑使用裸设备代替文件系统。这里简要讲述下文件系统与裸设备的对比:
使用裸设备的优点有:
? 数据可以直接读写,不需要经过操作系统级的缓存,节省了内存资源,避免了内存资源争用。
? 避免了文件系统级的维护开销,比如文件系统需要维护超级块、I-node等。
? 避免了操作系统的cache预读功能,减少了I/O请求。
使用裸设备的缺点是:
? 数据管理、空间管理不灵活,需要很专业的人来操作。
其实裸设备的优点就是文件系统的缺点,反之也是如此,这就需要我们做出合理的规划和衡量,根据应用的需求,做出对应的策略。
下面接着介绍对磁盘IO的评估标准。
3.1 sar -d命令组合
通过“sar –d”组合,可以对系统的磁盘IO做一个基本的统计,请看下面的一个输出:
[root@webserver ~]# sar -d 2 3
Linux 2.6.9-42.ELsmp (webserver)        11/30/2008      _i686_  (8 CPU)

11:09:33 PM  DEV   tps   rd_sec/s wr_sec/s  avgrq-sz  avgqu-sz  await  svctm   %util
11:09:35 PM dev8-0  0.00  0.00     0.00      0.00      0.00      0.00   0.00    0.00

11:09:35 PM  DEV   tps  rd_sec/s  wr_sec/s  avgrq-sz  avgqu-sz  await   svctm   %util
11:09:37 PM dev8-0  1.00  0.00     12.00     12.00      0.00     0.00    0.00    0.00

11:09:37 PM   DEV   tps  rd_sec/s  wr_sec/s  avgrq-sz  avgqu-sz  await  svctm  %util
11:09:39 PM dev8-0  1.99   0.00    47.76     24.00     0.00      0.50    0.25    0.05

Average:  DEV     tps    rd_sec/s  wr_sec/s  avgrq-sz  avgqu-sz  await  svctm   %util
Average:  dev8-0  1.00   0.00      19.97     20.00      0.00     0.33    0.17    0.02
对上面每项的输出解释如下:
? DEV表示磁盘设备名称。
? tps表示每秒到物理磁盘的传送数,也就是每秒的I/O流量。一个传送就是一个I/O请求,多个逻辑请求可以被合并为一个物理I/O请求。
? rd_sec/s表示每秒从设备读取的扇区数(1扇区=512字节)。
? wr_sec/s表示每秒写入设备的扇区数目。
? avgrq-sz表示平均每次设备I/O操作的数据大小(以扇区为单位)。
? avgqu-sz表示平均I/O队列长度。
? await表示平均每次设备I/O操作的等待时间(以毫秒为单位)。
? svctm表示平均每次设备I/O操作的服务时间(以毫秒为单位)。
? %util表示一秒中有百分之几的时间用于I/O操作。
Linux中I/O请求系统与现实生活中超市购物排队系统有很多类似的地方,通过对超市购物排队系统的理解,可以很快掌握linux中I/O运行机制。比如:
avgrq-sz类似与超市排队中每人所买东西的多少。
avgqu-sz类似与超市排队中单位时间内平均排队的人数。
await类似与超市排队中每人的等待时间。
svctm类似与超市排队中收银员的收款速度。
%util类似与超市收银台前有人排队的时间比例。
对以磁盘IO性能,一般有如下评判标准:
正常情况下svctm应该是小于await值的,而svctm的大小和磁盘性能有关,CPU、内存的负荷也会对svctm值造成影响,过多的请求也会间接的导致svctm值的增加。
await值的大小一般取决与svctm的值和I/O队列长度以及I/O请求模式,如果svctm的值与await很接近,表示几乎没有I/O等待,磁盘性能很好,如果await的值远高于svctm的值,则表示I/O队列等待太长,系统上运行的应用程序将变慢,此时可以通过更换更快的硬盘来解决问题。
%util项的值也是衡量磁盘I/O的一个重要指标,如果%util接近100%,表示磁盘产生的I/O请求太多,I/O系统已经满负荷的在工作,该磁盘可能存在瓶颈。长期下去,势必影响系统的性能,可以通过优化程序或者通过更换更高、更快的磁盘来解决此问题。


3.2 iostat –d命令组合
通过“iostat –d”命令组合也可以查看系统磁盘的使用状况,请看如下输出:
[root@webserver ~]#   iostat -d 2 3
Linux 2.6.9-42.ELsmp (webserver)        12/01/2008      _i686_  (8 CPU)

Device:            tps   Blk_read/s   Blk_wrtn/s   Blk_read   Blk_wrtn
sda               1.87         2.58       114.12    6479462  286537372

Device:            tps   Blk_read/s   Blk_wrtn/s   Blk_read   Blk_wrtn
sda               0.00         0.00         0.00          0          0

Device:            tps   Blk_read/s   Blk_wrtn/s   Blk_read   Blk_wrtn
sda               1.00         0.00        12.00          0         24
对上面每项的输出解释如下:
? Blk_read/s表示每秒读取的数据块数。
? Blk_wrtn/s表示每秒写入的数据块数。
? Blk_read表示读取的所有块数
? Blk_wrtn表示写入的所有块数。
这里需要注意的一点是:上面输出的第一项是系统从启动以来到统计时的所有传输信息,从第二次输出的数据才代表在检测的时间段内系统的传输值。
可以通过Blk_read/s和Blk_wrtn/s的值对磁盘的读写性能有一个基本的了解,如果Blk_wrtn/s值很大,表示磁盘的写操作很频繁,可以考虑优化磁盘或者优化程序,如果Blk_read/s值很大,表示磁盘直接读取操作很多,可以将读取的数据放入内存中进行操作。对于这两个选项的值没有一个固定的大小,根据系统应用的不同,会有不同的值,但是有一个规则还是可以遵循的:长期的、超大的数据读写,肯定是不正常的,这种情况一定会影响系统性能。
“iostat –x”组合还提供了对每个磁盘的单独统计,如果不指定磁盘,默认是对所有磁盘进行统计,请看下面的一个输出:
[root@webserver ~]#   iostat -x /dev/sda  2 3
Linux 2.6.9-42.ELsmp (webserver)        12/01/2008      _i686_  (8 CPU)

avg-cpu:  %user   %nice %system %iowait  %steal   %idle
           2.45    0.00    0.30    0.24    0.00   97.03

Device: rrqm/s  wrqm/s  r/s  w/s  rsec/s  wsec/s avgrq-sz avgqu-sz   await  svctm  %util
sda   0.01     12.48    0.10  1.78  2.58   114.03    62.33   0.07    38.39   1.30   0.24

avg-cpu:  %user   %nice %system %iowait  %steal   %idle
           3.97    0.00    1.83    8.19    0.00   86.14

Device:rrqm/s wrqm/s   r/s  w/s   rsec/s  wsec/s avgrq-sz avgqu-sz   await  svctm  %util
sda    0.00   195.00  0.00 18.00  0.00  1704.00    94.67     0.04    2.50   0.11   0.20

avg-cpu:  %user   %nice %system %iowait  %steal   %idle
           4.04    0.00    1.83    8.01    0.00   86.18

Device: rrqm/s  wrqm/s  r/s  w/s   rsec/s   wsec/s avgrq-sz avgqu-sz     await  svctm  %util
sda    0.00     4.50    0.00   7.00   0.00    92.00    13.14     0.01    0.79   0.14   0.10
这个输出基本与“sar –d”相同,需要说明的几个选项的含义为:
? rrqm/s表示每秒进行merged的读操作数目。
? wrqm/s表示每秒进行 merge 的写操作数目。
? r/s表示每秒完成读I/O设备的次数。
? w/s表示每秒完成写I/O设备的次数。
? rsec/s表示每秒读取的扇区数。
? wsec/s表示每秒写入的扇区数。


3.3 vmstat –d组合
通过“vmstat –d”组合也可以查看磁盘的统计数据,情况下面的一个输出:

[root@webserver ~]# vmstat -d 3 2|grep sda
disk- ------------reads------------ ------------writes----------- -----IO------
     total  merged sectors    ms    total    merged   sectors      ms     cur    sec
sda  239588 29282  6481862  1044442 4538678  32387680 295410812  186025580  0   6179
disk- ------------reads------------ ------------writes----------- -----IO------
     total  merged  sectors  ms    total     merged    sectors     ms     cur   sec
sda  239588 29282  6481862 1044442 4538680   32387690 295410908 186025581  0   6179
这个输出显示了磁盘的reads、writes和IO的使用状况。


3.4

本节小结
上面主要讲解了对磁盘I/O的性能评估,其实衡量磁盘I/O好坏是多方面的,有应用程序本身的,也有硬件设计上的,还有系统自身配置的问题等,要解决I/O的瓶颈,关键是要提高I/O子系统的执行效率。例如,首要要从应用程序上对磁盘读写进行优化,能够放到内存执行的操作,尽量不要放到磁盘,同时对磁盘存储方式进行合理规划,选择适合自己的RAID存取方式,最后,在系统级别上,可以选择适合自身应用的文件系统,必要时使用裸设备提高读写性能。



4 网络性能评估
网络性能的好坏直接影响应用程序对外提供服务的稳定性和可靠性,监控网络性能,可以从以下几个方面进行管理和优化。
4.1 通过ping命令检测网络的连通性
如果发现网络反应缓慢,或者连接中断,可以通过ping来测试网络的连通情况,请看下面的一个输出:
[root@webserver ~]# ping 10.10.1.254
PING 10.10.1.254 (10.10.1.254) 56(84) bytes of data.
64 bytes from 10.10.1.254: icmp_seq=0 ttl=64 time=0.235 ms
64 bytes from 10.10.1.254: icmp_seq=1 ttl=64 time=0.164 ms
64 bytes from 10.10.1.254: icmp_seq=2 ttl=64 time=0.210 ms
64 bytes from 10.10.1.254: icmp_seq=3 ttl=64 time=0.178 ms
64 bytes from 10.10.1.254: icmp_seq=4 ttl=64 time=0.525 ms
64 bytes from 10.10.1.254: icmp_seq=5 ttl=64 time=0.571 ms
64 bytes from 10.10.1.254: icmp_seq=6 ttl=64 time=0.220 ms
--- 10.10.1.254 ping statistics ---
7 packets transmitted, 7 received, 0% packet loss, time 6000ms
rtt min/avg/max/mdev = 0.164/0.300/0.571/0.159 ms, pipe 2
在这个输出中,time值显示了两台主机之间的网络延时情况,如果此值很大,则表示网络的延时很大,单位为毫秒。在这个输出的最后,是对上面输出信息的一个总结,packet loss表示网络的丢包率,此值越小,表示网络的质量越高。


4.2 通过netstat –i组合检测网络接口状况
netstat命令提供了网络接口的详细信息,请看下面的输出:
[root@webserver ~]# netstat -i
Kernel Interface table
Iface MTU  Met RX-OK     RX-ERR RX-DRP RX-OVR   TX-OK    TX-ERR TX-DRP TX-OVR       Flg
eth0  1500  0 1313129253  0      0       0     1320686497    0      0      0        BMRU
eth1  1500  0 494902025   0      0       0     292358810     0      0      0        BMRU
lo   16436  0 41901601    0      0       0     41901601      0      0      0        LRU
对上面每项的输出解释如下:
? Iface表示网络设备的接口名称。
? MTU表示最大传输单元,单位字节。
? RX-OK/TX-OK表示已经准确无误的接收/发送了多少数据包。
? RX-ERR/TX-ERR表示接收/发送数据包时产生了多少错误。
? RX-DRP/TX-DRP表示接收/发送数据包时丢弃了多少数据包。
? RX-OVR/TX-OVR表示由于误差而遗失了多少数据包。
? Flg表示接口标记,其中:
? L:表示该接口是个回环设备。
? B:表示设置了广播地址。
? M:表示接收所有数据包。
? R:表示接口正在运行。
? U:表示接口处于活动状态。
? O:表示在该接口上禁用arp。
? P:表示一个点到点的连接。
正常情况下,RX-ERR/TX-ERR、RX-DRP/TX-DRP和RX-OVR/TX-OVR的值都应该为0,如果这几个选项的值不为0,并且很大,那么网络质量肯定有问题,网络传输性能也一定会下降。
当网络传输存在问题是,可以检测网卡设备是否存在故障,如果可能,可以升级为千兆网卡或者光纤网络,还可以检查网络部署环境是否合理。


4.3 通过netstat –r组合检测系统的路由表信息
在网络不通,或者网络异常时,首先想到的就是检查系统的路由表信息,“netstat –r”的输出结果与route命令的输出完全相同,请看下面的一个实例:
[root@webserver ~]#  netstat -r
Kernel IP routing table
Destination     Gateway         Genmask         Flags   MSS Window  irtt Iface
10.10.1.0       *               255.255.255.0   U         0   0       0  eth0
192.168.200.0   *               255.255.255.0   U         0   0       0  eth1
169.254.0.0     *               255.255.0.0     U         0   0       0  eth1
default         10.10.1.254     0.0.0.0         UG        0   0       0  eth0
关于输出中每项的具体含义,已经在前面章节进行过详细介绍,这里不再多讲,这里我们重点关注的是default行对应的值,default项表示系统的默认路由,对应的网络接口为eth0。


4.4 通过sar –n组合显示系统的网络运行状态
sar提供四种不同的选项来显示网络统计信息,通过“-n”选项可以指定4个不同类型的开关:DEV、EDEV、SOCK和FULL。DEV显示网络接口信息,EDEV显示关于网络错误的统计数据,SOCK显示套接字信息,FULL显示所有三个开关。请看下面的一个输出:
[root@webserver ~]# sar -n DEV 2 3
Linux 2.6.9-42.ELsmp (webserver)        12/01/2008      _i686_  (8 CPU)

02:22:31 PM     IFACE   rxpck/s   txpck/s    rxkB/s    txkB/s   rxcmp/s   txcmp/s  rxmcst/s
02:22:33 PM        lo     31.34     31.34     37.53     37.53      0.00      0.00      0.00
02:22:33 PM      eth0    199.50    279.60     17.29    344.12      0.00      0.00      0.00
02:22:33 PM      eth1      5.47      4.98      7.03      0.36      0.00      0.00      0.00
02:22:33 PM      sit0      0.00      0.00      0.00      0.00      0.00      0.00      0.00

02:22:33 PM     IFACE   rxpck/s   txpck/s    rxkB/s    txkB/s   rxcmp/s   txcmp/s  rxmcst/s
02:22:35 PM        lo     67.66     67.66     74.34     74.34      0.00      0.00      0.00
02:22:35 PM      eth0    159.70    222.39     19.74    217.16      0.00      0.00      0.00
02:22:35 PM      eth1      3.48      4.48      0.44      0.51      0.00      0.00      0.00
02:22:35 PM      sit0      0.00      0.00      0.00      0.00      0.00      0.00      0.00

02:22:35 PM     IFACE   rxpck/s   txpck/s    rxkB/s    txkB/s   rxcmp/s   txcmp/s  rxmcst/s
02:22:37 PM        lo      4.52      4.52      9.25      9.25      0.00      0.00      0.00
02:22:37 PM      eth0    102.51    133.67     20.67    116.14      0.00      0.00      0.00
02:22:37 PM      eth1     27.14     67.34      2.42     89.26      0.00      0.00      0.00
02:22:37 PM      sit0      0.00      0.00      0.00      0.00      0.00      0.00      0.00

Average:        IFACE   rxpck/s   txpck/s    rxkB/s    txkB/s   rxcmp/s   txcmp/s  rxmcst/s
Average:           lo     34.61     34.61     40.48     40.48      0.00      0.00      0.00
Average:         eth0    154.08    212.15     19.23    226.17      0.00      0.00      0.00
Average:         eth1     11.98     25.46      3.30     29.85      0.00      0.00      0.00
Average:         sit0      0.00      0.00      0.00      0.00      0.00      0.00      0.00
对上面每项的输出解释如下:
? IFACE表示网络接口设备。
? rxpck/s表示每秒钟接收的数据包大小。
? txpck/s表示每秒钟发送的数据包大小。
? rxkB/s表示每秒钟接收的字节数。
? txkB/s表示每秒钟发送的字节数。
? rxcmp/s表示每秒钟接收的压缩数据包。
? txcmp/s表示每秒钟发送的压缩数据包。
? rxmcst/s表示每秒钟接收的多播数据包。
通过“sar –n”的输出,可以清楚的显示网络接口发送、接收数据的统计信息。此外还可以通过“sar -n EDEV 2 3”来统计网络错误信息等。


4.5 小结
      本节通过几个常用的网络命令介绍了对网络性能的评估,事实上,网络问题是简单而且容易处理的,只要我们根据上面给出的命令,一般都能迅速定位问题。解决问题的方法一般是增加网络带宽,或者优化网络部署环境。
      除了上面介绍的几个命令外,排查网络问题经常用到的命令还有traceroute,主要用于跟踪数据包的传输路径,还有nslookup命令,主要用于判断DNS解析信息。
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP