<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>绿色记忆 &#187; Command</title>
	<atom:link href="https://blog.gmem.cc/tag/command/feed" rel="self" type="application/rss+xml" />
	<link>https://blog.gmem.cc</link>
	<description></description>
	<lastBuildDate>Sun, 19 Apr 2026 07:54:29 +0000</lastBuildDate>
	<language>en-US</language>
		<sy:updatePeriod>hourly</sy:updatePeriod>
		<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.9.14</generator>
	<item>
		<title>JVM学习笔记</title>
		<link>https://blog.gmem.cc/jvm-study-note</link>
		<comments>https://blog.gmem.cc/jvm-study-note#comments</comments>
		<pubDate>Tue, 12 Jun 2012 04:00:36 +0000</pubDate>
		<dc:creator><![CDATA[Alex]]></dc:creator>
				<category><![CDATA[Java]]></category>
		<category><![CDATA[Command]]></category>
		<category><![CDATA[JVM]]></category>
		<category><![CDATA[学习笔记]]></category>

		<guid isPermaLink="false">http://blog.gmem.cc/?p=2805</guid>
		<description><![CDATA[<p>JVM内存管理 JVM内存区域 根据Java虚拟机规范，在运行时，JVM管理的内存分为以下区域： 其中：方法区和堆被所有线程共享，其它三个区域则是线程私有，这些区域的功能如下：  区域 说明  程序计数器 当前线程所执行的字节码的行号指示器，在虚拟机的槪念模型里，字节码解释器工作时就是通过改变此计数器的值来选取下一条需要执行的字节码指令，分支、循环、跳转、异常处理、线程恢复等基础功能都依赖于此计数器。 如果当前正在执行的是一个java方法，这个计数器记录的是正在执行的虚拟机字节码指令的地址；如果正在执行本地方法则为空 JVM栈 此栈的生命周期与线程相同。每个方法执行的时候都会同时创建一个栈帧（Stack Frame），用于存储局部变量表、操作数栈、动态链接、方法出口等信息。每一个方法被调用直至执行完成的过程，就对应着一个栈帧在虚拟机栈中从入栈到出栈过程。这一点和C语言是类似的，栈帧对应着一个未执行完毕的函数。 局部变量表：存放了编译期可知的基本类型、对象引用（reference类型，它不等同于对象本身，根据不同的虚拟机实现，它可能是一个指向对象起始地址的引用指针，也可能指向一个代表对象的句柄或 者其他与此对象相关的位置）和retumAddress类型（指向了一条字节码指令的地址)。其中64位长度的long和double类型的数据会占用2个局部变量空间（Slot），其余的数据类型只占用1个。局部变量表所需的内存空间在编译期间完成分配，当进入一个方法时，这个方法需要在帧中分配多大的局部变量空间是完全确定的，在方法运行期间不会改变局部变量表的大小。 本地方法栈 类似于JVM栈，但是其是用来执行本地方法的。Hotspot虚拟机把JVM栈和本地方法栈合二为一实现。 Java堆 在虚拟机启动时创建，不需要连续的内存区域。此内存区域用于存放对象实例。根据JVM规范的描述，所有对象、数组都要在堆上分配。 Java堆是垃圾回收的主要管理区域。根据GC算法的不同，可能分为：新生代（Eden、From Surivor、To Surivor）和老年代。 Java堆可能划分出线程私有的分配缓冲区（TLAB） <a class="read-more" href="https://blog.gmem.cc/jvm-study-note">[...]</a></p>
<p>The post <a rel="nofollow" href="https://blog.gmem.cc/jvm-study-note">JVM学习笔记</a> appeared first on <a rel="nofollow" href="https://blog.gmem.cc">绿色记忆</a>.</p>
]]></description>
				<content:encoded><![CDATA[<div class="wri_content_clear_both"><div class="blog_h1"><span class="graybg">JVM内存管理</span></div>
<div class="blog_h2"><span class="graybg">JVM内存区域</span></div>
<p>根据Java虚拟机规范，在运行时，JVM管理的内存分为以下区域：</p>
<p><img class="size-full wp-image-2808 aligncenter" style="width: 70%;" src="https://blog.gmem.cc/wp-content/uploads/2012/06/jvm-1.png" alt="jvm-1" /></p>
<p>其中：方法区和堆被所有线程共享，其它三个区域则是线程私有，这些区域的功能如下：</p>
<table style="width: 100%;" border="1" cellspacing="0" cellpadding="5">
<thead>
<tr>
<td style="width: 150px; text-align: center;"> 区域</td>
<td style="text-align: center;">说明 </td>
</tr>
</thead>
<tbody>
<tr>
<td>程序计数器</td>
<td>
<p>当前线程所执行的字节码的行号指示器，在虚拟机的槪念模型里，字节码解释器工作时就是通过改变此计数器的值来选取下一条需要执行的字节码指令，<span style="background-color: #c0c0c0;">分支、循环、跳转、异常处理、线程恢复</span>等基础功能都依赖于此计数器。</p>
<p>如果当前正在执行的是一个java方法，这个计数器记录的是正在执行的<span style="background-color: #c0c0c0;">虚拟机字节码指令的地址</span>；如果正在执行本地方法则为空</p>
</td>
</tr>
<tr>
<td>JVM栈</td>
<td>
<p>此栈的生命周期与线程相同。每个方法执行的时候都会同时创建一个<span style="background-color: #c0c0c0;">栈帧（Stack Frame）</span>，用于存储<span style="background-color: #c0c0c0;">局部变量表、操作数栈、动态链接、方法出口</span>等信息。每一个方法被调用直至执行完成的过程，就对应着一<span style="background-color: #c0c0c0;">个栈帧在虚拟机栈中从入栈到出栈</span>过程。这一点和C语言是类似的，<span style="background-color: #c0c0c0;">栈帧对应着一个未执行完毕的函数</span>。</p>
<p>局部变量表：存放了编译期可知的<span style="background-color: #c0c0c0;">基本类型、对象引用</span>（reference类型，它不等同于对象本身，根据不同的虚拟机实现，它可能是一个指向对象起始地址的引用指针，也可能指向一个代表对象的句柄或 者其他与此对象相关的位置）和<span style="background-color: #c0c0c0;">retumAddress类型（</span>指向了一条字节码指令的地址)。其中64位长度的long和double类型的数据会占用2个局部变量空间（Slot），其余的数据类型只占用1个。局部变量表所需的内存空间在编译期间完成分配，当进入一个方法时，这个方法需要在帧中分配多大的<span style="background-color: #c0c0c0;">局部变量空间是完全确定</span>的，在方法运行期间不会改变局部变量表的大小。</p>
</td>
</tr>
<tr>
<td>本地方法栈</td>
<td>
<p>类似于JVM栈，但是其是用来执行本地方法的。Hotspot虚拟机把JVM栈和本地方法栈合二为一实现。</p>
</td>
</tr>
<tr>
<td>Java堆</td>
<td>
<p>在虚拟机启动时创建，不需要连续的内存区域。此内存区域用于<span style="background-color: #c0c0c0;">存放对象实例</span>。根据JVM规范的描述，所有对象、数组都要在堆上分配。</p>
<p>Java堆是<span style="background-color: #c0c0c0;">垃圾回收的主要管理区域</span>。根据GC算法的不同，可能分为：<span style="background-color: #c0c0c0;">新生代（Eden、From Surivor、To Surivor）和老年代</span>。</p>
<p>Java堆可能划分出<span style="background-color: #c0c0c0;">线程私有的分配缓冲区</span>（TLAB）</p>
</td>
</tr>
<tr>
<td>TLAB</td>
<td>
<p>线程本地分配缓冲（Thread-local allocation buffer）是在<span style="background-color: #c0c0c0;">Eden Space中开辟了一小块线程私有的区域，默认占用Eden的1%空间</span></p>
<p>在Java程序中很多对象都是小对象且用过即丢，它们不存在线程共享也适合被快速GC，对于小对象通常JVM会优先分配在TLAB上，并且TLAB上的分配由于是线程私有所以没有锁开销。因此在实践中分配多个小对象的效率通常比分配一个大对象的效率要高</p>
<p>在TLAB上分配对象时不需要锁住整个堆</p>
<p>对象分配过程：</p>
<ol>
<li>编译器通过逃逸分析，确定对象是在栈上分配还是在堆上分配。如果是在堆上分配，则进入步骤2</li>
<li>如果tlab_top + size &lt;= tlab_end，则在在TLAB上直接分配对象并增加tlab_top 的值，如果现有的TLAB不足以存放当前对象则进入步骤3</li>
<li>重新申请一个TLAB，并再次尝试存放当前对象。如果放不下，则进入步骤4</li>
<li>在Eden区加锁（这个区是多线程共享的），如果eden_top + size &lt;= eden_end则将对象存放在Eden区，增加eden_top 的值，如果Eden区不足以存放，则进入步骤5</li>
<li>执行一次Young GC</li>
<li>经过Young GC之后，如果Eden区任然不足以存放当前对象，则直接分配到老年代</li>
</ol>
</td>
</tr>
<tr>
<td>方法区</td>
<td>
<p>存储已被虚拟机加载的<span style="background-color: #c0c0c0;">类信息、常量、静态变量、即时编译器编译后的代码</span>等数据。尽管虚拟机规范把方法区描述为堆的一个逻辑部分，但是它却有一个别名叫做<span style="background-color: #c0c0c0;">Non-Heap (非堆 ）</span></p>
<p>对于Hotspot来说，常常把方法区称为<span style="background-color: #c0c0c0;">永久代</span></p>
<p><span style="background-color: #c0c0c0;">运行时常量池（Runtime Constant Pool)</span>：存放编译期生成的各种字面量和符号引用，这部分内容将在类加载后存放到方法区的运行时常量池中。注意Java语言不强制常量在编译时产生，所以此池具有动态性</p>
</td>
</tr>
</tbody>
</table>
<div class="blog_h3"><span class="graybg">直接内存</span></div>
<p>除了上述的运行时区域以外，还有一块内存区域叫直接内存（Direct Memory）。 NIO类库引入了一种基于通道（Channel) 与缓冲区（Buffer)的I/O方式，它可以使用Native函数库<span style="background-color: #c0c0c0;">直接分配堆外内存</span>，然后通过一个存储在Java堆里面的<span style="background-color: #c0c0c0;">DirectByteBuffer</span>对象作为这块内存的引用进行操作，避免在<span style="background-color: #c0c0c0;">Java堆和Native堆</span>中来回复制数据以提高性能。</p>
<p>除了程序计数器以外，其它区域均可能发生OOM异常。</p>
<div class="blog_h3"><span class="graybg">对象访问</span></div>
<p>考虑最简单的代码：Object obj = new Object();</p>
<ol>
<li>Object obj 将映射到Java栈的本地变量表中，作为Reference类型出现</li>
<li>new Object()将反映到Java堆中，形成一块存储Object类型实例数据值（对象各字段数据）的结构化内存</li>
<li>关于Object类的类型信息（Class、父类、接口、方法等）存放于方法区</li>
</ol>
<p>引用类型的两种实现方式：</p>
<ol>
<li>使用句柄：堆中划分单独区域作为句柄池，Reference中存放的为对象句柄地址，而句柄中包含对象实例数据、类型数据各自的具体地址</li>
<li>直接指针：Reference直接存放对象的地址，需要考虑类型数据的布局。Hostspot使用的是这种方式</li>
</ol>
<div class="blog_h3"><span class="graybg">JVM内存溢出错误</span></div>
<table style="width: 100%;" border="1" cellspacing="0" cellpadding="5">
<thead>
<tr>
<td style="width: 300px; text-align: center;">内存溢出类型 </td>
<td style="text-align: center;"> 说明</td>
</tr>
</thead>
<tbody>
<tr>
<td>java.lang.OutOfMemoryError: java heap space</td>
<td>
<p>这是最常见的堆内存溢出，即堆对内存空间不足，无法完成对象分配请求。 </p>
<p>出现此问题时，有必要分清内存泄漏（Memory Leak）、内存溢出（Memory overflow），对于前者，要检查泄漏对象到GC Root的路径，对于后者，要考虑增加内存、减少对象生命周期</p>
</td>
</tr>
<tr>
<td>java.lang.OutOfMemoryError:GC over head limit exceeded</td>
<td>垃圾回收器频繁工作，但是GC效果不理想的情况下发生。说明有无法回收的对象</td>
</tr>
<tr>
<td>java.lang.OutOfMemoryError: PermGen space</td>
<td>永久区溢出，通常在系统加载的类非常多、定义了非常多的常量、大量使用动态字节码生成技术导致</td>
</tr>
<tr>
<td>java.lang.OutOfMemoryError: Direct buffer memory</td>
<td>直接或间接使用了ByteBuffer中的allocateDirect方法的时候，而不做clear的时候就会出现类似的问题，设置-XX:MaxDirectMemorySize解决</td>
</tr>
<tr>
<td>java.lang.StackOverflowError</td>
<td>如果线程请求的栈深度大于虚拟机所允许的最大深度则抛出，通常在错误的递归调用中出现。</td>
</tr>
<tr>
<td>java.lang.OutOfMemoryError: unable to create new native thread</td>
<td>
<p>创建了超过系统限制的内存数时会导致</p>
</td>
</tr>
<tr>
<td>java.lang.OutOfMemoryError: requested n bytes for . Out of swap space</td>
<td>一般是由于地址空间不够而造成</td>
</tr>
</tbody>
</table>
<div class="blog_h3"><span class="graybg">操作系统对进程的限制</span></div>
<p>OS对于单个进程的内存是有限制的，<span style="background-color: #c0c0c0;">对于32位Windows，进程内存的上限为2GB</span>。</p>
<p><span style="background-color: #c0c0c0;">JVM进程总内存 = Xmx + MaxPermSize+ 程序计数器 + JVM进程本身内存消耗 + JVM栈 + 本地栈</span></p>
<p>JVM能创建的线程数，一方面受到OS对进程最大线程数的限制，一方面受到内存的限制：总可用栈内存/每个栈的大小。</p>
<div class="blog_h2"><span class="graybg">垃圾收集器与内存分配策略</span></div>
<div class="blog_h3"><span class="graybg">引用计数算法</span></div>
<p>给对象中添加一个引用计数器，每 当有一个地方引用它时，计数器值就加1，当引用失效时，计数器值就减1；任何时刻 计数器都为0的对象就是不可能再被使用的。</p>
<p>缺点：很难解决对象之间的相互<span style="background-color: #c0c0c0;">循环引用</span>的问题。</p>
<div class="blog_h3"><span class="graybg">根搜索算法</span></div>
<p>Java语言中具体垃圾回收算法均是<span style="background-color: #c0c0c0;">根搜索算法的变体</span>。通过一系列的名为“GC Roots”的对象作为起始点，从这些点开始向下搜索，搜索所 走过的路径称为引用链（Reference Chain)，当一个对象到GC Roots没有任何引用链相连时，则证明此对象是不可用 的。在Java语言里，GC Roots对象可以是：</p>
<ol>
<li>虚拟机栈（栈帧中的本地变量表）中的引用的对象</li>
<li>方法区中的类静态属性引用的对象</li>
<li>方法区中的常量引用的对象</li>
<li>本地方法栈中的引用的对象</li>
</ol>
<div class="blog_h3"><span class="graybg">常见的算法列表</span></div>
<table style="width: 100%;" border="1" cellspacing="0" cellpadding="5">
<thead>
<tr>
<td style="width: 150px; text-align: center;">GC算法 </td>
<td style="text-align: center;">说明 </td>
</tr>
</thead>
<tbody>
<tr>
<td>标记-清除算法</td>
<td>
<p>Mark-Sweep算法是最基础的算法，分为“标记”和“清除”两个阶段：<span style="background-color: #c0c0c0;">首先标记出所有需要回收</span>的对象，在<span style="background-color: #c0c0c0;">标记完成后统一回收</span>掉所有被标记的对象</p>
<p>缺点有两个：</p>
<ol>
<li>标记和清除过程的效率都不高，在标记时必须STW</li>
<li>清除之后会产生大量不连续的内存碎片（因为垃圾是分散的），空间碎片太多可能会导致需要分配较大对象时无法找到足够的<span style="background-color: #c0c0c0;">连续内存</span>而不得不提前触发另一次GC</li>
</ol>
</td>
</tr>
<tr>
<td>复制算法</td>
<td>
<p>复制算法主要解决效率问题，将可用内存按容量<span style="background-color: #c0c0c0;">划分为大小相等的两块，每次只使用其中的一块</span>。当这一块的内存用完了，就将还存活着的对象复制到另外一块上面，然后再把已使用过的内存空间一次清理掉。该算法<span style="background-color: #c0c0c0;">避免了内存碎片</span>，但是具有严重缺点：<span style="background-color: #c0c0c0;">两倍的内存消耗</span></p>
<p>由于巨大的内存浪费，实际都采用复制算法的变体来<span style="background-color: #c0c0c0;">回收新生代</span>。JVM通常将内存分为一块较大的Eden空间和两块较小的Survivor空间，每次使用Eden和其中的 一块Survivor。当回收时，<span style="background-color: #c0c0c0;">将Eden和Survivor中还存活着的对象一次性地拷贝到另外一块Survivor空间</span>上，<span style="background-color: #c0c0c0;">最后清理掉Eden和刚才用过的Survivor的空间</span>。HotSpot默认Eden和Survivor的大小比例是8 : 1，也就是Eden中可用内存空间为整个新生代容量的90%。当Survivor空间不够用时，需要依赖年老代进行Promotion</p>
<p>Eden和Survivor默认8:1的比例是基于<span style="background-color: #c0c0c0;">绝大部分对象都是朝生暮死型</span>的假设，某些垃圾收集器能够自适应的调整该比例，该比值越小，内存浪费越大</p>
</td>
</tr>
<tr>
<td>标记-整理算法</td>
<td>
<p>Mark-Compact算法<span style="background-color: #c0c0c0;">针对年老代</span>特点进行设计，<span style="background-color: #c0c0c0;"> 标记过程仍然与“标记-清除”算法一样</span>，但后续步骤不是直接对可回收对象进行清理，而是让<span style="background-color: #c0c0c0;">所有存活的对象都向一端移动，然后直接清理掉端边界以外</span>的内存</p>
<p>该算法的效率低于复制算法</p>
</td>
</tr>
</tbody>
</table>
<div class="blog_h3"><span class="graybg">垃圾回收分类</span></div>
<ol>
<li>Minor GC：只针对年轻代的GC，也称为Young GC</li>
<li>Full GC：针对年老代的GC，偶尔会伴随年轻代、永久代的GC，也称为Major GC</li>
</ol>
<div class="blog_h3"><span class="graybg">JVM垃圾收集器实现</span></div>
<p>Jdk 6u22以后，可用的垃圾收集器有（年轻代年老代之间的连线表示可以组合使用）： <img class="size-full wp-image-2848 aligncenter" style="width: 70%;" src="https://blog.gmem.cc/wp-content/uploads/2012/06/jvm-3.png" alt="jvm-2" /></p>
<table style="width: 100%;" border="1" cellspacing="0" cellpadding="5">
<thead>
<tr>
<td style="width: 150px; text-align: center;"> 垃圾收集器</td>
<td style="text-align: center;"> 说明</td>
</tr>
</thead>
<tbody>
<tr>
<td>Serial</td>
<td>
<p>JDK1.3.1之前的新生代收集唯一选择，<span style="background-color: #c0c0c0;">STW的基于复制算法的单GC线程收集器</span></p>
<p>使用-XX:+UseSerialGC打开，该选项会同时打开Serial Old。在JMC中，该收集器显示为Copy</p>
</td>
</tr>
<tr>
<td>ParNew</td>
<td>
<p><span style="background-color: #c0c0c0;">Serial收集器的多GC线程版本</span>，除了使用多条线程进行垃圾收集之外，其余行为包括Serial收集器可用的所有控制参数（例如：-XXSurvivorRatio、 -XX:PretenureSizeThreshold、-XX:HandlePromotionFailure 等）、收集算法、STW、对象分配规则、回收策略与Serial完全一样</p>
<p>ParNew是许多server模式下JVM的默认新生代收集器，因为它可以与CMS一起工作</p>
<p>在单CPU场景下该收集器不会比Serial表现更好。</p>
<p>-XX:ParallelGCThreads用来指定线程数，默认与CPU数相同，在CPU特别多的情况下，可以减少数量</p>
<p>使用-XX:+UseParNewGC打开，默认与Serial Old配合。在JMC中，该收集器显示为ParNew</p>
</td>
</tr>
<tr>
<td>Parallel Scavenge</td>
<td>
<p><span style="background-color: #c0c0c0;">STW的基于复制算法的多GC线程收集器</span>。它的特点是：<span style="background-color: #c0c0c0;">吞吐量优先</span>（Throughput)，而其它垃圾回收器都是以响应时间为目标，吞吐量=用户代码时间 / (用户代码时间 + GC时间)</p>
<p>-XX:MaxGCPauseMillis用于控制响应时间，-XX:GCTimeRatio用于控制吞吐量。</p>
<p><span style="background-color: #c0c0c0;">自适应调节</span>也是此回收器与ParNew的重要区别：-XX:+UseAdaptiveSizePolicy用于自动调整新生代大小、E/S比例、晋升阈值（-XX:PretenureSizeThreshold）来达到最合适的响应时间和吞吐量要求</p>
<p>使用-XX:+UseParallelGC打开，默认与Serial Old配合。在JMC中，该收集器显示为PS Scavenge</p>
<p>并行收集器（Parallel Scavenge / Parallel Old）的：</p>
<ol>
<li>优势：多线程扫描、整理堆</li>
<li>劣势：不管Minor/Full GC都STW</li>
</ol>
</td>
</tr>
<tr>
<td>Serial Old</td>
<td>
<p><span style="background-color: #c0c0c0;">STW的基于标记-清除-整理（Mark Sweep Compact）算法的单GC线程收集器</span>，专用于年老代（Tenured）</p>
<p>使用-XX:+UseSerialGC打开，该选项会同时打开Serial。在JMC中，该收集器显示为MarkSweepCompact</p>
</td>
</tr>
<tr>
<td>Parallel Old</td>
<td>
<p><span style="background-color: #c0c0c0;">基于标记-清除算法的多GC线程年老代收集器</span>，具有压缩功能，JDK1.6以后出现。主要用于配合Parallel Scavenge</p>
<p>使用-XX:+UseParallelOldGC打开，该选项会同时打开Parallel Scavenge。在JMC中，该收集器显示为PS MarkSweep</p>
</td>
</tr>
<tr>
<td>CMS</td>
<td>
<p>CMS (Concurrent Mark Sweep)，<span style="background-color: #c0c0c0;">低停顿的并发的标记-清除算法收集器</span>，<span style="background-color: #c0c0c0;">以获取最短回收停顿时间为目标</span>。B/S系统服务器适合使用CMS，工作流程分为以下4步骤：</p>
<ol>
<li>初始标记（CMS initial mark)，STW，标记GC Roots能直接到达的对象，很快</li>
<li>并发标记（CMS concurrent mark)，进行GC Root Tracing</li>
<li>重新标记（CMS remark)，<span style="background-color: #c0c0c0;"><strong>STW</strong></span>，修正并发标记期间，用户程序并发运行导致的对象记录变动，<span style="background-color: #c0c0c0;"><strong>比初始标记略长，默认单线程</strong></span></li>
<li>并发清除（CMS concurrent sweep)</li>
</ol>
<p>缺点：</p>
<ol>
<li>对CPU资源敏感：默认回收线程数=(CPU数量+3)/4，CPU不足4个时，CMS对用户程序代码影响较大</li>
<li>浮动垃圾问题：可能出现Concurrent Mode Failure而导致<span style="background-color: #c0c0c0;">自动使用Serial Old</span>进行Full GC。-XX:CMSInitiatingOccupancyFraction=68为默认值，可以调整以改变触发CMS的年老代内存占用比例</li>
<li>基于标记-清除算法，GC后产生大量碎片，可能因没有连续空间导致提前发生Full GC。-XX:+UseCMSCompactAtFullCollection可以在Full GC后进行碎片整理，-XX: CMSFullGCsBeforeCompaction用于执行多少次不压缩的Full GC后进行压缩</li>
</ol>
<p>使用-XX:+UseConcMarkSweepGC打开，该选项会自动打开ParNew。在JMC中，该收集器显示为MarkSweepCompact</p>
<p>并发模式失败：YGC要求提升对象到年老代，而后者没有足够的空间（没有足够的时间为其清理出空间）</p>
</td>
</tr>
<tr>
<td>G1</td>
<td>
<p>JDK1.6u14后出现，G1将整个Java堆（包括新生代、老年代）划分为多个大小固定的独立区域 (Region)，并且跟踪这些区域里面的垃圾堆积程度，在后台维护一个优先列表，每次根据允许的收集时间，优先回收垃圾最多的区域（这就是Garbage First名称的来由）</p>
<p>G1用于更好的支持大内存（4G+）</p>
<p>G1随时整理堆，而CMS只有在STW时才整理</p>
<p>从JDK 8u20开始G1支持字符串（包括底层char[]）去重，使用-XX:+UseStringDeduplicationJVM打开</p>
</td>
</tr>
</tbody>
</table>
<div class="blog_h3"><span class="graybg">内存分配和回收策略</span></div>
<ol>
<li>对象优先在Eden分配，如果Eden空间不足，发生Minor GC</li>
<li>大对象直接进入年老代：所谓大对象就是指，需要大量连续内存空间的Java对象（长字符串、数组）</li>
<li>长期存活对象进入年老代：所谓长期，是指经历多次Minor GC仍然存活</li>
<li>空间分配担保</li>
</ol>
<div class="blog_h3"><span class="graybg">Java引用的类型</span></div>
<ol>
<li>强引用：普通方式new的对象，均为强引用，这类对象不会被回收</li>
<li>软引用：系统将要发生内存溢出异常之前，将会把这些对象列进回收范围之中并进行第二 次回收。如果这次回收还是没有足够的内存，才会抛出内存溢出异常</li>
<li>弱引用：一旦垃圾回收器运作，即被回收，最多活到下一次垃圾回收之前</li>
<li>幻引用：一个对象是否 有虚引用的存在，完全不会对其生存时间构成影响，也无法通过虚引用来取得一个对象实例。为一个对象设置虚引用关联的唯一目的就是希望能在这个对象被收 集器回收时收到一个系统通知。</li>
</ol>
<div class="blog_h1"><span class="graybg">JVM执行子系统</span></div>
<div class="blog_h2"><span class="graybg">Class文件的结构</span></div>
<p>Class文件是一组以字节为基础单位的、格式紧凑的二进制流，如果某数据项需要超过8位，则按高位在前方式分割为若干字节存储。 </p>
<div class="blog_h3"><strong><span class="graybg">数据类型只包括2类</span></strong> </div>
<ol>
<li>无符号数：ul、u2、u4、u8分别代表1个字节、2个字节、 4个字节和8个字节的无符号数，无符号数可以用来描述数字、索引引用、数量值、Unicode编码的字符</li>
<li>表是以多个无符号数、其他表作为数据项构成的复合类型，一般以 _info结尾。整个Class文件就是一张表：<br />
<table style="width: 100%;" border="1" cellspacing="0" cellpadding="5">
<thead>
<tr>
<td style="width: 100px; text-align: center;"> 类型</td>
<td style="width: 150px; text-align: center;">名称</td>
<td style="text-align: center;">说明</td>
</tr>
</thead>
<tbody>
<tr>
<td>u4</td>
<td>magic</td>
<td>1个。用于确认是否为合法Class文件，为0xCAFEBABE</td>
</tr>
<tr>
<td>u2</td>
<td>minor_version</td>
<td>1个。次版本号</td>
</tr>
<tr>
<td>u2</td>
<td>major_version</td>
<td>1个。主版本号</td>
</tr>
<tr>
<td>u2</td>
<td>constant_pool_count</td>
<td>1个。记录常量池条目的数量</td>
</tr>
<tr>
<td>cpinfo</td>
<td>constant_pool</td>
<td>
<p>constant_pool_count - 1个。此容器的计数从1开始。主要包括两类常量：字面量（Literal)和符号引用（Symbolic Reference），字面量包括字符串、声明为final的常量值。符号引用包括：</p>
<ol>
<li>类和接口的全限定名（Fully Qualified Name)</li>
<li>字段的名称和描述符（Descriptor)</li>
<li>方法的名称和描述符</li>
</ol>
<p>Java与C不同，不存在"链接"的编译步骤，而是在JVM加载class文件时动态链接——class文件中不包含方法、字段 的内存布局信息——通过符号引用进行翻译，得到具体内存地址</p>
</td>
</tr>
<tr>
<td>u2</td>
<td>access_flags</td>
<td>1个。识别一些类或接口层次的访问信息，包括：这个Class是类还是接口 、是否定义为 public类型、是否定义为abstract类型、如果是类的话，是否被声明为final，等等</td>
</tr>
<tr>
<td>u2</td>
<td>this_class</td>
<td>1个。类索引（指向常量池）</td>
</tr>
<tr>
<td>u2</td>
<td>superclass</td>
<td>1个。父类索引（指向常量池）</td>
</tr>
<tr>
<td>u2</td>
<td>interfaces_count</td>
<td>1个。接口个数</td>
</tr>
<tr>
<td>u2</td>
<td>interfaces </td>
<td>interfaccs_count个。接口索引集合（指向常量池）</td>
</tr>
<tr>
<td>u2</td>
<td>fields_count</td>
<td>1个。字段个数</td>
</tr>
<tr>
<td>field_info</td>
<td>fields</td>
<td>
<p>fields_count个。字段表包含字段的各种限定符、描述符、名字索引等信息。字段表集合中不会列出从超类或父接口中继承而来的字段。</p>
<p>结构：</p>
<p>u2 access_flags 1，字段访问标记，参考下面的表格<br />u2 name_index 1，简单名称的索引<br />u2 descriptor_index，描述符的索引<br />u2 attributes_count，属性的个数<br />attribute_info attributes attributes_count 属性用于描述一些额外的信息</p>
</td>
</tr>
<tr>
<td>u2</td>
<td>methods_count</td>
<td>1个。方法个数</td>
</tr>
<tr>
<td>method_info</td>
<td>methods</td>
<td>
<p>methods_count个。方法表包含字段的各种限定符、描述符、名字索引等信息</p>
<p>结构：</p>
<p>u2 access_flags 1，方法访问标记，参考下面的表格<br />u2 name_index 1，简单名称的索引<br />u2 descriptor_index，描述符的索引<br />u2 attributes_count，属性的个数<br />attribute_info attributes attributes_count 属性用于描述一些额外的信息，包括表示方法的代码的Code属性。</p>
</td>
</tr>
<tr>
<td>u2</td>
<td>attributes_count</td>
<td>1个。</td>
</tr>
<tr>
<td>attribute_info</td>
<td>attributes</td>
<td>
<p>attributes_count个。属性表</p>
<p>结构：</p>
<p>u2 attribute_name_index 1 属性名称在常量池的索引<br />u2 attribute_length 1 属性长度<br />u1 info attribute_length 属性内容</p>
</td>
</tr>
</tbody>
</table>
</li>
</ol>
<div class="blog_h3"><span class="graybg">JVM版本对照表</span></div>
<table border="1" width="100%" cellspacing="0" cellpadding="0">
<tbody>
<tr>
<td valign="top">
<p align="center"><b><span lang="EN-US">JDK</span> 编译器版本</b></p>
</td>
<td valign="top">
<p align="center"><b><span lang="EN-US"> target</span> 参数</b></p>
</td>
<td valign="top">
<p align="center"><b>十六进制<span lang="EN-US">minor.major </span></b></p>
</td>
<td valign="top">
<p align="center"><b>十进制 <span lang="EN-US">minor.major</span></b></p>
</td>
</tr>
<tr>
<td valign="top">
<p align="left"><span lang="EN-US">jdk1.1.8</span></p>
</td>
<td valign="top">
<p align="left">不能带 <span lang="EN-US">target</span> 参数</p>
</td>
<td valign="top">
<p align="left"><span lang="EN-US">00 03 00 2D</span></p>
</td>
<td valign="top">
<p align="left"><span lang="EN-US">45.3</span></p>
</td>
</tr>
<tr>
<td valign="top">
<p align="left"><span lang="EN-US">jdk1.2.2</span></p>
</td>
<td valign="top">
<p align="left">不带<span lang="EN-US">(</span>默认为 <span lang="EN-US">-target 1.1)</span></p>
</td>
<td valign="top">
<p align="left"><span lang="EN-US">00 03 00 2D </span></p>
</td>
<td valign="top">
<p align="left"><span lang="EN-US">45.3 </span></p>
</td>
</tr>
<tr>
<td valign="top">
<p align="left"><span lang="EN-US">jdk1.2.2</span></p>
</td>
<td valign="top">
<p align="left"><span lang="EN-US">-target 1.2</span></p>
</td>
<td valign="top">
<p align="left"><span lang="EN-US">00 00  00 2E</span></p>
</td>
<td valign="top">
<p align="left"><span lang="EN-US">46.0 </span></p>
</td>
</tr>
<tr>
<td valign="top">
<p align="left"><span lang="EN-US">jdk1.3.1_19</span></p>
</td>
<td valign="top">
<p align="left">不带<span lang="EN-US">(</span>默认为 <span lang="EN-US">-target 1.1)</span></p>
</td>
<td valign="top">
<p align="left"><span lang="EN-US">00 03 00 2D</span></p>
</td>
<td valign="top">
<p align="left"><span lang="EN-US">45.3</span></p>
</td>
</tr>
<tr>
<td valign="top">
<p align="left"><span lang="EN-US">jdk1.3.1_19</span></p>
</td>
<td valign="top">
<p align="left"><span lang="EN-US">-target 1.3</span></p>
</td>
<td valign="top">
<p align="left"><span lang="EN-US">00 00  00 2F</span></p>
</td>
<td valign="top">
<p align="left"><span lang="EN-US">47.0 </span></p>
</td>
</tr>
<tr>
<td valign="top">
<p align="left"><span lang="EN-US">j2sdk1.4.2_10</span></p>
</td>
<td valign="top">
<p align="left">不带<span lang="EN-US">(</span>默认为 <span lang="EN-US">-target 1.2) </span></p>
</td>
<td valign="top">
<p align="left"><span lang="EN-US">00 00  00 2E</span></p>
</td>
<td valign="top">
<p align="left"><span lang="EN-US">46.0 </span></p>
</td>
</tr>
<tr>
<td valign="top">
<p align="left"><span lang="EN-US">j2sdk1.4.2_10 </span></p>
</td>
<td valign="top">
<p align="left"><span lang="EN-US">-target 1.4 </span></p>
</td>
<td valign="top">
<p align="left"><span lang="EN-US">00 00  00 30</span></p>
</td>
<td valign="top">
<p align="left"><span lang="EN-US">48.0 </span></p>
</td>
</tr>
<tr>
<td valign="top">
<p align="left"><span lang="EN-US">jdk1.5.0_11 </span></p>
</td>
<td valign="top">
<p align="left"><span lang="EN-US"> </span>不带<span lang="EN-US">(</span>默认为 <span lang="EN-US">-target 1.5) </span></p>
</td>
<td valign="top">
<p align="left"><span lang="EN-US">00 00  00 31 </span></p>
</td>
<td valign="top">
<p align="left"><span lang="EN-US">49.0</span></p>
</td>
</tr>
<tr>
<td valign="top">
<p align="left"><span lang="EN-US">jdk1.5.0_11 </span></p>
</td>
<td valign="top">
<p align="left"><span lang="EN-US">-target 1.4 -source 1.4 </span></p>
</td>
<td valign="top">
<p align="left"><span lang="EN-US">00 00  00 30</span></p>
</td>
<td valign="top">
<p align="left"><span lang="EN-US">48.0 </span></p>
</td>
</tr>
<tr>
<td valign="top">
<p align="left"><span lang="EN-US">jdk1.6.0_01</span></p>
</td>
<td valign="top">
<p align="left">不带<span lang="EN-US">(</span>默认为 <span lang="EN-US">-target 1.6)</span></p>
</td>
<td valign="top">
<p align="left"><span lang="EN-US">00 00  00 32  </span></p>
</td>
<td valign="top">
<p align="left"><span lang="EN-US">50.0</span></p>
</td>
</tr>
<tr>
<td valign="top">
<p align="left"><span lang="EN-US">jdk1.6.0_01 </span></p>
</td>
<td valign="top">
<p align="left"><span lang="EN-US">-target 1.5</span></p>
</td>
<td valign="top">
<p align="left"><span lang="EN-US">00 00  00 31 </span></p>
</td>
<td valign="top">
<p align="left"><span lang="EN-US">49.0</span></p>
</td>
</tr>
<tr>
<td valign="top">
<p align="left"><span lang="EN-US">jdk1.6.0_01</span></p>
</td>
<td valign="top">
<p align="left"><span lang="EN-US">-target 1.4 -source 1.4  </span></p>
</td>
<td valign="top">
<p align="left"><span lang="EN-US">00 00  00 30</span></p>
</td>
<td valign="top">
<p align="left"><span lang="EN-US">48.0</span></p>
</td>
</tr>
<tr>
<td valign="top">
<p align="left"><span lang="EN-US">jdk1.6.0_01 </span></p>
</td>
<td valign="top">
<p align="left">不带<span lang="EN-US">(</span>默认为 <span lang="EN-US">-target 1.6) </span></p>
</td>
<td valign="top">
<p align="left"><span lang="EN-US">00 00  00 32 </span></p>
</td>
<td valign="top">
<p align="left"><span lang="EN-US">50.0</span></p>
</td>
</tr>
<tr>
<td valign="top">
<p align="left"><span lang="EN-US">jdk1.7.0</span></p>
</td>
<td valign="top">
<p align="left">不带<span lang="EN-US">(</span>默认为 <span lang="EN-US">-target 1.6)</span></p>
</td>
<td valign="top">
<p align="left"><span lang="EN-US">00 00  00 32 </span></p>
</td>
<td valign="top">
<p align="left"><span lang="EN-US">50.0 </span></p>
</td>
</tr>
<tr>
<td valign="top">
<p align="left"><span lang="EN-US">jdk1.7.0</span></p>
</td>
<td valign="top">
<p align="left"><span lang="EN-US">-target 1.7</span></p>
</td>
<td valign="top">
<p align="left"><span lang="EN-US">00 00  00 33</span></p>
</td>
<td valign="top">
<p align="left"><span lang="EN-US">51.0 </span></p>
</td>
</tr>
<tr>
<td valign="top">
<p align="left"><span lang="EN-US">jdk1.7.0 </span></p>
</td>
<td valign="top">
<p align="left"><span lang="EN-US"> -target 1.4 -source 1.4</span></p>
</td>
<td valign="top">
<p align="left"><span lang="EN-US">00 00  00 30 </span></p>
</td>
<td valign="top">
<p align="left"><span lang="EN-US">48.0 </span></p>
</td>
</tr>
</tbody>
</table>
<div class="blog_h3"><span class="graybg">常量池</span></div>
<p>常量池是Class文件结构中与其他项目关联最多的数据类型，也是占用Class文件空间最大的数据项目之一。</p>
<p>常量池中的每一项常量都是一个表，共有<span style="background-color: #c0c0c0;">11种结构各不相同的表结构数据</span>，这11 种表都有一个共同的特点，就是表开始的<span style="background-color: #c0c0c0;">第一位是一个u1类型的标志位</span>，代表当前这个常量属于哪种常量类型：</p>
<table style="width: 100%;" border="1" cellspacing="0" cellpadding="5">
<thead>
<tr>
<td style="width: 250px; text-align: center;">类型 </td>
<td style="width: 30px; text-align: center;"> </td>
<td style="text-align: center;"> 描述</td>
</tr>
</thead>
<tbody>
<tr>
<td>CONSTANT_Utf8_info</td>
<td>1</td>
<td>
<p>UTF-8编码的字符串</p>
<p>u1 tag 1<br />u2 length 1，字符串长度为多少字节<br />u1 bytes length 使用UTF-8缩略编码的字符串内容</p>
</td>
</tr>
<tr>
<td>CONSTANT_Integer_info</td>
<td>3 </td>
<td>整型字面量，高位在前</td>
</tr>
<tr>
<td>CONSTANT_Float_info</td>
<td>4 </td>
<td>浮点型字面量，高位在前</td>
</tr>
<tr>
<td>CONSTANT_Long_info</td>
<td>5 </td>
<td>长整型字面量，高位在前</td>
</tr>
<tr>
<td>CONSTANT_Doublc_info</td>
<td>6 </td>
<td>双精度浮点型字面量，高位在前</td>
</tr>
<tr>
<td>CONSTANT_Class_info</td>
<td>7 </td>
<td>
<p>类或接口的符号引用</p>
<p>u1 tag 1<br />u2 name index 1：指向CONSTANT_Utf8_info类型的常量，相对于常量池的偏移量</p>
</td>
</tr>
<tr>
<td>CONSTANT_String_info</td>
<td>8 </td>
<td>字符串类型字面量，指向字符串字面量的索引</td>
</tr>
<tr>
<td>CONSTANT_Fieldref_info</td>
<td>9 </td>
<td>
<p>字段的符号引用</p>
<p>tag u1<br />index u2 指向声明字段的类或接口描述符CONSTANTS_Class_info的索引项<br />index u2 指向字段描述符CONSTANT_NameAndType的索引项</p>
</td>
</tr>
<tr>
<td>CONSTANT_Methodref_info</td>
<td>10 </td>
<td>
<p>类中方法的符号引用</p>
<p>tag u1<br />index u2 指向声明方法的类描述符CONSTANT_Class_info 的索引项<br />index u2 指向名称及类型描述符CONSTANT_NameAndType的索引项</p>
</td>
</tr>
<tr>
<td>CONSTANT_InterfaceMethodref_info</td>
<td>11</td>
<td>
<p>接口中方法的符号引用</p>
<p>tag u1<br />index u2 指向声明方法的类描述符CONSTANT_Class_info 的索引项<br />index u2 指向名称及类型描述符CONSTANT_NameAndType的索引项</p>
</td>
</tr>
<tr>
<td>CONSTANT_NameAndType_info</td>
<td>12</td>
<td>
<p>字段或方法的部分符号引用</p>
<p>tag u1<br />index u2 指向该字段或方法名称常量项的索引<br />index u2 指向该字段或方法描述符常量项的索引</p>
</td>
</tr>
</tbody>
</table>
<div class="blog_h3"><strong><span class="graybg">类访问标记</span></strong></div>
<p>在常量池结束之后，紧接着的2个字节代表访问标志（access_flags)：</p>
<table style="width: 100%;" border="1" cellspacing="0" cellpadding="5">
<thead>
<tr>
<td style="text-align: center;">标志名称 </td>
<td style="text-align: center;">标志值 </td>
<td style="text-align: center;"> 说明</td>
</tr>
</thead>
<tbody>
<tr>
<td> ACC_PUBLIC</td>
<td> 0x0001</td>
<td> 是否为public类型</td>
</tr>
<tr>
<td> ACC_FINAL</td>
<td> 0x0010</td>
<td> 是否被声明为final,只有类可设置</td>
</tr>
<tr>
<td> ACC_SUPER</td>
<td> 0x0020</td>
<td> 是否允许使用invokespecial字节码指令</td>
</tr>
<tr>
<td> ACC_INTERFACE</td>
<td> 0x0200</td>
<td> 标识这是一个接口</td>
</tr>
<tr>
<td> ACC_ABSTRACT</td>
<td> 0x0400</td>
<td> 是否为abstract类型，对于接口或抽象类来说值为真</td>
</tr>
<tr>
<td> ACC_SYNTHETIC</td>
<td> 0x1000</td>
<td> 标识这个类并非由用户代码产生的</td>
</tr>
<tr>
<td> ACC_ANNOTATION</td>
<td> 0x2000</td>
<td> 标识这是一个注解</td>
</tr>
<tr>
<td> ACC_ENUM</td>
<td> 0x4000</td>
<td> 标识这是一个枚举</td>
</tr>
</tbody>
</table>
<p>&nbsp;</p>
<div class="blog_h3"><strong><span class="graybg">字段访问标记</span></strong></div>
<p>&nbsp;</p>
<p>字段表的前两个字节：</p>
<table style="width: 100%;" border="1" cellspacing="0" cellpadding="5">
<thead>
<tr>
<td style="text-align: center;">标志名称 </td>
<td style="text-align: center;">标志值 </td>
<td style="text-align: center;"> 说明</td>
</tr>
</thead>
<tbody>
<tr>
<td>ACC_PUBLIC</td>
<td> 0x0001</td>
<td>字段是否public</td>
</tr>
<tr>
<td>ACC_PRIVATE</td>
<td> 0x0002</td>
<td>字段是否pravate</td>
</tr>
<tr>
<td>ACC_PROTECTED</td>
<td> 0x0004</td>
<td>字段是否protected</td>
</tr>
<tr>
<td>ACC_STATIC</td>
<td> 0x0008</td>
<td>字段是否static</td>
</tr>
<tr>
<td>ACC_FINAL</td>
<td> 0x0010</td>
<td>字段是否final</td>
</tr>
<tr>
<td>ACC_VOLATILE</td>
<td> 0x0040</td>
<td>字段是否volatile</td>
</tr>
<tr>
<td>ACC_TRANSIENT</td>
<td> 0x0080</td>
<td>字段是否transient</td>
</tr>
<tr>
<td>ACC_SYNTHETIC</td>
<td> 0x1000</td>
<td>字段是否由编译器自动产生的</td>
</tr>
<tr>
<td>ACC_ENUM</td>
<td> 0x4000</td>
<td>字段是否enum</td>
</tr>
</tbody>
</table>
<div class="blog_h3"><span class="graybg">方法访问标记</span></div>
<p>方法表的前两个字节：</p>
<table style="width: 100%;" border="1" cellspacing="0" cellpadding="5">
<thead>
<tr>
<td style="text-align: center;">标志名称 </td>
<td style="text-align: center;">标志值 </td>
<td style="text-align: center;"> 说明</td>
</tr>
</thead>
<tbody>
<tr>
<td>ACC_PUBLIC</td>
<td>0x0001</td>
<td>方法是否public</td>
</tr>
<tr>
<td>ACC_PRIVATE</td>
<td>0x0002</td>
<td>方法是否pravate</td>
</tr>
<tr>
<td>ACC_PROTECTED</td>
<td>0x0004</td>
<td>方法是否protected</td>
</tr>
<tr>
<td>ACC_STATIC</td>
<td>0x0008</td>
<td>方法是否static</td>
</tr>
<tr>
<td>ACC_FINAL</td>
<td>0x0010</td>
<td>方法是否final</td>
</tr>
<tr>
<td>ACC_SYNCHRONIZED</td>
<td>0x0020</td>
<td>方法是否synchronized</td>
</tr>
<tr>
<td>ACC_BRIDGE</td>
<td>0x0040</td>
<td>方法是否为编译器产生的桥接方法</td>
</tr>
<tr>
<td>ACC_VARARGS</td>
<td>0x0080</td>
<td>方法是否接受不定参数</td>
</tr>
<tr>
<td>ACC_NATIVE</td>
<td>0x0100</td>
<td>方法是否为native</td>
</tr>
<tr>
<td>ACC_ABSTRACT</td>
<td>0x0400</td>
<td>方法是否为abstract</td>
</tr>
<tr>
<td>ACC_STRICT</td>
<td>0x0800</td>
<td>方法是否为strict</td>
</tr>
<tr>
<td>ACC_SYNTHETIC</td>
<td>0x1000</td>
<td>方法是否是由编译器自动产生的</td>
</tr>
</tbody>
</table>
<div class="blog_h3"><span class="graybg"><a id="type-id-in-jvm"></a>字段与方法描述符 </span></div>
<p>描述符标识符列表：</p>
<table style="width: 100%;" border="1" cellspacing="0" cellpadding="5">
<thead>
<tr>
<td style="width: 100px; text-align: center;"> 标识符</td>
<td style="text-align: center;">含义 </td>
</tr>
</thead>
<tbody>
<tr>
<td> B</td>
<td>基本类型byte</td>
</tr>
<tr>
<td> C</td>
<td>基本类型char</td>
</tr>
<tr>
<td> D</td>
<td>基本类型double</td>
</tr>
<tr>
<td> F</td>
<td>基本类型float </td>
</tr>
<tr>
<td> I</td>
<td>基本类型int </td>
</tr>
<tr>
<td> J </td>
<td>基本类型long </td>
</tr>
<tr>
<td> S</td>
<td>基本类型short </td>
</tr>
<tr>
<td> Z</td>
<td>基本类型boolean </td>
</tr>
<tr>
<td> V</td>
<td>特殊类型void</td>
</tr>
<tr>
<td> L</td>
<td>对象类型，如Ljava/lang/Object;</td>
</tr>
<tr>
<td> [</td>
<td>
<p>表示数组的前缀。例如java.lang.String[][] 表示为 [[Ljava/lang/String;</p>
</td>
</tr>
</tbody>
</table>
<p>描述方法时，按如下规则：</p>
<ol>
<li>先参数列表，后返回值。例如：void ific()描述为()V</li>
<li>参数按声明顺序放置于()内。例如：int compare(Object o1,Object o2)描述为(Ljava/lang/ObjectLjava/lang/Object)I</li>
</ol>
<div class="blog_h3"><strong><span class="graybg">属性表集合</span></strong></div>
<p>在Class文件、字段 表、方法表中都可以携带自己的属性表集合，以用于描述某些场景专有的信息。JVM规范中预定义了9项虚拟机实现应当能识別的属性：</p>
<table style="width: 100%;" border="1" cellspacing="0" cellpadding="5">
<thead>
<tr>
<td style="text-align: center;">属性名称 </td>
<td style="text-align: center;">使用位置 </td>
<td style="text-align: center;"> 说明</td>
</tr>
</thead>
<tbody>
<tr>
<td> Code</td>
<td> 方法表</td>
<td>
<p>Java代码编译成的字节码指令</p>
<p>结构：</p>
<p>u2 attribute_name_index 1，固定为"Code"<br />u4 attribute_length 1 <br />u2 maxstack 1 操作数栈最大深度<br />u2 max_locals 1 局部变量表所需的存储空间，单位为Slot<br />u4 code_length 1<br />ul code code_length 存放字节码指令<br />u2 exception_table_length 1<br />exception_info exception_table exception_table_length<br />u2 attributes_count 1<br />attribute_info attributes attributes_count </p>
</td>
</tr>
<tr>
<td> ConstantValue</td>
<td> 字段表</td>
<td> final关键字定义的常量值</td>
</tr>
<tr>
<td> Deprecated</td>
<td> 类、方法表、字段表</td>
<td> 被声明为deprecated的方法和字段</td>
</tr>
<tr>
<td> Exceptions</td>
<td> 方法表</td>
<td> 方法抛出的异常</td>
</tr>
<tr>
<td> InnerClasses</td>
<td> 类文件</td>
<td> 内部类列表</td>
</tr>
<tr>
<td> LineNumberTable</td>
<td> Code属性</td>
<td> Java源码的行号与字节码指令的对应关系</td>
</tr>
<tr>
<td> LocalVariableTable</td>
<td> Code属性</td>
<td> 方法的局部变量描述</td>
</tr>
<tr>
<td> SourceFile</td>
<td> 类文件</td>
<td> 源文件的名称</td>
</tr>
<tr>
<td> Synthetic</td>
<td> 类、方法表、宇段表</td>
<td> 标记方法或字段为编译器自动生成的</td>
</tr>
</tbody>
</table>
<div class="blog_h2"><span class="graybg">类加载机制</span></div>
<div class="blog_h3"><span class="graybg">Java类的生命周期</span></div>
<p><strong> <img class="size-full wp-image-2926 aligncenter" style="width: 80%;" src="https://blog.gmem.cc/wp-content/uploads/2012/06/jvm-study.png" alt="jvm-study" /></strong></p>
<ol>
<li>加载：JVM规范没有规定何时加载类，实行根据需要决定。加载阶段需要完成3件事：<br />a) 通过一个类的全限定名来获取定义此类的二进制字节流<br />b) 将这个字节流所代表的静态存储结构转化为方法区的运行时数据结构<br />c) 在Java堆中生成一个代表这个类的java.lang.Class对象，作为方法区这些数据的访问入口</li>
<li>验证：确保Class文件的字节流中包含的信息符合当前虚拟机的要求，并且不会危害虚拟机自身的安全。包括文件格式验证、元数据验证、字节码验证、符号引用验证等步骤</li>
<li>准备：为类变量分配内存并设置类变量初始值，这些内存都在<span style="background-color: #c0c0c0;">方法区</span>中分配。</li>
<li>解析：是将常量池内的符号引用替换为直接引用的过程。包括接口和类解析、字段解析、类方法解析、接口方法解析</li>
<li>初始化：是执行类构造方法()的过程（此方法收集静态变量赋值、static代码块自动生成），虚拟机保证多线程环境下()方法被正确的加锁与同步。以下情况，如果类尚未初始化，则需要触发初始化。遇到 new、getstatic、putstatic 或 invokestatic 这 4 条字节码指令时；当通过反射调用时；父类未初始化时，首先初始化父类；虚拟机启动时，初始化main函数所在类</li>
</ol>
<div class="blog_h3"><strong><span class="graybg">类加载器</span></strong> </div>
<p>比较两个类是否“相 等”，只有在<span style="background-color: #c0c0c0;">这两个类是由同一个类加载器加载</span>的前提之下才有意义。</p>
<p>从JVM的角度，类加载器只分为两类：一种是启动类加载器 (Bootstrap ClassLoader)，这个类加栽器使用C++语言实现，是虚拟机自身的一部分； 另外一种就是所有其他的类加载器，这些类加栽器都由Java语言实现且全都继承自抽象类java.lang.ClassLoader。</p>
<p>从开发人员角度，类加载器可以细分为：</p>
<table style="width: 100%;" border="1" cellspacing="0" cellpadding="5">
<thead>
<tr>
<td style="width: 200px; text-align: center;">类加载器</td>
<td style="text-align: center;">说明 </td>
</tr>
</thead>
<tbody>
<tr>
<td>启动类加载器<br />Bootstrap ClassLoader</td>
<td>负责将<span style="background-color: #c0c0c0;">$JAVA_HOME\lib</span>目录中的、或者被<span style="background-color: #c0c0c0;">-Xbootclasspath</span>参数所指定的路径中的，并且是虚拟机识别的（<span style="background-color: #c0c0c0;">仅按照文件名识别</span>，如rt.jar）类库加载到虚拟机内存中</td>
</tr>
<tr>
<td>
<p>扩展类加栽器<br />Extension ClassLoader</p>
</td>
<td>由<span style="background-color: #c0c0c0;">sun.misc.Launcher$ExtClassLoader</span>实现，它负责加载<span style="background-color: #c0c0c0;">$JAVA_HOME\lib\ext</span>目录中的、或者被 <span style="background-color: #c0c0c0;">java.ext.dirs</span>系统变最所指定的路径中的<span style="background-color: #c0c0c0;">所有类库</span></td>
</tr>
<tr>
<td>
<p>应用程序类加栽器<br />Application ClassLoader)</p>
</td>
<td>由<span style="background-color: #c0c0c0;">sun.misc. Launcher$AppClassLoader</span>来实现，ClassLoader中.getSystemClassLoader()的返回值即为此加载器，一般也称为<span style="background-color: #c0c0c0;">系统类加载器</span>。负责加载CLASSPATH上所指定的类库，如果应用程序中没有自定义过自己的类加载器，一般情况下这个就是程序中 默认的类加栽器。</td>
</tr>
</tbody>
</table>
<p>所谓双亲委派模型，指出了启动类加载器外，所有ClassLoader都可通过getParent()得到父加载器。通常，如果一个类加载器收到了类加载的请求，它<span style="background-color: #c0c0c0;">首先不会自己去尝试加载这个类，而是把这个请求委派给父类加载器去完成</span>，每一个层次的类加 载器都是如此，因此所有的加载请求最终都应该传送到顶层的启动类加载器中，只有当 父加载器反馈自己无法完成这个加载请求时，子加载器才会尝试自己加载。</p>
<p>线程<span style="background-color: #c0c0c0;">上下文 类加载器（Thread Context ClassLoader)</span>可以通过java.lang.Thread类的 setContextClassLoader()方法进行设置，如果创建线程时还未设置，<span style="background-color: #c0c0c0;">它将会从父线程中继承</span>。</p>
<div class="blog_h2"><span class="graybg">虚拟机字节码执行引擎</span></div>
<div class="blog_h3"><span class="graybg">运行时栈帧结构</span></div>
<p><span style="background-color: #c0c0c0;">栈帧（Stack Frame)是用于支持JVM进行方法调用和方法执行的数据结构</span>，是JVM运行时数据区中的<span style="background-color: #c0c0c0;">虚拟机栈的栈元素</span>。栈帧存储了方法的<span style="background-color: #c0c0c0;">局部变量表、操作数栈、动态链接和方法返回地址</span>等信息。方法从调用开始到执行完成的过程，就对应着一个<span style="background-color: #c0c0c0;">栈帧在虚拟机栈里面从入栈到出栈</span>的过程。对于执行引擎来讲，只有<span style="background-color: #c0c0c0;">栈顶的栈帧是有效的，称为当前栈帧（Current Stack Frame)，这个栈帧所关联的方法称为当前方法（Current Method)。</span>执行引擎所运行的<span style="background-color: #c0c0c0;">所有字节码指令都只针对当前栈帧</span>进行操作，栈帧结构示意图如下：<br /><img class="size-full wp-image-2939 aligncenter" style="width: 80%;" src="https://blog.gmem.cc/wp-content/uploads/2012/06/jvm-5.png" alt="jvm-5" /></p>
<div class="blog_h3"><span class="graybg">局部变量表</span></div>
<p>局部变量表的容量以<span style="background-color: #c0c0c0;">变量槽（Variable Slot,下称Slot)为最小单位</span>，每个Slot 都应该能存放一个 boolean、byte、char、short、int、float、reference 或 retumAddress 类型的数据（即一般的说Slot大小为32bits）</p>
<p>虚拟机通过索引定位的方式使用局部变量表，索引值的范围是从0开始到局部变量 表最大的Slot数量。对于Long、Double占用2个Slot，高位在前</p>
<p>对于块级作用域的变量，其Slot可以被重用</p>
<div class="blog_h3"><span class="graybg">操作数栈</span></div>
<p>也称为操作栈，每个栈元素可以是任意Java类型，Long、Double占用两个栈容量。当方法开始执行时，操作数栈是空的，其后会有各种字节码指令<span style="background-color: #c0c0c0;">向操作数栈中写入和提取内容，也就是入栈出栈操作</span>。例如， 在做算术运算的时候是通过操作数栈来进行的，又或者在<span style="background-color: #c0c0c0;">调用其他方法的时候是通过操作数栈来进行参数传递</span>的。</p>
<div class="blog_h3"><span class="graybg">动态链接</span></div>
<p>每个栈帧都包含一个指向运行时常量池中该栈帧所属方法的引用，持有这个引用 是为了支持方法调用过程中的动态连接</p>
<div class="blog_h3"><span class="graybg">方法返回地址</span></div>
<p>方法退出有两种方式：</p>
<ol>
<li>执行引擎遇到方法返回的字节码指令，这时候可能会有返回值传递给上层的方法调用者，这种退出方法的方式称为正常完成出口</li>
<li>方法执行过程中遇到了异常，并且这个异常<span style="background-color: #c0c0c0;">没有在方法体内得到处理</span>，无论是Java虚拟机内部产生的异常，还是代码中使用athrow字节码指令 产生的异常，只要在本方法的异常表中没有<span style="background-color: #c0c0c0;">搜索到匹配的异常处理器</span>，就会导致方法退出，这种退出方法的方式称为异常完成出口</li>
</ol>
<p>方法退出后需要返回到方法被调用的位置，程序才能继续执行，方法返回时可能需要在栈帧中保存一些信息，用来帮助恢复它的上层方法的执行状态。一般来说，<span style="background-color: #c0c0c0;">方法正常退出时，调用者的PC计数器的值就可以作为返回地址</span>，栈帧中很可能会保存这个计数器值。而方法异常退出时，返回地址是<span style="background-color: #c0c0c0;">要通过异常处理器表来确定</span>。方法退出时可能执行的操作有：</p>
<ol>
<li>恢复上层方法的局部变量表和操作数栈</li>
<li>把返回值（如果有的话）压入调用者栈帧的操作数栈中</li>
<li>调整PC计数器的值以指向方法调用指令后面的一条指令</li>
</ol>
<div class="blog_h1"><span class="graybg">高效并发</span></div>
<div class="blog_h2"><span class="graybg">Java内存模型</span> </div>
<div class="blog_h3"><span class="graybg">主内存与工作内存</span></div>
<p>为了获得较好的执行效能，JMM不限制执行引擎使用处理器的<span style="background-color: #c0c0c0;">特定寄存器或缓存来和主内存进行交互</span>，也没有限制<span style="background-color: #c0c0c0;">即时编译器调整代码执行顺序</span>。</p>
<p>JMM规定了<strong>所有的变量都存储在主内存（Main Memory，相当于物理内存)</strong>中。每条<strong>线程</strong>还有自己的<strong>工作内存（Working Memory，相当于处理器高速缓存、寄存器）</strong>，线程的<strong>工作内存中保存</strong>了被该线程使用到的<strong>变量的主内存副本拷贝</strong>， 线程对<strong>变量的所有操作</strong>（读取、赋值等）都必须<strong>在工作内存中进行</strong>，而不能直接读写主内存中的变量。不同的<strong>线程之间也无法直接访问对方工作内存中的变量</strong>，线程间变量值的传递<strong>均需要通过主内存</strong>来完成。</p>
<div class="blog_h3"><span class="graybg">内存间交互操作</span></div>
<p>JMM定义了<span style="background-color: #c0c0c0;">8种原子性操作</span>来确定工作内存与主内存如何交互：</p>
<ol>
<li>lock (锁定）：作用于主内存的变量，它把一个变量标识为一条线程独占的状态</li>
<li>unlock (解锁）：作用于主内存的变量，它把一个处于锁定状态的变量释放出来， 释放后的变量才可以被其他线程锁定</li>
<li>read (读取）：作用于主内存的变量，它把一个变量的值从主内存传输到线程的 工作内存中，以便随后的load动作使用</li>
<li>load (载入）：作用于工作内存的变量，它把read操作从主内存中得到的变量值放入工作内存的变量副本中</li>
<li>use (使用）：作用于工作内存的变量，它把工作内存中一个变量的值传递给执 行引擎，每当虚拟机遇到一个需要使用到变量的值的字节码指令时将会执行这个操作</li>
<li>assign (赋值作用于工作内存的变量，它把一个从执行引擎接收到的值陚值 给工作内存的变量，每当虚拟机遇到一个给变量陚值的字节码指令时执行这个操作</li>
<li>store (存储）：作用于工作内存的变董，它把工作内存中一个变量的值传送到主内存中，以便随后的write操作使用</li>
<li> write (写入）：作用于主内存的变量，它把store操作从工作内存中得到的变量的值放入主内存的变量中</li>
</ol>
<p>JMM还规定了在执行上述八种基本操作时必须满足如下规则：</p>
<ol>
<li>不允许read和load、store和write操作之一单独出现，即不允许一个变量从主内存读取了但工作内存不接受，或者从工作内存发起回写了但主内存不接受的情况出现</li>
<li>不允许一个线程丢弃它的最近的assign操作，即变量在工作内存中改变了之后必须把该变化同步回主内存</li>
<li>不允许一个线程无原因地（没有发生过任何assign操作）把数据从线程的工作内存同步回主内存中</li>
<li>一个新的变量只能在主内存中“诞生”，不允许在工作内存中直接使用一个未被初始化（load或assign)的变量，换句话说就是对一个变量实施use和store操作之前，必须先执行过了 assign和load操作</li>
<li>一个变量在同一个时刻只允许一条线程对其进行lock操作，但lock操作可以被同一条线程重复执行多次，多次执行lock后，只有执行相同次数的unlock操作， 变量才会被解锁</li>
<li>如果对一个变量执行lock操作，将会清空工作内存中此变量的值，在执行引擎使用这个变量前，需要重新执行load或assign操作初始化变量的值</li>
<li>如果一个变量事先没有被lock操作锁定，则不允许对它执行unlock操作，也不允许去unlock一个被其他线程锁定住的变量</li>
<li>对一个变量执行unlock操作之前，必须先把此变量同步回主内存中（执行sotre 和write操作）</li>
</ol>
<div class="blog_h3"><span class="graybg">对于volatile型变量的特殊规则</span></div>
<p>关键字volatile可以说是Java虚拟机提供的<span style="background-color: #c0c0c0;">最轻量级的同步机制</span>。</p>
<p>当一个变量被定义成volatile之后，它将具备两种特性：</p>
<ol>
<li><span style="background-color: #c0c0c0;">第一是保证此变量对所有线程的可见性</span>，这里的“可见性”是指当一条线程修改了这个变量的值，新值对于<span style="background-color: #c0c0c0;">其他线程来说是可以立即得知</span>的。而普通变量不能做到这一点，变量值在线程间传递均需要通过主内存来完成，如：线程A修改一个普通变量的值，然后向主内存进行回写，另外一条线程B在线程A回写完成了之后再从主内存进行读取操作，新变量的值才会对线程B可见。</li>
<li><span style="background-color: #c0c0c0;">第二是禁止指令重排序优化</span>，<span style="background-color: #c0c0c0;">普通的变量仅仅会保证在该方法的执行过程中所有依赖赋值结果的地方都能获取到正确的结果</span>，而不能保证变 量<span style="background-color: #c0c0c0;">赋值操作的顺序与程序代码中的执行顺序</span>一致</li>
</ol>
<p>但是<span style="background-color: #c0c0c0;">volatile并不保证操作的原子性</span>，在<span style="background-color: #c0c0c0;">不符合</span>以下两条规则的运算场景中，仍要通过加锁来保证原子性：</p>
<ol>
<li>运算结果并不依赖变量的当前值（例如简单setter），或者能够确保只有单一的线程修改变量的值</li>
<li>变量不需要与其他的状态变量共同参与不变约束</li>
</ol>
<div class="blog_h3"><span class="graybg">对于long和double型变量的特殊规则</span></div>
<p>对于64位的数据类型（long和double)，JMM允许虚拟机将没有被volatile修饰的64位数据的<span style="background-color: #c0c0c0;">读写操作划分为两次进行</span>。但是实际上，商业JVM基本上都把64位数据的读写操作作为原子操作实现。</p>
<div class="blog_h3"><span class="graybg">原子性、可见性与有序性</span></div>
<ol>
<li>原子性（Atomicity）：由Java内存模型来直接保证的原子性变量操作包括read、 load、assign、use、store和write这六个，我们大致可以认为<span style="background-color: #c0c0c0;">基本数据类型的访问读写是具备原子性</span>的。如果需要在大范围实现原子性，lock、unlock操作可以完成（对应JVM指令monitorenter 、monitorexit，在代码上反映为<span style="background-color: #c0c0c0;">Synchronized代码块</span>）</li>
<li>可见性（Visibility）：当一个线程修改了共享变量的值，其他线程能够 立即得知这个修改。volatile保证了多线程 操作时变置的可见性，而普通变量则不能保证这一点。synchronized、final也可以实现可见性</li>
<li>有序性（Ordering)：<span style="background-color: #c0c0c0;">天然的有序性：如果在本线程内观察，所有的操作都是有序的</span>。在另一个线程观察，<span style="background-color: #c0c0c0;">所有的操作都是无序的</span>——指令重排、工作内存和主内存同步延迟的影响导致无序。volatile、synchronized提供有序性保证</li>
</ol>
<div class="blog_h3"><span class="graybg">先行发生原则</span></div>
<p>“先行发生”（happens-before)的原则非常重 要，它是判断数据<span style="background-color: #c0c0c0;">是否存在竞争，线程是否安全</span>的主要依据。下面是Java内存模型下一些“天然的”先行发生关系（无需任何同步保证手段）：</p>
<ol>
<li>程序次序规则（Program Order Rule)：在一个线程内，按照程序代码顺序，书写在前面的操作先行发生于书写在后面的操作</li>
<li>监视器锁定规则（Monitor Lock Rule)：一个unlock操作先行发生于后面对同一个锁的lock操作。这里必须强调的是同一个锁，而“后面”是指时间上的先后顺序</li>
<li>volatile变量规则 (Volatile Variable Rule)：对一个volatile变量的写操作先行发生于后面对这个变量的读操作，这里的“后面”同样是指时间上的先后顺序</li>
<li>线程启动规则（Thread Start Rule) ：Thread对象的start()方法先行发生于此线程的每一个动作</li>
<li>线程终止规则（Thread Termination Rule)：线程中的所有操作都先行发生于对此线程的终止检测，我们可以通过Thread.join()方法结束、Thread.isAlive()的返回值等手段检测到线程已经终止执行</li>
<li>线程中断规则（Thread Interruption Rule)：对线程interrupt()方法的调用先行发生于被中断线程的代码检测到中断事件的发生，可以通过Thread.interrupted()方法检测到是否有中断发生</li>
<li>对象终结规则（Hnalizer Rule)：一个对象的初始化完成（构造函数执行结束）先行发生于它的finalize()方法的开始</li>
<li>传递性（Transitivity)：如果操作A先行发生于操作B，操作B先行发生于操作 C，那么操作A先行发生于操作C</li>
</ol>
<div class="blog_h2"><span class="graybg">线程</span></div>
<p>Java中线程的实现具有以下几种方式：</p>
<ol>
<li>使用内核线程实现。内核线程（Kernel Thread, KLT）就是直接由操作系统内核支持的线程，这种线程由内核来完成线程切换，内核通过操纵调度器（Scheduler)对线程进行调度，并负责<span style="background-color: #c0c0c0;">将线程的任务映射到各个处理器上</span>。<br />程序一般不会直接去使用内核线程，而是去使用内核线程的一种髙级接口——<span style="background-color: #c0c0c0;">轻量级进程（Light Weight Process, LWP)。</span>轻量级进程就是我们通常意义上所讲的线程，由于每个轻量级进程都由一个内核线程支持，因此只有先支持内核线程，才能有轻量级进程。这种轻量级进程与内核线程之间1:1的关系称为一对一的线程模型</li>
<li>使用用户线程实现。狭义上的用户线程指的是完全建立在用户空间的线程库上，系统内核不能感知到线程存在的实现。用户线程的建立、同步、销毁和调度完全在用户态中完成，不需要内核的帮助。如果程序实现得当，这种线程不需要切换到内核态，因此<span style="background-color: #c0c0c0;">操作可以是非常快速且低消耗的，也可以支持规模更大的线程数量</span></li>
<li>混合实现：既存在用户线程，也存在轻量级进程。用户线程还是完全建立在用户空间中，因此用户线程的创建、切换、析构等操作依然廉价，并且可以支持大规模的用户线程并发。而操作系统提供支持的轻量级进程则作为用户线程和内核线程之间的桥梁，这样可以使用内核提供的线程调度功能及处理器映射，并且用户线程的系统调用要通过轻量级线程来完成，大大降低了进程被阻塞的风 险。在这种混合模式中，用户线程与轻量级进程的数量比是不定的，是M:N的关系</li>
</ol>
<div class="blog_h2"><span class="graybg">线程状态转换</span></div>
<p>Java语言定义了 5种进程状态：</p>
<ol>
<li>新建（New）：创建后尚未启动的线程处于这种状态</li>
<li>运行（Runable）：Runable包括了操作系统线程状态中的Running和Ready，也就是处于此状态的线程有可能正在执行，也有可能正在等待着CPU为它分配执行时间</li>
<li>无限期等待（Waiting）：处于这种状态的进程不会被分配CPU执行时间，它们要等待被其他线程显式地唤醒。以下方法会让线程陷入无限期的等待状态： <br />a) 没有设置Timeout参数的Object.wait()方法<br />b) 没有设置Timeout参数的Thread.join()方法<br />c) LockSupport.park()方法</li>
<li>限期等待（Timed Waitting）：处于这种状态的进程也不会被分配CPU执行时间， 不过无须等待被其他线程显式地唤醒，在一定时间之后它们会由系统自动唤醒。 以下方法会让线程进入限期等待状态：<br />a) Thread. sleep()方法<br />b) 设置了 Timeout 参数的 Object.wait()方法<br />c) 设置了 Timeout 参数的 Thread.join()方法<br />d) LockSupport.parkNanos() 方法<br />e) LockSupport.parkUntil()方法</li>
<li>阻塞（Blocked）：进程被阻塞了，“阻塞状态”与“等待状态”的区别是：“阻塞状态”在等待着获取到一个排它锁，这个事件将在另外一个线程放弃这个锁的时候发生；而“等待状态”则是在等待一段时间，或者唤醒动作的发生。在程序等待进入同步区域的时候，线程将进入这种状态。</li>
<li>结束（Terminated）：已终止线程的线程状态，线程已经结束执行</li>
</ol>
<div class="blog_h2"><span class="graybg">线程安全</span></div>
<p>当多个线程访问一个对象时，如果不用考虑这些线程在运行时环境下的调度和交替执行，也不需要进行额外的同步，或者在调用方进行任何其他的协调操作，调用这个对象的行为都可以获得正确的结果，那这个对象就是线程安全的。</p>
<p>按照线程安全的级别，可以按线程安全强度把共享数据分为5类：</p>
<ol>
<li>不可变对象：例如字符串、数字的部分子类、枚举</li>
<li>绝对线程安全：完全满足上述关于线程安全的定义。即使多个线程同时对这个对象进行一系列顺序的操作，也不会出现意外的结果</li>
<li>相对线程安全：通常意义上所讲的线程安全，它需要保证对<span style="background-color: #c0c0c0;">这个对象<strong>单独的操作</strong>是线程安全</span>的，我们在调用的时候不需要做额外的保障措施。在Java语言中，大部分的线程安全类都属于这种类型，例如Vector、HashTable、 Collections.synchronizedCollection()方法包装的集合等</li>
<li>线程兼容：是指对象本身并不是线程安全的，但是可以通过在调用端正确地使用同步手段来保证对象在并发环境中安全地使用，我们平常说一个<span style="background-color: #c0c0c0;">类不是线程安全的，绝大多数指的都是这种情况</span>。Java API中大部分的类都是线程兼容</li>
<li>线程对立：是指不管调用端是否采取了同步措施，都无法在多线程环境中并发使用的代码。由于Java语言天生就具备多线程特性，线程对立这种排斥多线程的代码是很少出现。一个线程对立的例子是Thread类的suspend()和resume()方法</li>
</ol>
<div class="blog_h3"><span class="graybg">线程安全的实现方法</span></div>
<ol>
<li>互斥同步（Mutual Exclusion &amp; Synchronization)：是最常见的一种并发正确性保障手段，<span style="background-color: #c0c0c0;">同步是指在多个线程并发访问共享数据时，保证共享数据在同一个时刻只被一条 (或者是一些，使用信号量的时候）线程使用</span>。而互斥是实现同步的一种手段，<span style="background-color: #c0c0c0;">临界区 (Critical Section)、互斥量（Mutex)和信号量（Semaphore)</span>都是主要的互斥实现方式。在Java里面，最基本的互斥同步手段就是synchronized关键字。synchronized是Java语言中一个重量级的操作，虚拟机会进行一些优化，譬如在<span style="background-color: #c0c0c0;">通知操作系统阻塞线程之前加入一段自旋等待过程，避免频繁地切入到内核态中</span>。除了 synchronized之外，还可以使用java.util.concurrent的重入锁（<span style="background-color: #c0c0c0;">ReentrantLock</span>)来实现同步，在基本用法上，ReentrantLock与synchronized 很相似，他们都具备一样的线程重入特性，只是代码写法上有点区别，一个表现为API 层面的互斥锁（<span style="background-color: #c0c0c0;">lock和unloek方法配合try/fmally语句块来完成</span>），一个表现为原生语法层面的互斥锁。不过ReentrantLock比synchronized增加了一些髙级功能，主要有以下三项：<br />a) <span style="background-color: #c0c0c0;">等待可中断</span>：当持有锁的线程长期不释放锁的时候，正在等待的线程可以选择 放弃等待，改为处理其他事情，可中断特性对处理执行时间非常长的同步块很有帮助<br />b)<span style="background-color: #c0c0c0;"> 公平锁</span>：多个线程在等待同一个锁时，必须按照申请锁的时间顺序来依次获得锁；而非公平锁则不保证这一点，在锁被释放时，任何一个等待锁的线程都有机会获得锁。synchronized中的锁是非公平的，<span style="background-color: #c0c0c0;">ReentrantLock默认情况下也是非公平</span>的，但可以通过带布尔值的构造函数要求使用公平锁<br />c) <span style="background-color: #c0c0c0;">锁绑定多个条件</span>：一个ReentrantLock对象可以同时绑定多个Condition对象， 而在synchronized中，锁对象的wait()和notify()或notifyAll()方法可以实现一个隐含的条件，如果要和多于一个的条件关联的时候，就不得不额外地添加一个 锁，而ReentrantLock则无须这样做，只需要多次调用newCondition()方法即可</li>
<li>非阻塞同步：随着硬件指令集的发展，可以使用基于冲突检测的乐观并发策略。Atomiclnteger就是这样的例子</li>
<li>无同步方案：<br />a) 可重入代码：也叫纯代码（Pure Code），可以在代码执行的任何时刻中断它，转而去执行另外一段代码（包括递归调用它本身），而在控制权返回后，原来的程序不会出现任何错误。可重入代码有一些共同的特征：例如<span style="background-color: #c0c0c0;">不依赖存储在堆上的数据和公用的系统资源、 用到的状态量都由参数中传入、不调用非可重入的方法</span>等。<br />b) 线程本地存储（Thread Local Storage）</li>
</ol>
<div class="blog_h2"><span class="graybg">锁优化</span></div>
<div class="blog_h3"><span class="graybg">自旋锁与自适应自旋</span></div>
<p>互斥同步对性能最大的影响是阻塞的实现， 挂起线程和恢复线程的操作都需要转入内核态中完成，这些操作给系统的并发性能带来 了很大的压力。在许多应用上，<span style="background-color: #c0c0c0;">共享数据的锁定状态 只会持续很短的一段时间</span>，为了这段时间去挂起和恢复线程并不值得。如果物理机器有 一个以上的处理器，能让两个或以上的线程同时并行执行，我们就可以让后面请求锁的那个线程“稍等一会儿”，<span style="background-color: #c0c0c0;">但不放弃处理器的执行时间</span>，看看持有锁的线程是否很快就会释放锁。为了让线程等待，我们<span style="background-color: #c0c0c0;">只须让线程执行一个忙循环（自旋）</span>，这项技术就是 所谓的自旋锁。</p>
<p>自旋锁在JDK1.6以后默认开启。使用-XX:+UseSpinning可以强制开启。自旋默认值是10次，可以使用参数-XX:PreBlockSpin来更改。</p>
<p>在JDK 1.6中引入了<span style="background-color: #c0c0c0;">自适应的自旋锁</span>。自旋的时间由前一次在同一个锁上的自旋时间及锁的拥有者的状态来决定。如果在同一个锁对象 上，自旋等待刚刚成功获得过锁，并且持有锁的线程正在运行中，那么虚拟机就会认为这次自旋也很有可能再次成功，进而它将允许自旋等待持续相对更长的时间。</p>
<div class="blog_h3"><span class="graybg">锁消除</span></div>
<p>对一些<span style="background-color: #c0c0c0;">代码上要求同步，但是被检测到不可能存在共享数据竞争</span>的锁进行消除。锁消除的主要判定依据来源于逃逸分析的数据支持。</p>
<div class="blog_h3"><span class="graybg">锁粗化</span></div>
<p>大部分情况下，倾向于将同步块的作用范围限制得尽量小，但是如果一系列的连续操作都对同一个对反复加锁和解锁，甚至加锁操作是出现在循环体中的，那即使没有线程竞争，频繁地 进行互斥同步操作也会导致不必要的性能损耗。</p>
<div class="blog_h3"><span class="graybg">轻量级锁</span></div>
<p>轻量级锁是JDK 1.6中加入的新型锁机制，它名字中的“轻量级”是相对于使用操作系统互斥量来实现的传统锁而言的。首先 需要强调一点的是，轻量级锁并不是用来代替重量级锁的，它的本意是<span style="background-color: #c0c0c0;">在没有多线程竞争的前提下，减少传统的重量级锁使用操作系统互斥量产生的性能消耗</span>。</p>
<p>轻量级锁能提升程序同步性能的依据是“对于绝大部分的锁，在整个同步周期内都是不存在竞争的”，这是一个经验数据。如果没有竞争，轻量级锁使用CAS操作避免了 使用互斥量的开销，但如果存在锁竞争，除了互斥量的开销外，还额外发生了 CAS操 作，因此在有竞争的情况下，轻量级锁会比传统的重量级锁更慢。</p>
<div class="blog_h3"><span class="graybg">偏向锁</span></div>
<p>偏向锁也是JDK 1.6中引入的一项锁优化，它的目的是<span style="background-color: #c0c0c0;">消除数据在无竞争情况下的同步原语，进一步提高程序的运行性能</span>。如果说轻量级锁是在无竞争的情况下使用CAS 操作去消除同步使用的互斥量，那偏向锁就是在无竞争的情况下<span style="background-color: #c0c0c0;">把整个同步都消除掉， 连CAS操作都不做</span>了。<span style="background-color: #c0c0c0;">偏向锁可以提高带有同步但无竞争的程序性能</span>。如果程序中<span style="background-color: #c0c0c0;">大多数的锁都总是被多个不同的线程访问</span>，那偏向模式就是多余的。有时候使用参数-XX:-UseBiasedLocking来禁止偏向锁优化反而可以提升性能。</p>
<div class="blog_h2"><span class="graybg">逃逸分析</span></div>
<p>逃逸分析是一种可以有效<span style="background-color: #c0c0c0;">减少Java 程序中同步负载和内存堆分配压力的跨函数全局数据流分析算法</span>。通过逃逸分析，Java Hotspot编译器能够<span style="background-color: #c0c0c0;">分析出一个新的对象的引用的使用范围</span>从而决定是否要将这个对象分配到堆上。</p>
<p>在计算机语言编译器优化原理中，逃逸分析是指<span style="background-color: #c0c0c0;">分析指针动态范围的方法</span>，它同编译器优化原理的指针分析和外形分析相关联。当变量（或者对象）在方法中分配后，其指针<span style="background-color: #c0c0c0;">有可能被返回或者被全局引用</span>，这样就<span style="background-color: #c0c0c0;">会被其他过程或者线程所引用</span>，这种现象<span style="background-color: #c0c0c0;">称作指针（或者引用）的逃逸（Escape）</span>。</p>
<p>Java在Java SE <span style="background-color: #c0c0c0;">6u23</span>以及以后的版本中支持并<span style="background-color: #c0c0c0;">默认开启了逃逸分析的选项</span>。Java的 HotSpot JIT编译器，能够在方法重载或者动态加载代码的时候对代码进行逃逸分析，同时Java对象在堆上分配和内置线程的特点使得逃逸分析成Java的重要功能。</p>
<p>&nbsp;</p>
<p>经过逃逸分析之后，可以得到三种对象的逃逸状态：</p>
<ol>
<li>GlobalEscape（全局逃逸）， 即一个对象的引用逃出了方法或者线程</li>
<li>ArgEscape（参数级逃逸），即在方法调用过程当中传递对象的引用给一个方法</li>
<li>NoEscape（没有逃逸），一个可以进行标量替换的对象。可以不将这种对象分配在传统的堆上</li>
</ol>
<p>编译器可以使用逃逸分析的结果，对程序进行以下优化：</p>
<ol>
<li>堆分配对象变成栈分配对象。一个方法当中的对象，对象的引用没有发生逃逸，那么这个方法<span style="background-color: #c0c0c0;">可能会被分配在栈内存上</span>而非常见的堆内存上</li>
<li>消除同步。<span style="background-color: #c0c0c0;">线程同步的代价是相当高</span>的，<span style="background-color: #c0c0c0;">同步的后果是降低并发性和性能</span>。<span style="background-color: #c0c0c0;">逃逸分析可以判断出某个对象是否始终只被一个线程访问</span>，如果只被一个线程访问，那么对该对象的同步操作就可以转化成没有同步保护的操作，这样就能大大提高并发程度和性能</li>
<li>矢量替代。逃逸分析方法如果发现对象的内存存储结构不需要连续进行的话，就可以将对象的部分甚至全部都<span style="background-color: #c0c0c0;">保存在CPU寄存器</span>内，这样能大大提高访问速度</li>
</ol>
<p>逃逸分析对应的JVM参数是 -XX:+DoEscapeAnalysis</p>
</div><p>The post <a rel="nofollow" href="https://blog.gmem.cc/jvm-study-note">JVM学习笔记</a> appeared first on <a rel="nofollow" href="https://blog.gmem.cc">绿色记忆</a>.</p>
]]></content:encoded>
			<wfw:commentRss>https://blog.gmem.cc/jvm-study-note/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>SVN知识集锦</title>
		<link>https://blog.gmem.cc/svn-faq</link>
		<comments>https://blog.gmem.cc/svn-faq#comments</comments>
		<pubDate>Thu, 23 Jul 2009 01:57:58 +0000</pubDate>
		<dc:creator><![CDATA[Alex]]></dc:creator>
				<category><![CDATA[Linux]]></category>
		<category><![CDATA[Work]]></category>
		<category><![CDATA[Command]]></category>
		<category><![CDATA[svn]]></category>

		<guid isPermaLink="false">http://blog.gmem.cc/?p=1306</guid>
		<description><![CDATA[<p>常用命令 服务器端命令 创建SVN版本库 命令格式： svnadmin create 路径 --fs-type fsfs&#124;bdb 具体可以参考：Ubuntu下安装subversion服务器  客户端命令 签出：从版本库下载带有svn元数据的副本 命令格式： svn  [co&#124;checkout]  协议://版本库路径　/本地路径   [选项]   [全局选项] 命令详解： 协议 根据版本库的配置不同，可能是svn、http、https等 版本库路径 <a class="read-more" href="https://blog.gmem.cc/svn-faq">[...]</a></p>
<p>The post <a rel="nofollow" href="https://blog.gmem.cc/svn-faq">SVN知识集锦</a> appeared first on <a rel="nofollow" href="https://blog.gmem.cc">绿色记忆</a>.</p>
]]></description>
				<content:encoded><![CDATA[<div class="wri_content_clear_both"><div class="blog_h1"><span class="graybg">常用命令</span></div>
<div class="blog_h2"><span class="graybg">服务器端命令</span></div>
<div class="blog_h3"><span class="graybg">创建SVN版本库</span></div>
<p>命令格式： svnadmin create 路径 --fs-type fsfs|bdb</p>
<p>具体可以参考：<a title="Ubuntu下安装subversion服务器" href="/subversion-server-under-ubuntu" target="_blank">Ubuntu下安装subversion服务器</a> </p>
<div class="blog_h2"><span class="graybg">客户端命令</span></div>
<div class="blog_h3"><span class="graybg">签出：从版本库下载带有svn元数据的副本</span></div>
<p>命令格式：</p>
<p>svn  [co|checkout]  协议://版本库路径　/本地路径   [选项]   [全局选项]</p>
<p>命令详解：</p>
<table style="width: 100%;" border="1" cellspacing="0" cellpadding="5">
<tbody>
<tr>
<td style="width: 100px;">协议</td>
<td>根据版本库的配置不同，可能是svn、http、https等</td>
</tr>
<tr>
<td>版本库路径</td>
<td>版本库往往会有trunk、tag、branches等分支，注意如果你需要签出demo，可能需要定位到demo/trunk</td>
</tr>
<tr>
<td>本地路径</td>
<td>可以指定相对（于当前目录的）路径或者绝对路径</td>
</tr>
<tr>
<td>选项</td>
<td><strong>-r　</strong>需要签出的版本，可以是版本号，或者：</p>
<p style="padding-left: 60px;">HEAD　最新版本；</p>
<p style="padding-left: 60px;">BASE　当前工作拷贝的版本；</p>
<p style="padding-left: 60px;">COMMITTED　上一次提交的版本；</p>
<p style="padding-left: 60px;">PREV　COMMITTED的前一个版本</p>
<p><strong>-q</strong>　不打印详细的信息 <strong>--depth</strong>　限制操作影响的目录深度：</p>
<p style="padding-left: 60px;">empty　仅指定的目录；</p>
<p style="padding-left: 60px;">files　目录和其子文件，不包括子目录；</p>
<p style="padding-left: 60px;">immediates　目录和其直接子文件、直接子目录；</p>
<p style="padding-left: 60px;">infinity　包括所有后代</p>
<p><strong>--force</strong>　强制执行，正常使用下，SVN可能会阻止某些操作</p>
<p><strong>--ignore-externals</strong>：忽略SVN管理的外部工作拷贝</p>
</td>
</tr>
<tr>
<td>全局选项</td>
<td><strong> --username:</strong> 指定用户名<br /> <strong>--password:</strong> 指定密码<br /> <strong>--no-auth-cache</strong>: 不要缓存用于认证的用户密码<strong>--non-interactive</strong> :不要进行交互式提示</p>
<p><strong>--force-interactive</strong> : 强制交互式提示</p>
<p><strong>--trust-server-cert :</strong> 信任服务端的证书，不做提示</p>
<p><strong>--config-dir:</strong> 从指定的目录读取用户的配置信息</p>
<p><strong>--config-option</strong> :以FILE:SECTION:OPTION=[VALUE]的形式设置选项</p>
</td>
</tr>
</tbody>
</table>
<p>示例：</p>
<pre class="crayon-plain-tag">#签出到当前目录的子目录
svn checkout svn://192.168.1.15/test svntest
#签出，并指定用户密码
svn co svn://192.168.1.15/demo ~/projects/demo --username u --password p
#非交互式导出，信任服务器证书
svn --non-interactive --no-auth-cache --trust-server-cert 
    --username $SVNUSER --password $SVNPSWD 
    export https://192.168.1.15/demo</pre>
<div class="blog_h3"><span class="graybg">更新：从版本库获取更改到工作拷贝</span></div>
<p>命令格式：svn update [路径]  [选项] [全局选项]</p>
<p>对于每一个受影响的文件，都用一个字母来表示对其进行的操作：</p>
<table class="full-width fixed-word-wrap" border="1" cellspacing="0" cellpadding="5">
<tbody>
<tr>
<td style="width: 20%;">A</td>
<td>新文件，添加到工作拷贝</td>
</tr>
<tr>
<td>D</td>
<td>删除工作拷贝的文件</td>
</tr>
<tr>
<td>U</td>
<td>更新空座拷贝的文件</td>
</tr>
<tr>
<td>C</td>
<td>文件存在冲突，需要处理</td>
</tr>
<tr>
<td>G</td>
<td>文件被自动合并</td>
</tr>
</tbody>
</table>
<p>命令详解：</p>
<table style="width: 100%;" border="1" cellspacing="0" cellpadding="5">
<tbody>
<tr>
<td style="width: 100px;">路径</td>
<td>需要更新的文件或者目录</td>
</tr>
<tr>
<td>选项</td>
<td><b>-r、--depth、-q、--force、--ignore-externals</b>：参考签出命令<br /> <strong>--set-depth</strong>　设置新的工作拷贝的depth<strong>--diff3-cmd</strong>　使用参数指定的命令进行文件合并<strong>--cl　</strong>仅仅操作参数指定的成员</p>
<p><strong>--editor-cmd</strong>　指定外部编辑器</p>
<p><strong>--accept　</strong>设置自动冲突处理方式：</p>
<p style="padding-left: 60px;">postpone(p)　不做任何处理；</p>
<p style="padding-left: 60px;">edit(e)　打开冲突文件手工处理；</p>
<p style="padding-left: 60px;">launch(l)　打开交互式冲突处理工具；</p>
<p style="padding-left: 60px;">base　使用BASE版本；</p>
<p style="padding-left: 60px;">working　使用工作拷贝版本，假设冲突已经被手工处理；</p>
<p style="padding-left: 60px;">mine-full(mf)　使用本地的修改；</p>
<p style="padding-left: 60px;">theirs-full(tf)　使用更新得到的文件；</p>
<p style="padding-left: 60px;">mine-conflict(mc)　冲突部分使用本地的修改；</p>
<p style="padding-left: 60px;">theirs-conflict(tc)　冲突部分使用更新得到的文件</p>
<p><strong>--parents</strong>　创建不存在的父目录</p>
</td>
</tr>
<tr>
<td>全局选项</td>
<td>参考签出命令</td>
</tr>
</tbody>
</table>
<p>示例：</p>
<pre class="crayon-plain-tag">#更新themes目录到HEAD版本，如果出现冲突，冲突部分替换为我的本地修改
svn update wp-content/themes --accept mc</pre>
<div class="blog_h3"><span class="graybg">提交：将本地修改保存到版本库上</span></div>
<p>命令格式：svn commit [路径] [选项] [全局选项]</p>
<p>命令详解：</p>
<table style="width: 100%;" border="1" cellspacing="0" cellpadding="5">
<tbody>
<tr>
<td style="width: 100px;">路径</td>
<td>需要更新的文件或者目录</td>
</tr>
<tr>
<td>选项</td>
<td><b>-r、--depth、-q、--force、--ignore-externals、--cl、--editor-cmd </b>：参考更新命令<strong>--targets</strong>　将该参数指定的文件的内容，作为额外参数传递</p>
<p><strong>-m　</strong>设置提交的日志消息</p>
<p><strong>-F</strong>　从文件中读取提交日志消息</p>
<p><strong>--encoding</strong>　指定字符集</p>
<p><strong>--with-revprop</strong>　使用name[=value]的形式提供即将提交的修订版的属性</p>
<p><strong>--keep-changelists</strong>　提交后保留changelists</p>
</td>
</tr>
<tr>
<td>全局选项</td>
<td>参考签出命令</td>
</tr>
</tbody>
</table>
<div class="blog_h3"><span class="graybg">其他SVN命令</span></div>
<table class=" full-width fixed-word-wrap">
<thead>
<tr>
<td style="width: 15%; text-align: center;">命令</td>
<td style="text-align: center;">说明</td>
</tr>
</thead>
<tbody>
<tr>
<td>svn status</td>
<td>
<p>打印工作拷贝中文件或者目录的状态</p>
<p>命令格式：<pre class="crayon-plain-tag">svn status 路径 [参数]</pre> </p>
</td>
</tr>
<tr>
<td>svn revert</td>
<td>
<p>还原本地修改</p>
<p>命令格式：<pre class="crayon-plain-tag">svn revert 路径</pre> </p>
</td>
</tr>
<tr>
<td>svn propset</td>
<td>
<p>设置目录、文件或者修订版的SVN属性</p>
<p>命令格式： <pre class="crayon-plain-tag">svn propset 属性名 属性值 路径</pre> </p>
<p>举例：</p>
<pre class="crayon-plain-tag"># 将当前目录下的log.txt加入到忽略文件列表
svn propset svn:ignore log.txt .</pre>
</td>
</tr>
<tr>
<td>svn propedit</td>
<td>
<p>使用外部编辑器编辑SVN属性
<p>命令格式：<pre class="crayon-plain-tag"> svn propedit 属性名</pre> </p>
</td>
</tr>
<tr>
<td>svn proplist </td>
<td>显示所有SVN属性</td>
</tr>
<tr>
<td>svn propdel</td>
<td>
<p>删除某个SVN属性</p>
<p>命令格式：<pre class="crayon-plain-tag">svn pd 属性名</pre> </p>
</td>
</tr>
<tr>
<td>svn export</td>
<td>
<p>导出一个未版本化的副本 </p>
<p>命令格式：<pre class="crayon-plain-tag">svn export [-r 修订版]  远程路径  本地路径</pre> </p>
<p>参数：--native-eol 用于指定换行符，可以是：'LF', 'CR', 'CRLF'</p>
</td>
</tr>
<tr>
<td>svn import </td>
<td>
<p>导入本地目录到版本库</p>
<p>命令格式： <pre class="crayon-plain-tag">svn import 本地路径 远程URL</pre> </p>
<p>如果本地路径不指定，则表示当前目录。注意：本地不会生成.svn目录，本地不会和版本库产生关联</p>
</td>
</tr>
<tr>
<td>svn lock</td>
<td>
<p>锁定版本库上的某个路径，避免被别的人修改</p>
<p>命令格式：<pre class="crayon-plain-tag">svn lock 路径</pre> </p>
<p>使用 --force可以窃取锁</p>
</td>
</tr>
<tr>
<td>svn unlock</td>
<td>
<p>解锁某个路径 </p>
<p>命令格式： <pre class="crayon-plain-tag">svn lock 路径</pre> </p>
</td>
</tr>
<tr>
<td>svn add</td>
<td>
<p>使未版本化的文件纳入版本控制，并在下一次commit时提交到版本库 </p>
<p>命令格式：<pre class="crayon-plain-tag">svn add 路径</pre> </p>
<p>--auto-props : 启用自动属性</p>
<p>--no-auto-props : 禁用自动属性 举例：</p>
<pre class="crayon-plain-tag">#将当前目录中所有未版本化的文件纳入版本控制，无限递归，自动在版本库创建缺少的目录
#自动添加属性，安静模式
svn add * --force  --auto-props --parents --depth infinity -q </pre>
</td>
</tr>
<tr>
<td>svn delete</td>
<td>
<p>将指定文件清除出版本控制，并在下一次commit时提交到版本库
<p>命令格式：<pre class="crayon-plain-tag">svn [delete|rm] 路径</pre> </p>
</td>
</tr>
<tr>
<td>svn copy </td>
<td>
<p>在版本库或者工作拷贝复制文件 </p>
<p>命令格式：<pre class="crayon-plain-tag">svn [copy|cp] 源路径  目标路径</pre> </p>
</td>
</tr>
<tr>
<td>svn move </td>
<td>
<p>在版本库或者工作拷贝移动文件</p>
<p>命令格式：<pre class="crayon-plain-tag">svn [move|mv] 源路径  目标路径</pre> </p>
</td>
</tr>
<tr>
<td>svn mkdir</td>
<td>在版本库或者工作拷贝创建目录</p>
<p>命令格式：<pre class="crayon-plain-tag">svn mkdir 路径</pre> </p>
</td>
</tr>
<tr>
<td>svn log </td>
<td>
<p>显示提交日志</p>
<p>命令格式：<pre class="crayon-plain-tag">svn log 路径</pre> </p>
<p>举例：</p>
<pre class="crayon-plain-tag">#显示最近5条提交日志
svn log -l 5 -v
#显示test.c的修订版42的提交日志
svn log test.c@42
#显示test.c上一次更新以后的提交消息
svn log -r BASE:HEAD test.c </pre>
</td>
</tr>
</tbody>
</table>
<div class="blog_h1"><span class="graybg">如何处理冲突</span></div>
<div class="blog_h2"><span class="graybg">基本知识</span></div>
<div>允许svn update时，可能出现冲突。当 冲突发生时，SVN会自动生成额外3个未版本化的文件到工作拷贝对应的目录中： <strong>fileName.mine </strong>当前工作拷贝的最新修改 <strong>fileName.rOLDREV </strong>当前工作拷贝的BASE版本 <strong>fileName.rNEWREV</strong> 刚从服务器更新的版本 这三个文件删除之前，无法提交。 解决冲突的方式有三种：</div>
<div>
<ol>
<li>
<div><span style="color: #000000;">手工合并</span></div>
</li>
<li>使用上面三个临时文件之一覆盖修改</li>
<li>svn revert回退本地修改</li>
</ol>
</div>
<div class="blog_h2"><span class="graybg">如何手工合并修改？</span></div>
<p>冲突文件中，使用<span style="color: #ff0000;"><strong>&lt;&lt;&lt; === &gt;&gt;&gt;</strong></span>这样的符号来对冲突进行标记：
<pre class="crayon-plain-tag">private int name;
/*前两段符号圈定的是本地的修改内容*/
&lt;&lt;&lt;&lt;&lt;&lt;&lt; .mine
private Date dob;
=======
private Date birthDate;
&gt;&gt;&gt;&gt;&gt;&gt;&gt; .r2
/*后两段符号圈定的是从版本库更新下来的内容，最后会附加其版本号*/</pre>
<p>具体的修改需要结合实际工作内容进行。</p>
<div class="blog_h1"><span class="graybg">TortoiseSVN</span></div>
<p>TortoiseSVN是一个图形化的SVN客户端软件，它使用不同的图标来标记文件的状态：</p>
<p><a href="/wp-content/uploads/2009/07/TortoiseSVN.png"><img src="https://blog.gmem.cc/wp-content/uploads/2009/07/TortoiseSVN.png" alt="TortoiseSVN" width="418" height="209" /></a></p>
<div class="blog_h1"><span class="graybg">常见问题</span></div>
<div class="blog_h2"><span class="graybg">常见错误</span></div>
<div class="blog_h3"><span class="graybg">设置svn:ignore无效</span></div>
<div>如果svn:ignore的目标文件已在版本库上已经存在，则设置无效，可以先删除版本库上的目标文件，客户端进行更新后设置</div>
<div class="blog_h3"><span class="graybg">working copy locked</span></div>
<p>运行：svn cleanup</p>
<div class="blog_h3"><span class="graybg">Can't convert string from 'UTF-8' to native encoding</span></div>
<p>Linux下出现此错误，是Locale设置问题，解决办法：</p>
<pre class="crayon-plain-tag">export LC_ALL=en_US.UTF-8</pre>
<div class="blog_h3"><span class="graybg">This line, and those below, will be ignored</span></div>
<p>需要添加提交日志：<pre class="crayon-plain-tag">svn commit -m "日志内容"</pre> </p>
<div class="blog_h3"><span class="graybg">svn: E155010: '***' is scheduled for addition, but is missing</span></div>
<p>运行：<pre class="crayon-plain-tag">svn delete ***</pre> </p>
<div class="blog_h2"><span class="graybg">Howtos</span></div>
<div class="blog_h3"><span class="graybg">全部添加到版本控制</span></div>
<pre class="crayon-plain-tag">svn add --force * --auto-props --parents --depth infinity -q </pre>
<div class="blog_h3"><span class="graybg">本地删除同步SVN删除</span></div>
<pre class="crayon-plain-tag">svn status | grep ^! | awk '{ print " --force " $2"@"}' | xargs svn rm</pre>
<p>之所以在文件名末尾添加@，是因为@是SVN特殊符号，结尾加上@表示将文件名中出现的@作为普通字符看待。 </p>
<div class="blog_h3"><span class="graybg">设置Maven项目的SVN属性</span></div>
<div>
<pre class="crayon-plain-tag">## svn:ignore设置 ##
#根目录上通常要设置：
target
.*
#如果使用JRebel，则src/main/resources上要设置
rebel.xml</pre>
</div>
</div><p>The post <a rel="nofollow" href="https://blog.gmem.cc/svn-faq">SVN知识集锦</a> appeared first on <a rel="nofollow" href="https://blog.gmem.cc">绿色记忆</a>.</p>
]]></content:encoded>
			<wfw:commentRss>https://blog.gmem.cc/svn-faq/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Linux命令知识集锦</title>
		<link>https://blog.gmem.cc/linux-command-faq</link>
		<comments>https://blog.gmem.cc/linux-command-faq#comments</comments>
		<pubDate>Tue, 15 Apr 2008 04:17:30 +0000</pubDate>
		<dc:creator><![CDATA[Alex]]></dc:creator>
				<category><![CDATA[Linux]]></category>
		<category><![CDATA[Command]]></category>
		<category><![CDATA[Linux知识]]></category>

		<guid isPermaLink="false">http://blog.gmem.cc/?p=2439</guid>
		<description><![CDATA[<p>Shell基本知识 Shell快捷键  快捷键 用途 ctrl + z 暂停当前程序，回到shell，注意当前任务不会被终止，只是被挂起（在jobs命令的输出中显示为Stopped）。例如，在执行vim编辑的时候，可以按Ctrl+Z挂起（stdout将显示jobnumber），回到Shell执行命令，然后输入fg继续vim编辑 注意：挂起的任务不再参与进程调度，要让一个任务在后台持续运行，可以使用 &#38; 后缀调用一个任务的命令行，或者在挂起后对其作业号运行bg命令 ctrl + c 停止当前程序，回到shell ctrl + d 发送EOF ctrl + r <a class="read-more" href="https://blog.gmem.cc/linux-command-faq">[...]</a></p>
<p>The post <a rel="nofollow" href="https://blog.gmem.cc/linux-command-faq">Linux命令知识集锦</a> appeared first on <a rel="nofollow" href="https://blog.gmem.cc">绿色记忆</a>.</p>
]]></description>
				<content:encoded><![CDATA[<div class="wri_content_clear_both"><div class="blog_h1"><span class="graybg">Shell基本知识</span></div>
<div class="blog_h2"><span class="graybg">Shell快捷键</span></div>
<table style="width: 100%;" border="1" cellspacing="0" cellpadding="5">
<thead>
<tr>
<td style="width: 15%; text-align: center;"> 快捷键</td>
<td style="text-align: center;">用途</td>
</tr>
</thead>
<tbody>
<tr>
<td>ctrl + z</td>
<td>
<p>暂停当前程序，回到shell，注意当前任务不会被终止，只是被挂起（在jobs命令的输出中显示为Stopped）。<br />例如，在执行vim编辑的时候，可以按Ctrl+Z挂起（stdout将显示jobnumber），回到Shell执行命令，然后输入fg继续vim编辑</p>
<p>注意：挂起的任务不再参与进程调度，要让一个任务在后台持续运行，可以使用 &amp; 后缀调用一个任务的命令行，或者在挂起后对其作业号运行bg命令</p>
</td>
</tr>
<tr>
<td>ctrl + c</td>
<td>停止当前程序，回到shell</td>
</tr>
<tr>
<td>ctrl + d</td>
<td>发送EOF</td>
</tr>
<tr>
<td>ctrl + r</td>
<td>快速搜索命令历史，比上下箭头高效</td>
</tr>
<tr>
<td>ctrl + s</td>
<td>使快速刷屏的终端界面静止下来</td>
</tr>
<tr>
<td>ctrl + q</td>
<td>恢复ctrl + s的造成的效果</td>
</tr>
<tr>
<td>ctrl + a</td>
<td>光标移动到行首</td>
</tr>
<tr>
<td>ctrl + e</td>
<td>光标移动到行尾</td>
</tr>
<tr>
<td>ctrl + u</td>
<td>从光标位置删除到行首</td>
</tr>
<tr>
<td>ctrl + k</td>
<td>从光标位置删除到行尾</td>
</tr>
<tr>
<td>backspace</td>
<td>向前删除一个字符</td>
</tr>
<tr>
<td>ctrl + d</td>
<td>向后删除一个字符</td>
</tr>
<tr>
<td>alt + backspace</td>
<td>向前删除一个单词</td>
</tr>
<tr>
<td>alt + d</td>
<td>向后删除一个单词</td>
</tr>
</tbody>
</table>
<div class="blog_h2"><span class="graybg">后台运行命令</span></div>
<pre class="crayon-plain-tag">#下面的命令将在后台运行
./command.sh &amp;
#下面的命令将不挂掉的在后台运行，标准输出被重定向到nohup.out，即使当前终端退出任然继续运行

#nohup命令可以忽略所有挂断（SIGHUP）信号
nohup ./command.sh &amp;

#忽略标准输出、错误。 0 1 2 分别表示标准输入、输出、错误，2&gt;&amp;1表示把标准错误重定向到标准输出，而前者已经重定向到空设备
nohup ./command &gt; /dev/null 2&gt;&amp;1 &amp;</pre>
<div class="blog_h1"><span class="graybg">Tmux</span></div>
<div class="blog_h2"><span class="graybg">子命令</span></div>
<pre class="crayon-plain-tag"># 列出当前Tmux服务中有哪些会话
tmux ls
# dev-120: 1 windows (created Fri Feb 23 19:57:35 2018) [180x49] (attached)

# 连接到会话
tmux a -t dev-120

# 命令
# 在当前位置插入新窗口
new-window -a</pre>
<div class="blog_h2"><span class="graybg">快捷键</span></div>
<p>所有快捷键必须在按下前缀键后才能使用，前缀键默认Ctrl + B</p>
<table class="full-width fixed-word-wrap">
<thead>
<tr>
<td style="width: 15%; text-align: center;">快捷键</td>
<td style="text-align: center;">说明</td>
</tr>
</thead>
<tbody>
<tr>
<td>"</td>
<td>垂直方向拆分面板</td>
</tr>
<tr>
<td>%</td>
<td>水平方向拆分面板</td>
</tr>
<tr>
<td>o</td>
<td>切换到当前窗口的下一个面板</td>
</tr>
<tr>
<td>PgUp</td>
<td>启用Page Up/Down滚动，按Q退出滚动模式</td>
</tr>
<tr>
<td>$</td>
<td>重命名当前会话</td>
</tr>
<tr>
<td>,</td>
<td>重命名当前窗口</td>
</tr>
<tr>
<td>.</td>
<td>修改窗口编号</td>
</tr>
<tr>
<td>s</td>
<td>列出所有会话，通过j，k，回车切换</td>
</tr>
<tr>
<td>c</td>
<td>创建新窗口</td>
</tr>
<tr>
<td>&lt;N&gt;</td>
<td>切换到第N-1个窗口</td>
</tr>
<tr>
<td>p</td>
<td>切换到上一个窗口</td>
</tr>
<tr>
<td>n</td>
<td>切换到下一个窗口</td>
</tr>
<tr>
<td>!</td>
<td>创建一个新窗口，并把当前面板置于其中</td>
</tr>
<tr>
<td>Space</td>
<td>切换面板布局</td>
</tr>
<tr>
<td>d</td>
<td>从当前会话断开，回到父Shell</td>
</tr>
<tr>
<td>D</td>
<td>选择一个会话以断开</td>
</tr>
<tr>
<td>Shift + Mouse1</td>
<td>选中文本，可以进行复制</td>
</tr>
<tr>
<td>:</td>
<td>
<p>输入命令，示例：set-option -g history-limit 100000</p>
</td>
</tr>
</tbody>
</table>
<div class="blog_h1"><span class="graybg">文件与目录命令</span></div>
<table style="width: 100%;" border="1" cellspacing="0" cellpadding="5">
<thead>
<tr>
<td style="text-align: center;">命令</td>
<td style="text-align: center;"> 说明</td>
</tr>
</thead>
<tbody>
<tr>
<td class="blog_h2">ls</td>
<td>
<p>列出目录中的文件</p>
<p><span style="background-color: #c0c0c0;">格式：</span><br />ls [OPTION]... [FILE]...</p>
<p><span style="background-color: #c0c0c0;">选项：</span><br />-a, --all 包含.号开始的文件<br />-A, --almost-all 包含除了.和..以外的任何文件<br />--author 与-l联用 打印文件的作者<br />-b, --escape 使用C-style转义来显示不可见字符<br />--block-size=SIZE 使用block size来显示尺寸<br />-B, --ignore-backups 忽略~结尾的备份文件<br />-c -lt:根据最后修改时间排序 -l: show 显示修改时间并按名称排序<br />-C 按列显示<br />--color[=always|never|auto] 输出语法高亮配置 <br />-d, --directory 显示目标，而不是其内容，不解引用符号链接<br />-f 禁止排序<br />-F, --classify 附加指示器(*/=&gt;@|) 到所有条目<br />--file-type 类似上面，只是不附加*<br />--format=WORD 格式：across -x, commas -m, horizontal -x, long -l, single-column -1, verbose -l, vertical -C<br />--full-time 类似-l --time-style=full-iso<br />-g 类似-l, 但是不显示所有者<br />--group-directories-first 在文件前显示目录，与--sort一起使用<br />-G, --no-group 在long listing时不显示组名<br />-h, --human-readable 与-l联用，使用易于人类阅读的方式显示尺寸<br />--si 与上面类似，但是计算倍数时使用1000而非1024<br />-H, --dereference-command-line Follow符号链接<br />--dereference-command-line-symlink-to-dir Follow指向目录的符号链接链接<br />--hide=PATTERN 隐藏所有匹配PATTERN的条目（被-a或-A覆盖）<br />-i, --inode 显示文件的索引号<br />-I, --ignore=PATTERN 隐藏所有匹配PATTERN的条目<br />-k 类似--block-size=1K<br />-l 使用长格式<br />-L, --dereference 显示符号链接的信息时，显示目标文件，而不是符号链接本身的信息<br />-n, --numeric-uid-gid 类似-l，但是列出用户和组标识符<br />-N, --literal 打印原始文件名<br />-o 类似-l，但是不列出组信息<br />-p, --indicator-style=slash 附加斜线到目录<br />-q, --hide-control-chars 打印?来代替控制字符<br />--show-control-chars 显示控制字符<br />-Q, --quote-name 在双引号中包含条目<br />-r, --reverse 排序时反转顺序（由降序改为升序）<br />-R, --recursive 递归的列出目录<br />-s, --size 打印文件实际分配尺寸，以块为单位<br />-S 根据文件尺寸排序<br />--sort=WORD 根据指定方式排序。无：-U, 扩展名：-X, 尺寸：-S,时间：-t,版本：-v<br />-t 根据修改时间排序<br />-T, --tabsize=COLS TAB的尺寸，默认8<br />-U 不进行排序<br />-w, --width=COLS 假设屏幕宽度<br />-x 按行列出条目<br />-X 根据扩展名排序 </p>
<p><span style="background-color: #c0c0c0;">举例：</span></p>
<pre class="crayon-plain-tag"># 设置时间格式
ls -l --time-style '+%Y-%m-%d %H:%M:%S'
# 可以修改文件vim ~/.bashrc，添加以下内容：
# alias ll='ls -alF --time-style "+%Y-%m-%d %H:%M:%S"'
# 对所有以后登陆的Terminal均生效

# 根据修改时间降序排列
ll -t
# 根据修改时间升序排列
ll -tr
# 根据文件尺寸升序排列
ll -Sr

# 需要注意文件尺寸和实际分配空间可能不一致
# 下面生成的文件，尺寸是10G，但是实际分配空间仅4K
dd if=/dev/zero of=/tmp/data.img bs=1K count=1 seek=10M
ls -lsh /tmp
# 4.0K -rw-r--r-- 1 root root 11G Jun 3 15:04 data.img</pre>
</td>
</tr>
<tr>
<td class="blog_h2">vdir</td>
<td>
<p>显示详细的目录列表， 与 ls -l 的效果类似
</td>
</tr>
<tr>
<td class="blog_h2">cp</td>
<td>
<p>拷贝文件到目标文件，或者拷贝若干文件到目录<br /><span style="background-color: #c0c0c0;">格式：</span><br />cp [OPTION]... [-T] SOURCE DEST<br />cp [OPTION]... SOURCE... DIRECTORY<br />cp [OPTION]... -t DIRECTORY SOURCE...</p>
<p><span style="background-color: #c0c0c0;">选项：</span><br />-a, --archive 等价于 -dR --preserve=all<br /> --attributes-only 不拷贝文件内容，只拷贝其属性<br />-b, --backup 对每个DEST文件进行备份<br />-d 等价于 --no-dereference --preserve=links<br />-f, --force 如果DEST文件不能打开，移除其并重试，使用-n时无效<br />-i, --interactive 在覆盖DEST文件前进行提示<br />-H 仅跟随（解引用）命令行指定的SOURCE本身的符号连接，递归（-R）的子文件不跟随<br />-l, --link 硬链接而不是拷贝文件<br />-L, --dereference 总是跟随（解引用）SOURCE 的符号连接<br />-n, --no-clobber 不覆盖已经存在的DEST文件，覆盖-i<br />-P, --no-dereference 绝不跟随（解引用）SOURCE 的符号连接<br />-p 等价于 --preserve=mode,ownership,timestamps<br />--preserve[=ATTR_LIST] 维持指定的文件属性<br />--no-preserve=[ATTR_LIST] 清除指定的属性<br />-R, -r, --recursive 递归的拷贝目录<br />--remove-destination 尝试打开目标文件前，删除它，与-f对比<br />-s, --symbolic-link 创建符号连接，而不是拷贝<br />-S, --suffix=SUFFIX 指定备份文件的后缀，默认~<br />-t, --target-directory=DIRECTORY 拷贝所有源文件到目标目录<br />-T, --no-target-directory 将DEST作为普通文件看待，可用于覆盖目标目录<br />-u, --update 如果目标文件不存在，或者源文件时间更新，才执行拷贝</p>
<p><span style="background-color: #c0c0c0;">举例：</span></p>
<pre class="crayon-plain-tag">cd ~/Test
mkdir src &amp;&amp; mkdir src/sub &amp;&amp; mkdir dest
echo FILE1_SRC &gt; src/file1 &amp;&amp; echo SUBFILE1_SRC &gt; src/sub/subfile1
touch dest/file1

cp src/file1 dest/               #dest/file1被覆盖，但是inode维持不变
cp src/file1 dest/file1_src      #直接指定DEST为文件

#复制src目录及其所有内容到dest目录，如果src本身是一个指向目录的符号链接
#则进行解引用，如果src的子目录是符号链接，则仅仅在dest下创建相同的符号链接
cp -R -H src/ dest/
#与上一个类似，但是所有src子目录的符号链接也被解引用
cp -R -H src/ dest/</pre>
</td>
</tr>
<tr>
<td class="blog_h2">mv</td>
<td>
<p>文件移动命令，移动文件的位置，移动多个文件到目录中，或者将目录重命名
<p>该命令的行为：</p>
<ol>
<li>如果目标位置是当前文件系统，则执行rename系统调用，将inode关联到新的目录项，文件本身（inode，文件系统级别概念）没有任何变化</li>
<li>如果目标位置是其它文件系统，则实际上是拷贝数据并在目标文件系统创建inode。然后，旧文件被unlink（解除和目录项的关联），如果没有打开的文件描述符则删除inode</li>
</ol>
<p>进程打开文件后，系统会返回文件描述符给它。不管何种情况下，mv都不会导致这些已经打开的文件描述符失效。也就是mv不影响已经打开文件的进程使用文件</p>
<p><span style="background-color: #c0c0c0;">格式：</span><br />mv [OPTION]... [-T] SOURCE DEST<br />mv [OPTION]... SOURCE... DIRECTORY<br />mv [OPTION]... -t DIRECTORY SOURCE...</p>
<p><span style="background-color: #c0c0c0;">选项：</span><br />--backup[=CONTROL] 对每一个DEST文件进行备份<br />-b 与上面类似，但是不支持指定参数<br />-f, --force 覆盖DEST前不进行提示<br />-i, --interactive 覆盖DEST前进行提示<br />-n, --no-clobber 不覆盖已经存在的文件<br />-S, --suffix=SUFFIX 备份文件的后缀<br />-t, --target-directory=DIRECTORY 移动所有文件到目标目录<br />-T, --no-target-directory 将DEST作为文件看待<br />-u, --update 只有当目标不存在，或者源比较新的时候，才移动</p>
<pre class="crayon-plain-tag">cd ~/Test
mkdir src &amp;&amp; mkdir src/sub &amp;&amp; mkdir dest
echo FILE1_SRC &gt; src/file1 &amp;&amp; echo SUBFILE1_SRC &gt; src/sub/subfile1

mv src/file1 dest      #把单个文件移动到目标目录
mv src/file1 destfile  #把单个文件移动到目标文件，如果目标文件已存在，则覆盖

mv src   dest          #把src目录移动作为dest的子目录
mv src/* dest          #把src目录下所有内容移动到dest目录下</pre>
</td>
</tr>
<tr>
<td class="blog_h2">rm</td>
<td>
<p>删除文件或者目录。默认情况下，该命令不会执行目录删除
<p><span style="background-color: #c0c0c0;">格式：</span><br />rm [OPTION]... FILE...</p>
<p><span style="background-color: #c0c0c0;">选项：</span><br />-f, --force 忽视不存在的文件或者参数，不进行提示<br />-i 删除每个文件前提示<br />-I 删除超过3个文件时，提示一次<br />--one-file-system  递归删除时，遇到不再同一文件系统上目录时跳过<br />-r, -R, --recursive 递归的移除目录及其内容<br />-d, --dir 移除空目录</p>
<p><span style="background-color: #c0c0c0;">举例：</span></p>
<pre class="crayon-plain-tag">cd ~/Test
touch file1 &amp;&amp; touch file2 &amp;&amp; touch file3
mkdir subdir &amp;&amp; touch subdir/file4

rm file1 file2     #删除两个文件
rm -r subdir       #删除子目录及其内容
rm -r *            #清空当前目录
rm -r /*           #尝试删除Linux目录树下所有文件
rm -- -foo         #移除 -开头的文件</pre>
</td>
</tr>
<tr>
<td class="blog_h2">rmdir</td>
<td>
<p>删除空目录
<p><span style="background-color: #c0c0c0;">格式：</span><br />rmdir [OPTION]... DIRECTORY...</p>
<p><span style="background-color: #c0c0c0;">选项：</span><br />--ignore-fail-on-non-empty 不提示非空目录的失败<br />-p, --parents 删除祖先目录<br />-v, --verbose 打印冗余信息</p>
<p><span style="background-color: #c0c0c0;">举例：</span></p>
<pre class="crayon-plain-tag">cd ~/Test
mkdir -p ed1/ed2/ed3

rmdir -p ed1            #失败，目录非空
rmdir -p ed1/ed2/ed3    #OK

mkdir ed1 &amp;&amp; mkdir ed2 &amp;&amp; mkdir ed3
rmdir ed1 ed2 ed3</pre>
</td>
</tr>
<tr>
<td class="blog_h2">mkdir</td>
<td>
<p>创建目录或者目录树
<p><span style="background-color: #c0c0c0;">格式：</span><br /> mkdir [OPTION]... DIRECTORY...</p>
<p><span style="background-color: #c0c0c0;">选项：</span><br />-m, --mode=MODE 设置文件的模式，类似于chmod中的模式<br />-p, --parents 创建必要的父目录<br />-v, --verbose 打印冗余信息</p>
<p><span style="background-color: #c0c0c0;">举例：</span></p>
<pre class="crayon-plain-tag">cd ~/Test
mkdir -m 777 tmp         #创建一个权限大开的目录
#在Ubuntu14上，新创建的目录权限为775
mkdir -p dir/sub         #自动创建缺少的父目录</pre>
</td>
</tr>
<tr>
<td class="blog_h2">chmod</td>
<td>修改文件权限，参见：<a href="/linux-file-and-privileges" target="_blank">Linux文件和权限</a></td>
</tr>
<tr>
<td class="blog_h2">namei</td>
<td>
<p>显示指定路径上，所有节点的权限：
<pre class="crayon-plain-tag">namei -om ~/Scripts/apache-init.sh 
# f: /home/alex/Scripts/apache-init.sh
#  drwxr-xr-x root root /
#  drwxr-xr-x root root home
#  drwxr-xr-x alex alex alex
#  drwxrwxr-x alex alex Scripts
#  -rwxrwxr-x alex alex apache-init.sh </pre>
</td>
</tr>
<tr>
<td class="blog_h2">umask</td>
<td>设定创建文件时权限的缺省权限</td>
</tr>
<tr>
<td class="blog_h2">chown</td>
<td>修改一个或多个文件的所有权</td>
</tr>
<tr>
<td class="blog_h2">chgrp</td>
<td>修改一个或多个文件的所属组</td>
</tr>
<tr>
<td class="blog_h2">chattr</td>
<td>
<p>修改Linux文件系统上的文件属性
<p><span style="background-color: #c0c0c0;">格式：</span><br />chattr [ -RVf ] [ -v version ] [ mode ] files...</p>
<p><span style="background-color: #c0c0c0;">选项：</span><br />-R 递归的修改目录及其内容的属性<br />-f 忽略大部分错误信息<br />-v 设置文件的版本号</p>
<p><span style="background-color: #c0c0c0;">模式：</span></p>
<p>mode：+-=效果类似于chmod，后面可以附加以下标记位：</p>
<p>a：文件只能被附加内容<br />c：文件被压缩<br />d：no dump<br />e：扩展格式<br />i：文件不可变，即使ROOT也不能改变其内容<br />j：数据日志<br />s：安全删除（删除后以0填充）<br />t：no ail-merging<br />u：禁止删除<br />A：禁止atime更新<br />D：同步目录更新<br />S：同步更新<br />T：目录层次的顶端<br />下面的属性为只读，不能被chattr修改<br />h：巨大文件<br />E：压缩错误<br />I：被索引的目录<br />X：压缩原始访问<br />Z：被压缩的脏文件</p>
<p><span style="background-color: #c0c0c0;">举例：</span></p>
<pre class="crayon-plain-tag">cd ~/Test
touch  file.tar.gz

#添加一个压缩属性
chattr +c file.tar.gz
#lsattr显示：
#--------c----e-- ./file.tar.gz</pre>
</td>
</tr>
<tr>
<td class="blog_h2">lsattr</td>
<td>
<p>列出Linux文件系统上文件的属性
<p><span style="background-color: #c0c0c0;">格式：</span><br />lsattr [ -RVadv ] [ files... ]</p>
<p><span style="background-color: #c0c0c0;">选项：</span><br />-R 递归的列出目录及其内容的属性<br />-a 列出目录中所有文件<br />-d 列出目录，而不是其中的文件<br />-v 显示文件版本</p>
<p><span style="background-color: #c0c0c0;">举例：</span></p>
<pre class="crayon-plain-tag">cd ~
ls Test        #列出Test下文件的属性
#输出--------c----e-- Test/file.tar.gz
ls -d Test     #列出目录Test本身的属性
#输出-------------e-- Test</pre>
</td>
</tr>
<tr>
<td class="blog_h2">ln</td>
<td>
<p>创建文件链接，TARGET为已经存在的被链接的文件
<p><span style="background-color: #c0c0c0;">格式：</span><br />ln [OPTION]... [-T] TARGET LINK_NAME <br />ln [OPTION]... TARGET <br />ln [OPTION]... TARGET... DIRECTORY<br />ln [OPTION]... -t DIRECTORY TARGET...</p>
<p><span style="background-color: #c0c0c0;">选项：</span><br />--backup[=CONTROL] 创建目标文件的备份<br />-b 与上面类似<br />-d, -F, --directory 允许超级用户硬链接目录<br />-f, --force 移除已经存在的DEST文件<br />-i, --interactive 提示用户是否删除目标<br />-L, --logical 为符号链接引用创建硬链接<br />-n, --no-dereference 按照普通文件的方式对待是符号链接的目标<br />-P, --physical 创建硬链接<br />s, --symbolic 创建符号链接<br />-S, --suffix=SUFFIX 备份文件后缀<br />-T, --no-target-directory 将链接名称作为普通文件看待<br /><span style="background-color: #c0c0c0;">举例：</span></p>
<pre class="crayon-plain-tag">cd ~/Test
mkdir target &amp;&amp; mkdir target/tgtsub  &amp;&amp; touch target/tgtfile

ln -s target target.ln                #创建target目录的符号链接
ln -s target.ln target.ln.ln          #创建符号链接的符号链接

ln -P target/tgtfile  tgtfile.pln     #创建文件的硬链接
rm target/tgtfile                     #文件tgtfile.pln仍然有效
ln -P target target.pln               #出错，不得对目录进行硬链接</pre>
</td>
</tr>
<tr>
<td class="blog_h2">readlink</td>
<td>
<p>显示符号连接所指向的文件
</td>
</tr>
<tr>
<td class="blog_h2">find</td>
<td>
<p>在目录层次中搜索匹配的文件</p>
<p><span style="background-color: #c0c0c0;">格式：</span><br />find [-H] [-L] [-P] [-D debugopts] [-Olevel] [path...] [expression]</p>
<p><span style="background-color: #c0c0c0;">基本选项：</span><br />-H -L -P 三个选项用于处理符号链接。<br />-P 从不跟随（解引用）符号链接，这是默认行为。当检查符号链接的属性或者打印其信息时，针对符号链接本身而不是其链接目标<br />-L 跟随（解引用）符号链接<br />-H 不跟随（解引用）符号链接，除了命令行参数指定的符号链接文件<br />-D debugoptions 打印诊断信息，调试选项使用逗号分隔<br />-Olevel 启用查询优化，启用后测试表达式的顺序将会被调整，以提高执行速度<br />　　0 与级别1相同<br />　　1 默认优化级别，表达式被重新排序，使与文件名称相关的表达式（-name、-regex）优先执行<br />　　2 任何-type、-xtype测试在-name、-regex后执行，但是被提前到需要从inode获取信息的表达式之前<br />　　3 完全的基于成本的优化器，低成本的测试被优先执行</p>
<p><span style="background-color: #c0c0c0;">表达式由选项、测试、动作三部分组成</span></p>
<p><span style="background-color: #c0c0c0;">表达式选项：</span><br />所有选项的返回值都是true，除了-daystart、-follow、-regextype，这些选项影响所有测试，选项最好放在表达式的最前面<br />-daystart 以自然日的开始点，而不是24小时前来度量时间（-amin, -atime, -cmin, -ctime, -mmin, -mtime）<br />-depth -d 在处理目录本身之前，先处理其内容<br />-ignore_readdir_race 正常情况下，如果find命令stat文件失败时（比如在find期间目标文件被删除）将发出一个错误信息，指定该选项择不会提示<br />-maxdepth levels 向下搜索子目录的最大深度<br />-mindepth levels 对于小于该选项的文件不执行任何测试或者动作，指定为1，表示处理除了命令行参数以外的所有文件<br />-mount 不去向下搜索位于其它文件系统上的文件<br />-noignore_readdir_race <br />-noleaf 禁止在非UNUX文件系统，MS-DOS系统，CD-ROM文件系统中进行最优化查找<br />-regextype type 改变-regex、-iregex 测试所使用的正则式类型，默认emacs，其它可以是posix-awk、posix-basic、posix-egrep、posix-extended<br />-warn, -nowarn 打开或者关闭警告信息</p>
<p><span style="background-color: #c0c0c0;">表达式测试：</span><br />数字参数可以设置为以下形式：+n 多于n；-n 少于n, n 等于n<br />-amin n 当前文件在n分钟前被访问过<br />-anewer file 当前文件的访问时间比file的修改时间更晚<br />-atime n 文件在n*24小时前被访问过，-atime +1表示多于1个24小时之前被最后访问过，即2天前被最后访问过<br />-cmin n 文件的状态在n分钟前改变过<br />-cnewer file 当前文件状态的改变时间比file的修改时间更晚<br />-ctime n 文件的状态在n*24小时前改变过<br />-empty 文件是空白的，或者是空目录<br />-executable 文件时刻执行的、或者命令是可搜索的<br />-false 总返回false<br />-fstype type 文件处于type文件系统上<br />-gid n 文件的组ID（数字表示）是n<br />-group gname 文件的组名称是gname<br />-ilname pattern 与-lname类似，但是大小写不敏感<br />-iname pattern 与-name类似，但是大小写不敏感<br />-inum n 文件的inode为n<br />-iregex pattern 与-regex类似，但是大小写不敏感<br />-iwholename pattern 与wholename类似，但是大小写不敏感<br />-links n 文件有n个链接<br />-lname pattern 文件是一个符号链接，并且其内容匹配pattern<br />-mmin n 当前文件在n分钟前被修改过<br />-mtime n 文件在n*24小时前被修改过<br />-name pattern 文件的基本名称（去除目录部分）匹配pattern<br />-newer file 当前文件的修改时间比file的修改时间更晚<br />-newerXY reference 比较当前文件与reference的时间戳，reference是一个文件名或者绝对时间，XY为其它字母的占位符，这些占位符用于表示reference的什么字段被用于比较：<br />　　a 访问时间<br />　　B 创建时间<br />　　c inode状态改变时间<br />　　m 修改时间<br />　　t reference被解释为绝对时间<br />-nogroup 没有组与文件的数字GID对应<br />-nouser 没有用户与文件的数字UID对应<br />-path pattern 文件名称匹配pattern<br />-perm mode 文件权限比特位精确匹配<br />-perm -mode 所有权限比特位被设置给当前文件<br />-perm /mode 任一权限比特位被设置给当前文件<br />-readable 匹配可读的文件<br />-regex pattern 文件名匹配正则式<br />-samefile name 当前文件与name指定的文件具有相同的inode<br />-size n[cwbkMG] 文件的尺寸为n。b表示512字节块；c表示字节；w表示双字节；k表示KB；M表示MB；G表示GB<br />-true 总是真<br />-type c 文件类型匹配。 b块；c字符；d目录；p命名管道；f普通文件；l符号链接；s套接字文件<br />-uid n 文件的数字UID是n<br />-used n 文件在其状态改变后n天被访问过<br />-user uname 文件的所有者用户名为uname<br />-wholename pattern 同-path<br />-writable 文件是可写入的<br />-xtype c 与-type类似，除了对于符号链接，如果-H -P被指定，与目标文件进行比较；如果-L被指定，则c为l是返回true</p>
<p><span style="background-color: #c0c0c0;">表达式动作：</span><br />-delete <br />删除匹配的文件，如果删除成功，返回true，否者打印错误信息，如果删除失败，find的退出状态为非0<br />-exec command ; <br />执行一个命令，如果命令的退出状态为0，返回true。在此动作之后的所有命令行参数被认为是command的参数，直到遇到分号（;），{}被替换为当前文件的名称<br />-exec command {} + <br />与上面类似，但是匹配的文件名将作为command的尾部参数，command执行的次数要远小于匹配文件数<br />-execdir command ; -execdir command {} + <br />与上面类似，但是命令将在找到文件的子目录中执行<br />-fls file <br />返回true。类似于ls，但是使用-fprint格式输出到目标文件<br />-fprint file <br />返回true。打印完整的文件名到文件，如果file不存在，会自动创建（即使测试不匹配），否则会被截断，文件/dev/stdout、/dev/stderr被作为标准输出、标准错误特别处理<br />-fprint0 file <br />返回true。类似 -print0，但是使用-fprint格式输出到目标文件<br />-fprintf file format <br />返回true。类似-fprint和-printf的组合<br />-ls <br />返回true; 以ls -dils形式打印到标准输出，块的单位为1KB，如果环境变量POSIXLY_CORRECT被设置，块单位为512B<br />-ok command ; <br />类似于-exec，但是会提示用户是否执行，如果用户同意，则执行之，否则返回false，如果命令运行，其标准输入重定向到/dev/null<br />-okdir command ; <br />类似-execdir和-ok组合<br />-print <br />返回true。打印完整的文件名到标准输出并换行<br />-print0 <br />返回true。打印完整的文件名到标准输出并附加null字符，便于处理文件名中包含换行符或者其他空白字符的情况<br />-printf format 返回true。在标准输出上打印format，支持\转义和%指令，列宽度和精度可以使用C语言printf函数风格指定，详见man手册<br />-prune <br />返回true; 如果文件是目录，不向下处理其内容<br />-quit <br />立即退出</p>
<p><span style="background-color: #c0c0c0;">表达式组合操作符：</span><br />　　( expr ) 强制优先级，由于括号在shell中是特殊字符，可能需要进行转义处理<br />　　! expr 取反<br />　　expr1 expr2 并且<br />　　expr1 -a expr2 并且<br />　　expr1 -o expr2 或者<br />　　expr1 , expr2 两个表达式都被计算，但是返回第二个表达式的值</p>
<p><span style="background-color: #c0c0c0;">举例：</span></p>
<pre class="crayon-plain-tag">find ~/ -name '*.txt' #查找txt文件
#在/tmp目录下寻找名为core的文件，并删除之
find /tmp -name core -type f -print | xargs /bin/rm -f
#在/tmp目录下寻找名为core的文件，并删除之，能正确处理文件名中的特殊字符
find /tmp -name core -type f -print0 | xargs -0 /bin/rm -f
#对当前目录下所有普通文件执行file命令，以获取其类型，注意;被转义，{}被括号保护
find . -type f -exec file '{}' \;
#遍历整个文件系统一次，输出setuid文件到suid.txt，输出大文件到big.txt
find / \
\( -perm -4000 -fprintf /root/suid.txt %#m %u %p\n \) , \
\( -size +100M -fprintf /root/big.txt %-10s %p\n \)
#在当前用户家目录中查找最近24小时内被修改过的文件
find $HOME -mtime 0
#搜索可执行却不可读的文件
find /sbin /usr/sbin -executable \! -readable -print
#搜索当前目录下权限模式为664的文件并打印
find . -perm 664 -print 
#搜索当前目录下权限模式包含了664所指定的权限位的文件
find . -perm -664
#搜索可以被某个人写入的文件

#删除core开头的文件，{}表示用匹配的文件路径名替换
find ~/ -name 'core*' -exec rm '{}' \; 

# 显示当前目录下包含的文件总数
find . -type f | wc -l

# 显示当前目录的所有直接子目录或文件
find . -maxdepth 1</pre>
</td>
</tr>
<tr>
<td class="blog_h2">touch</td>
<td>更新文件被存取或修改的时间，如果不存在文件则创建</td>
</tr>
<tr>
<td class="blog_h2">basename</td>
<td>从文件名中去掉路径信息，只打印出文件名</td>
</tr>
<tr>
<td class="blog_h2">dirname</td>
<td>从带路径的文件名中去掉文件名，只打印出路径信息</td>
</tr>
<tr>
<td class="blog_h2">cksum</td>
<td>sum, cksum, md5sum, sha1sum等均可用来生成校验和，验证文件的完整性</td>
</tr>
<tr>
<td class="blog_h2">shred</td>
<td>用随机字符填充文件，使得文件无法恢复</td>
</tr>
<tr>
<td class="blog_h2">mktemp</td>
<td>使用一个唯一的文件名来创建一个临时文件</td>
</tr>
<tr>
<td class="blog_h2">file</td>
<td>
<p>确定文件类型的工具
<p><span style="background-color: #c0c0c0;">格式：</span><br />file[OPTIONS...] [FILE...]</p>
<p><span style="background-color: #c0c0c0;">选项：</span><br />-b,--brief 不显示文件名字<br />-f,--files 读取待测试的文件<br />-F,--seperator 设置分隔符，默认:<br />-i,--mime 显示文件的MIME类型<br />-L,--dereference 显示符号链接所指向文件信息<br />-h,--no-dereference</p>
<p><span style="background-color: #c0c0c0;">示例：</span></p>
<pre class="crayon-plain-tag">#显示当前目录下所有文件的类型
file *
#仅显示类型，不显示名称
file --brief 1.txt
#显示文件的MIME类型
file --mime 1.txt</pre>
</td>
</tr>
</tbody>
</table>
<div class="blog_h1"><span class="graybg">时间与日期相关命令</span></div>
<table style="width: 100%;" border="1" cellspacing="0" cellpadding="5">
<thead>
<tr>
<td style="width: 100px; text-align: center;">命令</td>
<td style="text-align: center;"> 说明</td>
</tr>
</thead>
<tbody>
<tr>
<td class="blog_h2">date</td>
<td>
<p>打印日期和时间到 stdout
<p><span style="background-color: #c0c0c0;">格式：</span><br />date [OPTION]... [<span style="background-color: #ff0000;">+</span>FORMAT]<br />date [-u|--utc|--universal] [MMDDhhmm[[CC]YY][.ss]]</p>
<p><span style="background-color: #c0c0c0;">选项：</span><br />-d, --date=STRING 显示字符串所代表的日期，而非当前日期<br />-r, --reference=FILE 显示文件的最后修改日期时间<br />-R, --rfc-2822 使用RFC 2822格式输出时间，例如：Mon, 07 Aug 2006 12:34:56 -0600<br />--rfc-3339=TIMESPEC 使用RFC 3339格式输出日期时间<br />-s, --set=STRING 根据字符串所代表的时间来设置<br />-u, --utc, --universal 打印标准时间</p>
<p><span style="background-color: #c0c0c0;">日期时间格式：</span><br />%% 转义%<br />%a 本地化的周几简称，例如Sun<br />%A 本地化的周几完整名称，例如Sunday<br />%b 本地化的月份简称，例如Jan<br />%B 本地化月份完整名称，例如January<br />%c 本地化日期时间，例如Thu Mar 3 23:05:25 2005<br />%C 世纪<br />%d 月中的第几天，例如01<br />%D 日期，即%m/%d/%y<br />%e 月中的第几天，空格补白，即%_d<br />%F 日期，即%Y-%m-%d<br />%h 即%b<br />%H 小时(00..23)<br />%I 小时(01..12)<br />%j 年中的第几天(001..366)<br />%k 小时( 0..23)<br />%l 小时( 1..12)<br />%m 月份(01..12)<br />%M 分钟(00..59)<br />%n 新行<br />%N 纳秒(000000000..999999999)<br />%p 本地化的AM/PM，如果没有留空<br />%P 类似%p,小写<br />%r 本地化的12小时制时间(11:11:04 PM)<br />%R 24小时时间 %H:%M<br />%s 从1970-01-01 00:00:00 UTC开始的秒数<br />%S 秒(00..60)<br />%t 制表<br />%T 时间，即%H:%M:%S<br />%u 周中的第几天，周一为1(1..7)<br />%U 年中的第几周，周日为第一天(00..53)<br />%V ISO年中的第几周，周一为第一天 (01..53)<br />%W 年中的第几周，周一为第一天(00..53)<br />%x 本地化日期展示形式(12/31/99)<br />%X 本地化时间展示形式(23:13:48)<br />%y 年度最后2位(00..99)<br />%Y 年度<br />下面的符号可以紧随%后<br />- 不要补白字段<br />_ 使用空格补白<br />0 使用0补白<br />^ 如果可能，使用大写<br /># 如果可能，使反转大小写</p>
<div><span style="background-color: #c0c0c0;">举例：</span></div>
<pre class="crayon-plain-tag">#注意格式的+号
date "+%Y%m%d%H%M%S"
#输出20150510165155

date '+%s'
#输出1970-01-01到当前时间点消逝的秒数

date -R
#输出Fri, 15 May 2015 09:30:05 -0400
#当地时间9点30分，比世界时晚4小时（西四区）
#北京比世界时早8小时（东八区）</pre>
</td>
</tr>
<tr>
<td class="blog_h2">zdump</td>
<td>
<p>查看特定时区的当前时间
<p><span style="background-color: #c0c0c0;">举例：</span></p>
<pre class="crayon-plain-tag">#显示中国标准时间
zdump PRC</pre>
</td>
</tr>
<tr>
<td class="blog_h2">time</td>
<td>
<p>输出统计出来的命令执行的时间
<p><span style="background-color: #c0c0c0;">举例：</span></p>
<pre class="crayon-plain-tag">time ls  &gt; /dev/null
#输出内容：
#real    0m0.002s  真实世界的时间
#user    0m0.001s  用户态时间
#sys     0m0.002s  内核态时间</pre>
</td>
</tr>
<tr>
<td class="blog_h2">cal</td>
<td>从 stdout 中输出一个格式比较整齐的日历</td>
</tr>
<tr>
<td class="blog_h2">sleep</td>
<td>指定需要暂停的秒数并休眠当前进程</td>
</tr>
<tr>
<td class="blog_h2">usleep</td>
<td>Microsleep 睡眠微秒</td>
</tr>
</tbody>
</table>
<div class="blog_h1"><span class="graybg">未分类的基本命令</span></div>
<table style="width: 100%;" border="1" cellspacing="0" cellpadding="5">
<thead>
<tr>
<td style="width: 100px; text-align: center;">命令</td>
<td style="text-align: center;"> 说明</td>
</tr>
</thead>
<tbody>
<tr>
<td class="blog_h2">xargs</td>
<td>
<p>从标准输入解析并执行命令行
<p>xargs从标准输入读取数据，使用空白符或者换行符分隔成多个条目（标准输入的空白行被忽略），并执行命令<br />如果不指定命令，则默认使用/bin/echo。<strong>读取到的条目作为参数附加在命令初始参数（initial-arguments）后面</strong><br />由于UNIX文件名可以包含空白符甚至换行符，因此默认选项往往导致错误，最好使用-0选项<br />如果命令调用的退出状态是25，则xargs立即中止读入任何标准输入并在stderr显示错误信息</p>
<p><span style="background-color: #c0c0c0;">格式：</span><br /><strong>xargs</strong> <br />　　[-0prtx] [-E eof-str] [-e[eof-str]] [--eof[=eof-str]] [--null] <br />　　[-d delimiter] [--delimiter delimiter] [-I replace-str] [-i[replace-str]] <br />　　[--replace[=replace-str]] [-l[max-lines]] [-L　max-lines] <br />　　[--max-lines[=max-lines]] [-n max-args] [--max-args=max-args] <br />　　[-s max-chars] [--max-chars=max-chars] [-P max-procs] [--max-procs=max-procs] <br />　　[--interactive] [--verbose] [--exit]　[--no-run-if-empty] [--arg-file=file] <br />　　[--show-limits] [--version] [--help]<strong> [command [initial-arguments]]</strong></p>
<p><span style="background-color: #c0c0c0;">选项：</span><br />-a --arg-file 从文件而不是stdin读取条目<br />-0 --null 使用null字符而不是空白符分隔条目，并且所有字符（包括引号和反斜杠）作为字面值看待 <br />-d --delimiter 指定条目的分隔符为指定的字符，不支持多字节字符<br />-E eof-str 设置EOF字符串，如果该字符串作为输入的一行出现，则剩余的输入被忽略<br />-I replace-str 替换initial-arguments中的replace-str为从stdin读取到的名称<br />-L max-lines 每一个命令行最多使用的非空白行数<br />-n --max-args 每一个命令行最多使用的参数个数<br />-r --no-run-if-empty 如果输入没有非空白行，则不执行命令 <br />-s --max-chars 每个命令行最多使用的字符数<br />-t --verbose 在执行命令前打印之<br />-x --exit 如果字符数超过设定（-s）则退出s<br />-P --max-procs 同时最多运行的进程数，默认1，如果设置为0，则尽可能运行更多地进程，须与-n联用，否则只会有开启一个进程</p>
<p><span style="background-color: #c0c0c0;">退出状态：</span><br />　　0 执行成功<br />　　123 如果任何命令返回1-125之间的状态码<br />　　124 如果命令返回255状态码<br />　　125 如果命令被信号杀死<br />　　126 如果命令无法执行<br />　　127 如果命令不存在<br />　　1 发生其它错误</p>
<p><span style="background-color: #c0c0c0;">举例：</span></p>
<pre class="crayon-plain-tag">#查找目录/tmp中的core文件，并且删除之，能够正确处理带有空白符的文件名
find /tmp -name core -type f -print0 | xargs -0 /bin/rm -f
#输出系统中所有的用户名 
cut -d: -f1 &lt; /etc/passwd | sort | xargs echo

# 此命令可以用来去除（trim）首尾空白
echo "   hello  " | xargs</pre>
</td>
</tr>
<tr>
<td class="blog_h2">
<p>env
</td>
<td>
<p>在修改的环境下（即一系列修改后的环境变量）运行一个程序</p>
<p><span style="background-color: #c0c0c0;">格式：</span><br />env [OPTION]... [-] [NAME=VALUE]... [COMMAND [ARG]...]</p>
<p><span style="background-color: #c0c0c0;">选项：</span><br />-i 从空白环境开始<br />-u 取消环境变量的值</p>
</td>
</tr>
<tr>
<td class="blog_h2">printenv</td>
<td>显示出所有的环境变量</td>
</tr>
<tr>
<td class="blog_h2">which</td>
<td>给出命令的完整路径</td>
</tr>
<tr>
<td>locate</td>
<td>
<p>给出指定文件的完整位置，示例：</p>
<pre class="crayon-plain-tag">locate nginx.conf
# /usr/conf/nginx.conf</pre>
</td>
</tr>
<tr>
<td class="blog_h2">whereis</td>
<td>给出命令的完整路径、man页的完整路径</td>
</tr>
<tr>
<td class="blog_h2">chroot</td>
<td>改变根目录来运行某个命令</td>
</tr>
<tr>
<td class="blog_h2">pivot_root</td>
<td>
<p>改变根文件系统，将当前进程的根文件系统移动到其它目录，并将另外一个目录作为新的根文件系统
<p><span style="background-color: #c0c0c0;">格式：</span></p>
<pre class="crayon-plain-tag">pivot_root new_root put_old</pre>
<p><span style="background-color: #c0c0c0;">示例：</span></p>
<pre class="crayon-plain-tag">cd new_root
pivot_root . put_old
exec chroot . command</pre>
<p> 需要注意，chroot必须在新、旧根目录都可用。pivot_root可能不会自动为当前Shell chroot</p>
</td>
</tr>
<tr>
<td>man</td>
<td>
<p>查看系统手册，可以查看陈故乡、工具、编程函数等各类对象的手册。</p>
<p><span style="background-color: #c0c0c0;">格式：</span></p>
<pre class="crayon-plain-tag">man [section] page
# 示例
man  2 clone</pre>
<p>手册是分为多个段（Section）的，各个段中可以具有名字相同的page。当你在网络上看到namespaces(7)这样的Man Page链接时，就知道目标是在段7的namespaces页面。</p>
<p>段的定义如下：</p>
<ol>
<li>可执行程序或Shell命令</li>
<li>系统调用（内核提供的函数）</li>
<li>库调用（编程库中提供的函数）</li>
<li>特殊文件，主要在/dev/...这些页面</li>
<li>文件格式和约定，例如/etc/passwd</li>
<li>游戏</li>
<li>杂项</li>
<li>系统管理命令，通常仅供root使用</li>
<li>内核例程（非标准）</li>
</ol>
</td>
</tr>
</tbody>
</table>
<div class="blog_h1"><span class="graybg">作业控制命令</span></div>
<table style="width: 100%;" border="1" cellspacing="0" cellpadding="5">
<thead>
<tr>
<td style="width: 100px; text-align: center;">命令</td>
<td style="text-align: center;"> 说明</td>
</tr>
</thead>
<tbody>
<tr>
<td class="blog_h2">at</td>
<td>作业控制命令， 用来在指定时间执行给定的命令集合</td>
</tr>
<tr>
<td class="blog_h2">crontab</td>
<td>
<p>维护某个用户的CRON守护程序列表。<br />crontab可以用来添加、删除、列出CRON守护程序，每个用户有自己的crontab定义，一律位于目录/var/spool/cron/crontabs中，通常不需要直接编辑这些文件<br />如果配置文件/etc/cron.allow存在，那么只有其中列出的用户才能使用crontab<br />如果配置文件/etc/cron.deny存在，那么其中列出的用户不能使用crontab</p>
<p><span style="background-color: #c0c0c0;">格式：</span><br />crontab [ -u user ] file<br />crontab [ -u user ] [ -i ] { -e | -l | -r }</p>
<p><span style="background-color: #c0c0c0;">选项：</span><br />-u 指定crontab所属的用户，每个用户都有独立的crontab，里面的条目都以该用户为身份执行<br />-l 列出crontab的内容<br />-r 移除当前crontab<br />-e 使用默认编辑器编辑crontab</p>
<p><span style="background-color: #c0c0c0;">桌面应用支持：</span></p>
<p>守护程序脚本中需要添加：<pre class="crayon-plain-tag">export DISPLAY=:0.0</pre></p>
<p><span style="background-color: #c0c0c0;">模拟执行：</span></p>
<p>如果你的脚本在命令行中运行正常，但是在crontab中不能运行，可能是两种环境下的环境变量有差异。参考下面的方法立即模拟crontab的执行：</p>
<p>首先导出crontab的环境变量：</p>
<pre class="crayon-plain-tag">* * * * *  /usr/bin/env &gt; /root/cron-env</pre>
<p>然后模拟执行：</p>
<pre class="crayon-plain-tag">/usr/bin/env -i $(cat /root/cron-env) /my/crontab/item.sh</pre>
</td>
</tr>
<tr>
<td class="blog_h2">cron</td>
<td>
<p>计划任务调度器
</td>
</tr>
<tr>
<td class="blog_h2">jobs</td>
<td>查看所有后台运行的作业，可以看到jobnumber</td>
</tr>
<tr>
<td class="blog_h2">batch</td>
<td>在系统平均载量降到0.8 以下时执行一次性的任务</td>
</tr>
<tr>
<td class="blog_h2">nice</td>
<td>使用修改后的优先级来运行一个后台作业。 优先级从19(最低)到-20(最高)。 只有root 用户可以设置负的优先级</td>
</tr>
<tr>
<td class="blog_h2">nohup</td>
<td>保持一个命令的运行，即使用户退出Terminal也不会中断其执行（不会收到SIGHUP信号）</td>
</tr>
<tr>
<td class="blog_h2">pidof</td>
<td>取得一个正在运行的作业的PID</td>
</tr>
<tr>
<td class="blog_h2">cron</td>
<td>任务调度程序</td>
</tr>
<tr>
<td class="blog_h2">watch</td>
<td>
<p>以指定的时间间隔来重复运行一个命令，可以查看程序输出的变化</p>
<p><span style="background-color: #c0c0c0;">格式：</span><pre class="crayon-plain-tag">watch [options] command</pre></p>
<p><span style="background-color: #c0c0c0;">选项：</span></p>
<p>-d 高亮显示两次运行的结果变化<br />-n 运行间隔，单位秒<br />-t 不显示头信息，包括运行间隔，运行的命令等</p>
<p><span style="background-color: #c0c0c0;">示例：</span></p>
<pre class="crayon-plain-tag"># 持续监控软中断
watch -d -n 1 'cat /proc/softirqs'</pre>
</td>
</tr>
<tr>
<td class="blog_h2">fg</td>
<td>将后台中的命令调至前台继续运行。如果后台中有多个命令，可以用 fg %jobnumber将选中的作业调到前台</td>
</tr>
<tr>
<td class="blog_h2">bg</td>
<td>将作业调度到后台执行，如果有多个后台作业处于暂停（ctrl + z将导致暂停）状态，可以用bg %jobnumber将选中的作业调度执行</td>
</tr>
</tbody>
</table>
<div class="blog_h1"><span class="graybg">文本处理命令</span></div>
<div class="blog_h2"><span class="graybg">简单命令</span></div>
<table style="width: 100%;" border="1" cellspacing="0" cellpadding="5">
<thead>
<tr>
<td style="width: 100px; text-align: center;">命令 </td>
<td style="text-align: center;">说明 </td>
</tr>
</thead>
<tbody>
<tr>
<td class="blog_h3">sort</td>
<td>
<p>将文件的每一行作为一个单位，按ASCII顺序进行比较，并按升序输出
<p><span style="background-color: #c0c0c0;">格式：</span><br />sort [OPTION]... [FILE]...<br />sort [OPTION]... --files0-from=F</p>
<p><span style="background-color: #c0c0c0;">选项：</span><br />-u 在输出中去除重复行<br />-r 按降序排列<br />-o 将结果输出到目标文件，输出到原文件时用于替代重定向<br />-n 按照数值来排序<br />-t 按列排序，列的分隔符<br />-k 按列排序，第几列，例如： -k 3r -k 2 按第3列降序排列，按第2行作次要升序排列<br />-f 忽略大小写排序<br />-c 检查文件是否排好序，如果不是，输出第一行乱序的信息，退出码1<br />-C 检查文件是否排好序，如果不是，退出码1<br />-M 按月份进行排序（例如：JAN小于FEB）<br />-b 忽略前导空白符</p>
<p><span style="background-color: #c0c0c0;">举例：</span></p>
<pre class="crayon-plain-tag">#使用第二列排序，分隔符为冒号
sort -n -k 2 -t : readme.txt</pre>
</td>
</tr>
<tr>
<td class="blog_h3">cat,tac</td>
<td>
<p>输出文件的完整内容<br />-n 在目标文件中的所有行前边插入行号<br />-b 与 -n 选项类似，但不对空行进行编号<br />-v 可以使用 ^ 标记法来显示出不可打印字符<br />-s 把多个空行压缩成一个空行
<p>tac从文件的结尾列出文件</p>
</td>
</tr>
<tr>
<td class="blog_h3">tee</td>
<td>
<p>读取标准输入，并将内容输出到文件和标准输出</p>
<p><span style="background-color: #c0c0c0;">格式：</span><pre class="crayon-plain-tag">tee [OPTION]... [FILE]...</pre></p>
<p><span style="background-color: #c0c0c0;">选项：</span></p>
<p>-a, --append 附加内容到输出文件尾部，而不是覆盖它的内容<br />-i, --ignore-interrupts 忽视中断信号</p>
</td>
</tr>
<tr>
<td class="blog_h3">more, less</td>
<td>
<p>分页显示文本文件或stdout</p>
<p>more命令逐页的显示文本的内容，它在启动时读取整个文件的全部内容，按Space键可以向后翻页</p>
<p>less更加强大，它和more一样支持份也显示，但是支持PageUp、PageDown进行前后翻页，并且支持搜索。在提示符（:）后输入：</p>
<ol>
<li>/searchText，向下搜索指定的文本</li>
<li>?searchText，向上搜索指定的文本</li>
<li>n，向后继续查找搜索结果</li>
<li>N，向前继续查找搜索结果</li>
<li>d，向后翻半页</li>
<li>u，向前翻半页</li>
<li>Enter，向后滚动一行</li>
<li>y，向前滚动一行</li>
<li>Q，退出less命令</li>
</ol>
</td>
</tr>
<tr>
<td class="blog_h3">rev</td>
<td>把每一行中的内容反转，并且输出到 stdout 上</td>
</tr>
<tr>
<td class="blog_h3">uniq</td>
<td>
<p>过滤器，将会删除一个已排序文件中的重复行.<span style="background-color: #c0c0c0;">这个命令经常出现在 sort 命令的管道后</span></p>
<p><span style="background-color: #c0c0c0;">选项：</span></p>
<p>-c 在输出行前面加上每行在输入文件中出现的次数</p>
<p><span style="background-color: #c0c0c0;">举例</span></p>
<pre class="crayon-plain-tag">#输出3文件的内容，排序、去重、输出到final.list
cat list-1 list-2 list-3 | sort | uniq &gt; final.list  </pre>
</td>
</tr>
<tr>
<td class="blog_h3">expand, unexpand</td>
<td>expand 将会把每个tab 转化为一个空格；unexpand功能相反</td>
</tr>
<tr>
<td class="blog_h3">dos2unix</td>
<td>转换换行符的格式</td>
</tr>
<tr>
<td class="blog_h3">cut</td>
<td>
<p>从文件中提取特定字段（列）<br /><span style="background-color: #c0c0c0;">格式：</span><br />cut OPTION... [FILE]...
<p><span style="background-color: #c0c0c0;">选项：</span><br />-d 字段定界符<br />-f 选定字段列表</p>
<p><span style="background-color: #c0c0c0;">举例：</span></p>
<pre class="crayon-plain-tag">#按空格分隔字段，提取第1、3、11、12个字段
uname -a | cut -d" " -f1,3,11,12</pre>
</td>
</tr>
<tr>
<td class="blog_h3">paste</td>
<td>将多个文件，以每个文件一列的形式合并到一个文件</td>
</tr>
<tr>
<td class="blog_h3">join</td>
<td>
<p>能够操作2个文件，它可以将那些具有特定标记域的行合并起来，并且将结果输出到stdout
</td>
</tr>
<tr>
<td class="blog_h3">head</td>
<td>将一个文件的头（ 默认为10 行）打印到 stdout 上 </td>
</tr>
<tr>
<td class="blog_h3">tail</td>
<td>
<p>将一个文件的尾（ 默认为10 行）打印到 stdout 上</p>
<p><span style="background-color: #c0c0c0;">选项：</span></p>
<p>-f 继续显示添加到文件中的行<br />-s N 和-f配合使用时，每次获取更多数据后休眠N秒<br />-c N 显示文件的最后N字节<br />-n N 显示文件的最后N行</p>
</td>
</tr>
<tr>
<td class="blog_h3">grep</td>
<td>
<p>使用正则表达式的多用途文本搜索工具</p>
<p><span style="background-color: #c0c0c0;">格式：</span><br />grep [OPTIONS] PATTERN [FILE...]<br />grep [OPTIONS] [-e PATTERN | -f FILE] [FILE...]</p>
<p><span style="background-color: #c0c0c0;">选项：</span><br /><span style="background-color: #c0c0c0;">-E, --extended-regexp</span> 将PATTERN解释为扩展正则式（extended regular expression），等价于egrep<br />-<span style="background-color: #c0c0c0;">F, --fixed-strings</span> 将PATTERN解释为固定字符串的列表，以换行分隔，等价于fgrep <br />-G, --basic-regexp 将PATTERN解释为基本正则式（basic regular expression）<br />-P, --perl-regexp 将PATTERN解释为Perl正则式（basic regular expression），可以使用前向捕获等高级功能，例如<pre class="crayon-plain-tag">grep -P -o '[0-9]+(?=,)'</pre>要求匹配类似123,这样的子串，但是不消耗掉逗号</p>
<p>-e PATTERN, --regexp=PATTERN 指定匹配的PATTERN<br />-f FILE, --file=FILE 从文件读取PATTERN，空文件不匹配任何目标<br />-i,-y, --ignore-case 忽略PATTERN和输入文件中的大小写<br />-v, --invert-match 反转匹配，即选择不匹配的行<br />-w, --word-regexp 仅选择匹配项组成完整单词的行<br />-x, --line-regexp 仅选择匹配完整行的</p>
<p>-c, --count 取消正常输出，仅显示输入文件中匹配的行总数<br />-L, --files-without-match 取消正常输出，打印出第一个不匹配的文件名<br />-l, --files-with-matches 取消正常输出，打印出第一个匹配的文件名<br />-m NUM, --max-count=NUM 在到达NUM行后停止读入输入文件<br />-o, --only-matching 仅仅打印行的匹配部分<br />-q, --quiet, --silent 不打印，仅仅输出退出码<br />-s, --no-messages 取消对不存在或者不可见文件的错误信息</p>
<p>-b, --byte-offset 在每行前打印基于文件的行首的偏移量，如果指定-o则打印匹配部分的偏移量<br />-H, --with-filename 为每个匹配在行首打印文件名称，如果有多个输入文件，这是默认选项<br />-h, --no-filename 取消打印行首的文件名称，如果只有一个输入文件，这是默认选项<br />-n, --line-number 为每一行输出打印其相对于所在文件的行号</p>
<p>-a, --text 将二进制文件作为文本处理<br />-D ACTION, --devices=ACTION 如果输入文件时设备、FIFO或者Socket，使用ACTION来处理之，默认的ACTION是read<br />-d ACTION, --directories=ACTION 输入输入文件时目录，使用ACTION来处理之，默认的ACTION是read，即作为普通文件读入；recurse读入其中的所有子文件<br />--exclude=GLOB 排除匹配通配符的文件<br />--exclude-from=FILE 排除匹配从FILE中读取的通配符的文件<br />--exclude-dir=DIR 在递归搜索中，排除匹配DIR的目录<br />-I 等价于--binary-files=without-match <br />--include=GLOB 仅搜索匹配通配符的文件<br />-r, --recursive 递归搜索子文件与文件夹<br />-R, --dereference-recursive 递归搜索子文件与文件夹，并且Follow所有符号链接</p>
<p>--line-buffered 使用输出缓冲<br />--mmap 如果可能，使用系统调用mmap来读取输入，而不是read<br />-U, --binary 以二进制方式处理文件<br />-z, --null-data 把输入作为一系列行，每行以ASCII NUL（\0）分隔，而不是换行符</p>
<p><span style="background-color: #c0c0c0;">上下文行控制：</span></p>
<p>-A NUM,  --after-context=NUM 打印匹配行后面的NUM行<br /> -B NUM, --before-context=NUM  打印匹配行前面的NUM行<br />-C NUM,  打印匹配行前面、后面的NUM行</p>
<p><span style="background-color: #c0c0c0;">举例：</span></p>
<pre class="crayon-plain-tag">grep root /etc/passwd        # 搜索文件，并把包含roog的行打印出来
cat /etc/passwd | grep root  # 同上

# 在当前目录下递归搜索包含oo且oo前面没有g的文件，打印文件名而不显示行内容
grep -l -r '[^g]oo' * 
# 搜索全部日志
grep -r 'hello' /var/log

# 寻找名为java或者mysql的进程
ps -A | egrep '(java|mysql)'

# 显示文件名、行号
cat */*.php | grep "wp-content" --color=auto -iRnH

# 不打印匹配的部分

# 使用向后肯定预查
grep -oP "(?&lt;=image:\s).*" /tmp/cronjobs/*
# 对于 images: docker.gmem.cc/busybox-amd64:1.31 
# 前面的images: 引起匹配，但是不包含在匹配结果中
# 匹配结果是：docker.gmem.cc/busybox-amd64:1.31 

# 使用向前肯定预查
grep -m1 -oP '(?&lt;=template:\s).*(?=not\s+defined)'
# 对于 statefulset.yaml:49: function "MongoVersion" not defined
# 用于向后肯定预查、向前肯定预查，template、not defined引起匹配，但是结果是
# statefulset.yaml:49: function "MongoVersion"</pre>
</td>
</tr>
<tr>
<td class="blog_h3">egrep</td>
<td>
<p>基于正则式的grep
<p><span style="background-color: #c0c0c0;">举例：</span></p>
<pre class="crayon-plain-tag"># 搜索，并且仅仅输出匹配的部分
echo 1.1.1 | egrep -oh '[0-9]+.[0-9]+.[0-9]+' </pre>
</td>
</tr>
<tr>
<td class="blog_h3">wc</td>
<td>
<p>可以统计文件或 I/O 流中的单词数量<br /><span style="background-color: #c0c0c0;">格式：</span><br />wc [OPTION]... [FILE]...<br />wc [OPTION]... --files0-from=F
<p><span style="background-color: #c0c0c0;">选项：</span><br />-w 统计单词数量<br />-l 统计行数量<br />-c 统计字节数量<br />-m 统计字符数量<br />-L 给出文件中最长行的长度</p>
</td>
</tr>
<tr>
<td class="blog_h3">tr</td>
<td>
<p>读取标准输入，转换或者删除字符，并打印到标准输出</p>
<p><span style="background-color: #c0c0c0;">格式：</span><br />tr [OPTION]... SET1 [SET2]</p>
<p><span style="background-color: #c0c0c0;">选项：</span><br />-c 使用SET1的补集<br />-d 删除SET1指定的字符，不进行转换<br />-s 删除重复出现的SET1指定的字符</p>
<p><span style="background-color: #c0c0c0;">举例：</span></p>
<pre class="crayon-plain-tag">#把花括号替换为圆括号
tr '{}' '()'
#删除全部空格
tr -d ' '
#把小写转换为大写
tr 'a-z' 'A-Z'
#使用问号替换所有显示字符，*表示让SET2长度自动扩充到与SET1一致
tr -c '[:print:][:cntrl:]' '[?*]'
#使用#代替空白符，连续出现的空白符被合并为1个
tr -s '[:space:]' '[#*]'</pre>
</td>
</tr>
<tr>
<td class="blog_h3">fold</td>
<td>将输入按照指定宽度进行折行</td>
</tr>
<tr>
<td class="blog_h3">fmt</td>
<td>简单的文件格式化器，通常用在管道中，将一个比较长的文本行输出进行折行</td>
</tr>
<tr>
<td class="blog_h3">col</td>
<td>来滤除标准输入的反向换行符号</td>
</tr>
<tr>
<td class="blog_h3">column</td>
<td>
<p>将“列类型”的文本转化为“易于打印”的表格式进行输出
<p>可以用来按列对齐，例如：</p>
<pre class="crayon-plain-tag">sudo iptables -L -nv -t filter | column -t -s " "</pre>
</td>
</tr>
<tr>
<td class="blog_h3">colrm</td>
<td>列删除过滤器。 这个工具将会从文件中删除指定的列并且写到文件中</td>
</tr>
<tr>
<td class="blog_h3">nl</td>
<td>计算行号过滤器，在输出中添加前缀的行号</td>
</tr>
<tr>
<td class="blog_h3">pr</td>
<td>格式化打印过滤器. 这个命令会将文件（或stdout）分页</td>
</tr>
<tr>
<td class="blog_h3">gettext</td>
<td>将程序的输出翻译或者本地化为不同国家语言</td>
</tr>
<tr>
<td class="blog_h3">iconv</td>
<td>将文件转化为不同编码格式（字符集）</td>
</tr>
<tr>
<td class="blog_h3">strings</td>
<td>在二进制或数据文件中找出可打印字符</td>
</tr>
<tr>
<td class="blog_h3">diff</td>
<td>
<p>以一行接一行的形式来比较目标文件
<p><span style="background-color: #c0c0c0;">格式：</span><br />diff [OPTION]... FILES</p>
<p><span style="background-color: #c0c0c0;">参数：</span><br />--side-by-side 以左右方式显示，并把不同的行标记出来</p>
<p><span style="background-color: #c0c0c0;">退出码：</span><br />0 如果文件完全一样</p>
</td>
</tr>
<tr>
<td>jq</td>
<td>
<p>命令行JSON处理器，能够选取、迭代、reduce、修改JSON文档</p>
<p><span style="background-color: #c0c0c0;">格式：</span>jq [options...] filter [files...]</p>
<p><span style="background-color: #c0c0c0;">选项：</span></p>
<p>--seq 使用MIME类型application/json-seq来分隔jq输入输出的JSON文档，这意味着JSON记录前后分别有ASCII字符RS、LF。无法解析的输入JSON被忽略，同时忽略所有后续输入，直到RS出现<br />--stream 流式的解析输入，输出路径数组和叶子值<br />--slurp/-s 读取整个输入，然后一次运行Filter，而非逐个读取JSON对象，逐个运行Filter<br />--raw-input/-R 不要将输入读取为JSON，而是每行均以字符串形式传递给Filter<br />-c 紧凑输出，不格式化<br />--tab 使用Tab而非空格进行格式化<br />--indent 缩进对应空格数量<br />-C 彩色化输出<br />-S 按键排序字段<br />-r 原始输出，如果结果是字符串，直接输出内容，不要引号<br />-f  从文件而非命令行读取过滤器<br />-L 指定模块搜索目录<br />--arg name value 定义变量$name为value<br />--argjson name JSON-text 以JSON文档的形式定义变量</p>
<p><span style="background-color: #c0c0c0;">过滤器：</span></p>
<p>每个jq程序都称为过滤器，它将输入转换为输出，大量内置过滤器可以实现字段抽取、类型转换等标准化工作</p>
<p>过滤器可以用管道的形式连接起来，你还可以把过滤器的输出收集到数组中。某些过滤器会产生多个输出，通过管道连接在其后的过滤器会对每个输出执行处理</p>
<p>需要注意，任何过滤器都具有输入输出，哪怕是18这样的字面值也可以是过滤器——不管输入是什么，都输出18</p>
<p><span style="background-color: #c0c0c0;">基本过滤器：</span></p>
<p style="padding-left: 30px;"><pre class="crayon-plain-tag">.</pre> 直接输出输入，不处理</p>
<p style="padding-left: 30px;"><pre class="crayon-plain-tag">.foo.bar</pre>属性点号导航，路径有null值则返回null，如果JSON键有特殊字符，需要双引号<pre class="crayon-plain-tag">."foo$"</pre>，注意.foo.bar 和<pre class="crayon-plain-tag">.foo|.bar</pre>这种管道形式是等价的</p>
<p style="padding-left: 30px;"><pre class="crayon-plain-tag">.foo?</pre>，类似于.foo，但是当.不是对象或数组时不会报错，例如<pre class="crayon-plain-tag">echo '{"name":"alex"}' | jq '[.age?]'</pre>返回<pre class="crayon-plain-tag">[null]</pre></p>
<p style="padding-left: 30px;"><pre class="crayon-plain-tag">.[&lt;string&gt;]</pre>这种形式放为属性也可以</p>
<p style="padding-left: 30px;"><pre class="crayon-plain-tag">.[2]</pre>访问数组元素</p>
<p style="padding-left: 30px;"><pre class="crayon-plain-tag">.[10:15]</pre> 切片，获得子数组</p>
<p style="padding-left: 30px;"><pre class="crayon-plain-tag">.[]</pre> 迭代数组的所有元素，每个元素产生一个输出</p>
<p style="padding-left: 30px;"><pre class="crayon-plain-tag">filter1,filter2</pre>分别执行两个过滤器，然后先输出filter1的全部输出，后输出filter2的全部输出</p>
<p style="padding-left: 30px;"><pre class="crayon-plain-tag">filter1|filter2</pre> filter1的输出作为filter2的输入</p>
<p><span style="background-color: #c0c0c0;">类型和值：</span></p>
<p style="padding-left: 30px;"><pre class="crayon-plain-tag">[]</pre>用于构造数组，[.user, .projects[]]表示读取user属性、projects的所有元素，合并为一个数组</p>
<p style="padding-left: 30px;"><pre class="crayon-plain-tag">{}</pre> 用于构造对象，{user: .user, title: .title}可以简写为<pre class="crayon-plain-tag">{user, title}</pre>，用括号包围key，表示解析它的值，例如<pre class="crayon-plain-tag">{(.user): .titles}</pre>可以产生{"alex": [1,2]}</p>
<p><span style="background-color: #c0c0c0;">内置操作符和函数：</span></p>
<p style="padding-left: 30px;">+ 数字加、数组连接、字符串连接<br />- 数字减、数组对象差集<br />* / %<br />length 获得长度<br />keys, keys_unsorted 获得键的数组<br />has(key) 返回是否存在键，true/false<br />del(path_expression) 删除指定的键值</p>
<p><span style="background-color: #c0c0c0;">格式化和转义：</span></p>
<p style="padding-left: 30px;">@text 调用tostring<br />@json 串行化输入为JSON<br />@html 执行HTML转义<br />@base64 执行Base64编码</p>
</td>
</tr>
</tbody>
</table>
<div class="blog_h2"><span class="graybg">awk</span></div>
<p>AWK编程语言的GNU实现。</p>
<div class="blog_h3"><span class="graybg">命令格式</span></div>
<pre class="crayon-plain-tag"># GNU的Awk实现
gawk [ POSIX or GNU style options ] -f program-file [ -- ] file ...
gawk [ POSIX or GNU style options ] [ -- ] program-text file ...

# pgawk是剖析版本的Awk，速度比较慢
pgawk [ POSIX or GNU style options ] -f program-file [ -- ] file ...
pgawk [ POSIX or GNU style options ] [ -- ] program-text file ...

# dgawk是Awk的调试器
dgawk [ POSIX or GNU style options ] -f program-file [ -- ] file ...</pre>
<div class="blog_h3"><span class="graybg">命令示例</span></div>
<pre class="crayon-plain-tag"># 读取文件的第1、4列
awk '{print $1, $4}' filename

# 列出最近5个登陆记录，逐行处理。以空格作为字段分隔符，打印第一个字段
# $0表示所有字段，$1表示第一个字段，类推
last -n 5 | awk '{print $1}'

# 行过滤，仅仅显示第一列为tcp6且第六列为SYN_SENT的行
netstat -tn | awk '$1=="tcp6" &amp;&amp; $6=="SYN_SENT"'
# 同上，但是包含表头（第一行）
netstat -tn | awk '$1=="tcp6" &amp;&amp; $6=="SYN_SENT" || NR==1'


# 使用 : 作为分隔符，取第1、2个字段，之间用制表符分隔
cat /etc/passwd | awk -F ':' '{print $1 "\t" $2 }'

# 使用正则表达式作为分隔符
echo 'Hello darkness my old friend' | awk -F'\\s+' '{print "["$5"]"}'
# [friend]

# 使用正则式进行行过滤
# 如果第六列匹配正则式FIN，或者是第一行，则打印4、5、6列，表头总是打印，输出字段使用制表符分隔
awk '$6 ~ /FIN/ || NR==1 {print NR,$4,$5,$6}' OFS="\t" netstat.txt
# 正则式取反
netstat | awk '!/WAIT/'

# BEGIN 在处理输入之前执行
# END   在处理完所有输入行之后执行
cat /etc/passwd | head -5 | awk -F':' 'BEGIN {print "用户名"} {print $1} END {print "结束"}'
# 用户名
# root
# daemon
# bin
# sys
# sync
# 结束

# 格式化输出，C语言风格
netstat -nlt4 | awk '{printf "%-8s %-8s %-8s %-18s %-22s %-15s\n",$1,$2,$3,$4,$5,$6}'

# 拆分输出：仅仅输出指定的列
netstat -nt | awk 'NR!=1{print &gt; $6}'


# 统计数量
# 在映射a中存放每个网络状态的计数，默认计数为0，每次自动增加计数
# 处理完所有行后，遍历映射并打印
netstat -t | awk 'NR!=1{a[$6]++;} END {for (i in a) print i ", " a[i];}'
# LAST_ACK, 4
# CLOSE_WAIT, 1
# ESTABLISHED, 22
# Foreign, 1
# CLOSING, 1
# TIME_WAIT, 1

# 寻找log中长度大于80的行
awk 'length&gt;80' log</pre>
<div class="blog_h3"><span class="graybg">内置变量</span></div>
<table class="full-width fixed-word-wrap">
<thead>
<tr>
<td style="width: 15%; text-align: center;">变量</td>
<td style="text-align: center;">说明</td>
</tr>
</thead>
<tbody>
<tr>
<td>$0</td>
<td>当前记录，即整个行的内容</td>
</tr>
<tr>
<td>$1~$n</td>
<td>当前记录的第n个字段，字段间由FS分隔</td>
</tr>
<tr>
<td>FS</td>
<td>输入字段分隔符 默认是空格或Tab</td>
</tr>
<tr>
<td>NF</td>
<td>当前记录中的字段个数，就是有多少列</td>
</tr>
<tr>
<td>NR</td>
<td>
<p>已经读出的记录数，就是行号，从1开始，如果有多个文件话，这个值也是不断累加中</p>
</td>
</tr>
<tr>
<td>FNR</td>
<td>已经读出的记录数，就是行号，从1开始，如果有多个文件话，每个文件分别计数</td>
</tr>
<tr>
<td>RS</td>
<td>输入的记录分隔符， 默认为换行符</td>
</tr>
<tr>
<td>OFS</td>
<td>输出字段分隔符， 默认也是空格</td>
</tr>
<tr>
<td>ORS</td>
<td>输出的记录分隔符，默认为换行符</td>
</tr>
<tr>
<td>FILENAME</td>
<td>当前输入文件的名字</td>
</tr>
<tr>
<td>ENVIRON</td>
<td>环境变量的Map</td>
</tr>
</tbody>
</table>
<div class="blog_h3"><span class="graybg">内置函数</span></div>
<table class="full-width fixed-word-wrap">
<thead>
<tr>
<td style="width: 25%; text-align: center;">函数</td>
<td style="text-align: center;">说明</td>
</tr>
</thead>
<tbody>
<tr>
<td colspan="2"><em>数学函数</em></td>
</tr>
<tr>
<td>atan2( y, x )</td>
<td>返回 y/x 的反正切</td>
</tr>
<tr>
<td>cos( x )</td>
<td>返回 x 的余弦；x 是弧度</td>
</tr>
<tr>
<td>sin( x )</td>
<td>返回 x 的正弦；x 是弧度</td>
</tr>
<tr>
<td>exp( x )</td>
<td>返回 x 幂函数</td>
</tr>
<tr>
<td>log( x )</td>
<td>返回 x 的自然对数</td>
</tr>
<tr>
<td>sqrt( x )</td>
<td>返回 x 平方根</td>
</tr>
<tr>
<td>int( x )</td>
<td>返回 x 的截断至整数的值</td>
</tr>
<tr>
<td>rand( )</td>
<td>返回随机数字 n，其中 0 &lt;= n &lt; 1</td>
</tr>
<tr>
<td>srand( [Expr] )</td>
<td>将 rand 函数的种子值设置为 Expr 参数的值，或如果省略 Expr 参数则使用时间。返回先前的种子值</td>
</tr>
<tr>
<td colspan="2"><em>字符串函数</em></td>
</tr>
<tr>
<td>length [(String)]</td>
<td>计算字符串中的字符数量</td>
</tr>
<tr>
<td>blength [(String)]</td>
<td>计算字符串的字节数</td>
</tr>
<tr>
<td>sub( Ere, Repl, [ In ] )</td>
<td>
<p>用Repl替换In中第一个匹配正则式Ere的子串。如果不指定In则使用$0</p>
<p>注意：In直接被修改，返回值是替换的子串数量</p>
<p>示例：</p>
<pre class="crayon-plain-tag">df | awk 'NR&gt;1{sub("%","",$5);print $1 " usage " $5/100 }'</pre>
</td>
</tr>
<tr>
<td> gsub( Ere, Repl, [ In ] )</td>
<td>用Repl替换In中全部的匹配正则式Ere的子串。如果不指定In则使用$0</td>
</tr>
<tr>
<td>index( Str, Sub )</td>
<td>返回Sub第一次出现在Str中的位置，索引以1为基准，如果不存在Sub子串返回0</td>
</tr>
<tr>
<td>substr( Str, M, [ N ] )</td>
<td>提取Str从索引M开始，N结束的子串，不指定N则到结尾</td>
</tr>
<tr>
<td>match( Str, Ere )</td>
<td>返回Str匹配Ere的子串的出现位置，如果没有匹配返回0</td>
</tr>
<tr>
<td>split( Str, A, [Ere] )</td>
<td>分割字符串Str，将子串存放到数组A中。分隔符默认等于-F参数指定的字符，或者Ere正则式</td>
</tr>
<tr>
<td>tolower( Str )<br />toupper( Str )</td>
<td>大小写转换</td>
</tr>
<tr>
<td>sprintf(Format, Expr, . . . )</td>
<td>格式化打印：<br />%d   十进制有符号整数<br />%u  十进制无符号整数<br />%f   浮点数<br />%s   字符串<br />%c   单个字符<br />%p   指针的值<br />%e   指数形式的浮点数<br />%x %X  无符号以十六进制表示的整数<br />%o   无符号以八进制表示的整数<br />%g   自动选择合适的表示法</td>
</tr>
<tr>
<td colspan="2"><em>时间函数</em></td>
</tr>
<tr>
<td>mktime( YYYY MM DD HH MM SS[ DST])  </td>
<td>解析字符串为时间 </td>
</tr>
<tr>
<td>strftime([format [, timestamp]])</td>
<td>
<p>格式化时间：
<p>%a 星期几的缩写(Sun)<br />%A 星期几的完整写法(Sunday)<br />%b 月名的缩写(Oct)<br />%B 月名的完整写法(October)<br />%c 本地日期和时间<br />%d 十进制日期<br />%D 日期 08/20/99<br />%e 日期，如果只有一位会补上一个空格<br />%H 用十进制表示24小时格式的小时<br />%I 用十进制表示12小时格式的小时<br />%j 从1月1日起一年中的第几天<br />%m 十进制表示的月份<br />%M 十进制表示的分钟<br />%p 12小时表示法(AM/PM)<br />%S 十进制表示的秒<br />%U 十进制表示的一年中的第几个星期(星期天作为一个星期的开始)<br />%w 十进制表示的星期几(星期天是0)<br />%W 十进制表示的一年中的第几个星期(星期一作为一个星期的开始)<br />%x 重新设置本地日期(08/20/99)<br />%X 重新设置本地时间(12：00：00)<br />%y 两位数字表示的年(99)<br />%Y 当前月份<br />%Z 时区(PDT)<br />%% 百分号(%)</p>
</td>
</tr>
<tr>
<td>systime()</td>
<td>返回UNIX纪元到现在的秒数</td>
</tr>
<tr>
<td colspan="2"><em>其它函数</em></td>
</tr>
<tr>
<td>close(expr)</td>
<td>
<p>关闭由print、printf、getline打开的文件或管道，关闭成功返回0</p>
<p>如果打算写一个文件，并稍后在同一个程序中读取文件，则 close 语句是必需的</p>
</td>
</tr>
<tr>
<td>system(cmd)</td>
<td>
<p>执行cmd参数给出的系统命令，返回退出状态。示例：</p>
<pre class="crayon-plain-tag">jcmd -l | awk '{system("ps  --no-headers -p "$1 " -o command " ) }'</pre>
</td>
</tr>
<tr>
<td>getline</td>
<td>
<p>逐行读取外部文件的内容。示例：
<pre class="crayon-plain-tag">{ while( "cat /etc/passwd" | getline ){ print $0; }; close("/etc/passwd"); }
# 或者   getline &lt; "/etc/passwd"</pre>
</td>
</tr>
<tr>
<td>exit</td>
<td>提前结束处理，不再处理后续的记录。如果awk位于管道中间，后续命令获得处理机会</td>
</tr>
</tbody>
</table>
<div class="blog_h3"><span class="graybg">语言入门</span></div>
<p>Awk程序通常是读取一个个记录（默认每行是一个记录），并寻找到其中匹配pattern的行，执行指定的动作：
<pre class="crayon-plain-tag">pattern { action }

# 示例
$3 == 0 { print $1 }
# 可以不指定pattern，这样就匹配所有记录
{ print }  # 不带参数的print等价于print $0

# 起始和结束块，分别在处理任何记录之前、处理所有记录之后执行
BEGIN { action }
END   { action }</pre>
<p>Pattern分为：<span style="background-color: #c0c0c0;">BEGIN、END、 表达式、/正则表达式/ 、Pattern的逻辑组合，范围模式几类</span>。</p>
<p>范围模式：<pre class="crayon-plain-tag">pattern1，pattern2 { 语句 }</pre>，匹配从匹配pattern1的行、到匹配pattern2的行之间的所有行，包括匹配pattern1、pattern2的那两个首尾行。</p>
<p>你可以对记录中的字段，进行各种运算：</p>
<pre class="crayon-plain-tag">{ print $1, $2 * $3 }
$2 * $3 &gt; 50 { printf("$%.2f for %s\n", $2 * $3, $1) }</pre>
<p>pattern可以通过逻辑操作符进行组合，包括：<pre class="crayon-plain-tag">&amp;&amp;</pre>、<pre class="crayon-plain-tag">||</pre>和<pre class="crayon-plain-tag">!</pre>，支持使用括号：</p>
<pre class="crayon-plain-tag">!($2 &lt; 4 &amp;&amp; $3 &lt; 20)</pre>
<p>字符串拼接语法 —— <span style="background-color: #c0c0c0;">直接连续写多个字符串（或变量）即可，不需要操作符，空格被忽略</span>：</p>
<pre class="crayon-plain-tag">netstat -nlt4 | awk 'NR &gt; 2 {print $4}' | awk -F':' '{print $1}' | sort -u | \
    #         赋值语法
    #           字符串拼接语法
    awk '{ips = ips $1 "|"} END{print ips}'
# 0.0.0.0|10.0.0.1|127.0.0.1|172.17.0.1|172.18.0.1|172.21.0.1|192.168.142.140|</pre>
<div class="blog_h3"><span class="graybg">控制结构 </span></div>
<p>if-else分支结构： </p>
<pre class="crayon-plain-tag">echo -e "0\n-1\n1" | awk '{ if($1&gt;0) print "TRUE"; else if($1&lt;0) print "N/A"; else print "FALSE" }'
# FALSE
# N/A
# TRUE</pre>
<p>while循环结构： </p>
<pre class="crayon-plain-tag">while (i &lt;= $3) { i = i + 1 }</pre>
<p>for循环结构：</p>
<pre class="crayon-plain-tag">{ 
for (i = 1; i &lt;= $3; i = i + 1)
    printf("\t%.2f\n", $1 * (1 + $2) ^ i)
}</pre>
<div class="blog_h3"><span class="graybg">数组支持</span></div>
<pre class="crayon-plain-tag">{ line[NR] = $0 }  # 记录每个输入行，将其存为数组元素

# 逆序打印
END { 
  i = NR
  while (i &gt; 0) {
    print line[i]
    i = i - 1
  }
}</pre>
<div class="blog_h2"><span class="graybg">sed</span></div>
<p>sed是流式文本编辑器，该命令用于在输入流（文件或者管道输入）上执行基本的文本转换，该命令只会对输入进行一次逐行的顺序的处理，因而效率较高。</p>
<div>
<div class="blog_h3"><span class="graybg">命令格式</span></div>
</div>
<pre class="crayon-plain-tag">sed [OPTION]... {script-only-if-no-other-script} [input-file]...</pre>
<div>
<div class="blog_h3"><span class="graybg">命令选项</span></div>
</div>
<pre class="crayon-plain-tag">-n, --quiet, --silent
       #不自动打印当前要处理的行
-e script, --expression=script
       #指定需要执行的命令（脚本），可以指定多个-e
-f script-file, --file=script-file
       #指定文件中的脚本
--follow-symlinks
       #跟随符号链接到目标文件
-i[SUFFIX], --in-place[=SUFFIX]
       #指定备份文件，修改直接应用到原始文件
-l N, --line-length=N
       #对于l类型的命令，指定期望的换行的行长度阈值
--posix
       #禁用所有GNU扩展
-r, --regexp-extended
       #在此脚本中使用正则式
-s, --separate
       #把输入文件看作若干单个文件，而不是一个连续的流
-u, --unbuffered
       #使用尽量少的缓冲区，尽量读入较少的文件内容，并把输出刷空
-z, --null-data
       #使用NUL字符来划分行</pre>
<div>
<div class="blog_h3"><span class="graybg">脚本语法</span></div>
</div>
<pre class="crayon-plain-tag">[address][!] cmd [cmd-args]

# address 指定后面的命令的作用范围，有以下几种方式：
# 不指定：作用于输入的所用行
# n,m：从第n到第m行，$表示最后一行
# n,+m：从第n行开始，到n+m行为止
# n~m：从第n行开始，每隔m行执行一次命令
# /pattern/：基于正则式匹配，所有匹配的行均执行命令
# /pattern1/,/pattern2/：基于正则式匹配，从pattern1匹配的行开始，到pattern2匹配的行为止

 #命令，包括添加、插入、替换、删除、打印等
#                 p                           打印
#                 =                           打印行号
# [addr1[,addr2]] i text                      在指定的行的前面插入文本
# [addr1[,addr2]] a text                      在指定的行的后面添加文本
# [addr1[,addr2]] d                           删除指定的行
# [addr1[,addr2]] s/pattern/replace/[opts]    把指定的行内的pattern替换为replace，
#                                               默认只会替换第一个匹配pattern的文本
#                                               选项：
#                                                 n 替换第n个匹配
#                                                 g 替换所有匹配
#                                                 p 如果替换成功打印该行
#                                                 w 存储改变的行到文件
#                                                 i 匹配时忽略大小写
#                 s;pattern;replace;          如果replace中有/，可以用;代替/</pre>
<div class="blog_h3"><span class="graybg">应用举例</span></div>
<pre class="crayon-plain-tag"># 替换文本中每行的所有WangZhen为Alex
sed "s/WangZhen/Alex/g" greetings.txt &gt; result.txt
# 同上，直接写回到原文件

sed -i "s/WangZhen/Alex/g" greetings.txt
# 只替换每行的第2个匹配
sed -i "s/WangZhen/Alex/2" greetings.txt
# 只替换每行的第3个以后的匹配
sed -i "s/WangZhen/Alex/3g" greetings.txt
# 只替换3-10行的内容
sed -i "3,10s/WangZhen/Alex/g" greetings.txt

# 在每一行的开始处添加一个#
sed 's/^/#/g' greetings.txt 
# 在每行的结尾添加一个#
sed 's/$/#/g' greetings.txt 


# 同时执行多个脚本（两种等价方式）
sed '1,3s/WangZhen/Alex/g; 3,$s/Is/Are/g' greetings.txt
sed -e '1,3s/WangZhen/Alex/g' -e '3,$s/Is/Are/g'  greetings.txt

# 正则式匹配引用，使用\1、\2依次引用第1、2个括号内的匹配内容
# 正则式([^,]*).*says(.*)
#替换为：\1:\2
sed 's/\([^,]*\).*says\(.*\)/\1:\2/g' greetings.txt

# 在输入的每一行首部，加上  docker.gmem.cc/
sed "s;^;docker.gmem.cc/;"
# 常用正则式关键字
# ^ 开头
# $ 结尾
# \&lt; 词首，例如 \&lt;abc 表示abc开头的词
# \&gt; 词尾
# . 任意单词
# * 重复
# [] 字符集</pre>
<div class="blog_h1"><span class="graybg">归档与压缩命令</span></div>
<table style="width: 100%;" border="1" cellspacing="0" cellpadding="5">
<thead>
<tr>
<td style="width: 100px; text-align: center;">命令 </td>
<td style="text-align: center;"> 说明</td>
</tr>
</thead>
<tbody>
<tr>
<td class="blog_h2">tar</td>
<td>
<p>打包和解压文件。该命令支持使用短横线（-）来代替标准输入/输出，以代替输入/输出tar文件名</p>
<p><span style="background-color: #c0c0c0;">格式：</span><br />tar [options] [pathname ...]</p>
<p><span style="background-color: #c0c0c0;">选项：</span><br />-c 创建一个新的归档文件<br />-x 从归档文件中解压文件<br />-z 用gzip压缩归档文件（压缩还是解压, 依赖于是否组合了-c或-x）<br />--delete 从存在的归档文件中删除文件<br />-r 将文件添加到现存的归档文件的尾部<br />-A 将tar文件添加到现存的归档文件的尾部<br />-t 列出现存的归档文件中包含的内容<br />-u 更新归档文件<br />-d 使用指定的文件系统比较归档文件<br />-j 用bzip2压缩归档文件<br />-d, --diff, --compare 查找文件系统和归档文件的不同<br />-a, --auto-compress 根据后缀名自动确认压缩算法<br />-C, --directory DIR 修改输出目录为DIR<br />--exclude=PATTERN 根据指定的PATTERN排除文件<br />-f, --file ARCHIVE 使用归档文件（后面要直接连接归档文件名）<br />-h, --dereference 压缩时使用符号连接指向的真实文件<br />-H, --format FORMAT 创建指定格式的文件<br />-k, --keep-old-files 解压时，不覆盖已经存在的旧文件<br />-p ：使用原文件的原来属性<br />-P ：使用绝对路径来压缩<br />-N ：比日期(yyyy/mm/dd)更新的文件才会被打包进去</p>
<p><span style="background-color: #c0c0c0;">举例：</span></p>
<pre class="crayon-plain-tag"># 将/etc下的文件全部打包
tar -cvf /tmp/etc.tar /etc
# 同上，使用gzip压缩
tar -zcvf /tmp/etc.tar.gz /etc 
# 同上，使用bzip2压缩
tar -jcvf /tmp/etc.tar.bz2 /etc 
# 查阅归档文件内有哪些文件
tar -ztvf /tmp/etc.tar.gz
# 将/tmp/etc.tar.gz解压缩在/usr/local/src下
tar -zxvf /tmp/etc.tar.gz -C /usr/local/src
# 递归搜索当前目录下的日志文件，解符号引用，打包
tar czfh logs.tgz $(find . -name *.log)</pre>
</td>
</tr>
<tr>
<td class="blog_h2"> 7za</td>
<td>
<p>高压缩比压缩工具。支持7z, ZIP, CAB, ARJ, GZIP, BZIP2, TAR, CPIO, RPM, DEB等格式
<p><span style="background-color: #c0c0c0;">格式：</span><br />7za [adeltux] [-] [SWITCH] [ARCHIVE_NAME] [ARGUMENTS]...</p>
<p>子命令：<br />a 添加<br />d 删除<br />e 解压<br />l 列出明细<br />t 测试<br />u 更新<br />x 解压，保留路径</p>
<p><span style="background-color: #c0c0c0;">选项：</span><br />-bd 禁用百分比指示器<br />-l 跟踪符号链接 <br />-m{Parameters} 参数<br />-mhe=on|off 启用或者禁用归档文件头加密，仅用于7z<br />-o{Directory} 输出目录<br />-p{Password} 设置密码<br />-si 从标准输入读取数据<br />-so 写出数据到标准输出<br />-sfx[{name}] 创建自解压文档<br />-t{Type} 归档文件的类型 7z, zip, gzip, bzip2, tar，默认7z<br />-u[-][p#][q#][r#][x#][y#][z#][!newArchiveName] 更新选项<br />-w[path] 设置工作目录<br />-y 对所有提问默认选择是</p>
<p><span style="background-color: #c0c0c0;">举例：</span></p>
<pre class="crayon-plain-tag">#把dir目录中所有文件加入到archive.7z中
#-m0=lzma 使用lzma方式
#-mx=9 使用最高压缩级别
#-mfb=64 设置LZMA快速比特
#-md=32m 字典大小设置为32MB
#-ms=on 启用固化归档，所有文件被作为一个大数据块看待
7za a -t7z -m0=lzma -mx=9 -mfb=64 -md=32m -ms=on archive.7z dir

#把dir目录中所有文件加入到自解压文件archive.exe中
7za a -sfx archive.exe dir
#压缩单个文件
7za a -t7z /tmp/gmem.sql.7z /tmp/gmem.sql

#压缩并加密
7za a -mhe=on -ppswd archive.7z dir

#解压到当前文件夹，保持目录结构
7za x archive.zip
#解压到指定/tmp目录
7za x /tmp/gmem.sql.7z -o/tmp


#Linux/Unix备份，注意不能直接使用7za，因为文件所有权信息无法保存
#备份并压缩为7z格式
tar cvf  - dir | 7za a -si archive.tar.7z
#解压缩并展开备份文件
7za x -so archive.tar.7z | tar xf -</pre>
</td>
</tr>
<tr>
<td class="blog_h2">shar</td>
<td>标准的 GNU/UNIX 压缩工具</td>
</tr>
<tr>
<td class="blog_h2">bzip2</td>
<td>用来压缩的一个可选的工具, 通常比 gzip 命令压缩率更高</td>
</tr>
<tr>
<td class="blog_h2">zip, unzip</td>
<td>跨平台的文件归档和压缩工具</td>
</tr>
<tr>
<td>gzip,gunzip</td>
<td>
<p>跨平台的文件归档和压缩工具
<p><span style="background-color: #c0c0c0;">举例：</span></p>
<pre class="crayon-plain-tag"># 从标准输入读取数据并压缩
docker save busybox:1.30.1 | gzip -c &gt; busybox.tar.gz

# 解压缩到标准输出
gunzip -c busybox.tar.gz</pre>
</td>
</tr>
<tr>
<td>cpio</td>
<td>
<p>从归档文件拷贝出、拷贝到归档文件
<p>拷出模式：</p>
<p style="padding-left: 30px;">将文件拷贝到归档文件中，从stdin读取一系列文件名（每个一行），然后将归档文件写出到标准输出</p>
<p>拷入模式：</p>
<p style="padding-left: 30px;">从归档文件拷贝文件，或者列出归档文件的内容</p>
<p><span style="background-color: #c0c0c0;">选项：</span></p>
<p>-d 如果必要，创建需要的目录<br />-i  以拷入模式运行<br />-m 保持文件的修改时间不变</p>
</td>
</tr>
</tbody>
</table>
<div class="blog_h1"><span class="graybg">数学与计算命令</span></div>
<table style="width: 100%;" border="1" cellspacing="0" cellpadding="5">
<thead>
<tr>
<td style="width: 100px; text-align: center;"> 命令</td>
<td style="text-align: center;">说明 </td>
</tr>
</thead>
<tbody>
<tr>
<td class="blog_h2">factor</td>
<td>分解质因数，空格分隔结果</td>
</tr>
<tr>
<td class="blog_h2">bc</td>
<td>支持浮点运算</td>
</tr>
<tr>
<td class="blog_h2">expr</td>
<td>
<p>通用求值表达式：通过给定的操作（参数必须以空格分开）连接参数进行算术操作、比较操作、字符串操作或者是逻辑操作</p>
<p><span style="background-color: #c0c0c0;">举例：</span></p>
<pre class="crayon-plain-tag">expr 5 + 3
a=`expr 5 + 3` #等价于 $((5+3))</pre>
</td>
</tr>
<tr>
<td class="blog_h2">seq</td>
<td>
<p>打印一系列连续的数字
<p>格式：</p>
<pre class="crayon-plain-tag"># 从1开始，LAST结束
seq [OPTION]... LAST
# 从FIRST开始，LAST结束
seq [OPTION]... FIRST LAST
# 从FIRST开始，LAST结束，步长INCREMENT
seq [OPTION]... FIRST INCREMENT LAST </pre>
</td>
</tr>
</tbody>
</table>
<div class="blog_h1"><span class="graybg">通信与网络命令</span></div>
<table class="fixed-word-wrap" style="width: 100%;" border="1" cellspacing="0" cellpadding="5">
<thead>
<tr>
<td style="width: 100px; text-align: center;">命令</td>
<td style="text-align: center;">说明 </td>
</tr>
</thead>
<tbody>
<tr>
<td class="blog_h2">host</td>
<td>
<p>DNS查找工具，用于进行域名和IP地址的双向转换
<p><span style="background-color: #c0c0c0;">格式：</span><br />host [-aCdlriTwv] [-c class] [-N ndots] [-t type] [-W time]<br />　　 [-R number] [-m flag] hostname [server]</p>
<p><span style="background-color: #c0c0c0;">选项：</span><br />-a 等价于 -v -t ANY<br />-R 指定重试次数（发送UDP包的个数）<br />-c 查询类，一般不用指定，默认IN表示互联网地址查询<br />-t 指定查询类型，支持A,NS,CNAME,PTR,MX,ANY等，<br />-v -d 启用冗长输出<br />-w 一直等待不超时<br />-W 指定最多等待多久，单位秒<br />-4 强制基于IPv4发送查询<br />-6 强制基于IPv6发送查询</p>
<p><span style="background-color: #c0c0c0;">举例：</span></p>
<pre class="crayon-plain-tag">#查询域名gmem.cc的所有类型的记录
host -v -t ANY gmem.cc 8.8.4.4
#输出内容：
#Trying "gmem.cc"
#Using domain server:
#Name: 8.8.4.4
#Address: 8.8.4.4#53
#Aliases:
#
#;; -&gt;&gt;HEADER&lt;&gt;HEADER&lt;</pre>
</td>
</tr>
<tr>
<td class="blog_h2">nslookup</td>
<td>
<p>和DNS服务器交互。如果不指定任何参数，进入交互模式
<p><span style="background-color: #c0c0c0;">格式：</span></p>
<p>nslookup [-option] [name | -] [server]</p>
<p><span style="background-color: #c0c0c0;">选项：</span></p>
<p>[no]debug 调试模式<br />port=value  DNS服务器端口<br />querytype=value ，type=value 查询类型，默认A<br />[no]recurse，提示DNS服务器，是否递归的请求上游DNS<br />[no]fail，如果一个DNS服务器应答SERVFAIL，是否尝试下一个<br />[no]vc，发送请求时是否总是使用虚拟环路（virtual circuit）</p>
<p><span style="background-color: #c0c0c0;">示例：</span></p>
<pre class="crayon-plain-tag"># 通过TCP 5353端口进行查询
nslookup -vc kubernetes.default.svc.k8s.gmem.cc localhost -port=5353

# 发起AAAA查询
nslookup -q=AAAA tredis-keydb-0.tredis-keydb 10.96.0.10</pre>
</td>
</tr>
<tr>
<td class="blog_h2">arp</td>
<td>
<p>操控系统的ARP缓存
<p><span style="background-color: #c0c0c0;">格式：</span><br />arp [-vn] [-H type] [-i if] [-a] [hostname]<br />arp [-v] [-i if] -d hostname [pub]<br />arp [-v] [-H type] [-i if] -s hostname hw_addr [temp]<br />arp [-v] [-H type] [-i if] -s hostname hw_addr [netmask nm] pub<br />arp [-v] [-H type] [-i if] -Ds hostname ifname [netmask nm] pub<br />arp [-vnD] [-H type] [-i if] -f [filename]</p>
<p><span style="background-color: #c0c0c0;">选项：</span><br />-v, --verbose 显示冗余信息<br />-d 删除 ARP表中对应IP的条目条目：arp -d address<br />-s 新增一条ARP表条目：arp  -s address hw_addr<br />-n, --numeric 显示数字地址，而不是尝试解析主机名、端口<br />-H type, --hw-type type 在读取ARP缓存时，该参数指明那种条目需要被检查，默认值是以太网ether<br />-a 使用备选的BSD风格的输出格式 （不固定列宽）<br />-D, --use-device 使用网络接口的名称，而不是硬件地址<br />-i If, --device If 选择一个网络接口</p>
<p><span style="background-color: #c0c0c0;">举例：</span></p>
<pre class="crayon-plain-tag">#eth1将应答针对192.168.3.90的ARP请求，并将该IP地址关联到eth0的MAC地址
arp -i eth1 -Ds 192.168.3.90 eth0 pub

#删除eth1上关于192.168.3.90的ARP条目
arp -i eth1 -d 192.168.3.90

#查询eth1上的ARP条目
arp -i eth1
#Address        HWtype  HWaddress           Flags Mask            Iface
#192.168.0.89   ether   0c:82:68:52:76:3e   C                     eth1
#192.168.0.243  ether   00:d0:23:82:ba:12   C                     eth1
#192.168.0.61   ether   e0:db:55:ad:29:3c   C                     eth1



# 根据Mac地址查询IP地址
ip neighbor | grep "00:e0:4c:68:7e:45" | cut -d" " -f1</pre>
</td>
</tr>
<tr>
<td class="blog_h2">arp-scan</td>
<td>
<p>ARP扫描器<br />该命令向本地网络上的主机发送ARP数据报，并打印任何响应信息<br />可以使用--I指定使用的网络接口，如果不指定，该命令会使用所有的配置好的网卡（loopback除外）<br />默认情况下，数据报被发送到以太网广播地址ff:ff:ff:ff:ff:ff
<p><span style="background-color: #c0c0c0;">选项：</span><br />-f 从文件而不是命令行读取目标主机名称或者地址<br />-l 从网络接口的配置（IP和子网掩码）中生成目标主机的地址，包含广播地址<br />-r 每个目标主机的总计重试次数，默认2<br />-t 初始的每个主机的超时时间，默认100<br />-i 最小的数据报发送间隔<br />-v 显示冗余进度信息<br />-R 随机打乱目标主机列表的顺序<br />-N 仅使用IP地址，不使用主机名，使用该选项后，所有目标主机必须以IP地址的方式指定<br />-I 使用的本机网络接口的名称，该接口必须支持ARP协议<br />-q 仅显示最小化的输出<br />-g 不显示重复的数据报，默认的会显示并添加(DUP: n)后缀</p>
<p><span style="background-color: #c0c0c0;">举例：</span></p>
<pre class="crayon-plain-tag">#通过eth1网卡执行扫描，并显示其中IP地址为192.168.0.232的条目
#该命令可以用于IP查重
sudo arp-scan -I eth1 -l | grep 192.168.0.232</pre>
</td>
</tr>
<tr>
<td class="blog_h2">traceroute</td>
<td>
<p>跟踪到目的主机的路由信息
<p><span style="background-color: #c0c0c0;">格式：</span></p>
<pre class="crayon-plain-tag">traceroute [-46dFITUnreAV] [-f first_ttl] [-g gate,...]
           [-i device] [-m max_ttl] [-p port] [-s src_addr]
           [-q nqueries] [-N squeries] [-t tos]
           [-l flow_label] [-w waittime] [-z sendwait] [-UL] [-D]
           [-P proto] [--sport=port] [-M method] [-O mod_options]
           [--mtu] [--back]
           host [packet_len]
traceroute6  [options]
tcptraceroute  [options]
lft  [options]</pre>
<p><span style="background-color: #c0c0c0;">选项：</span><br />-4, -6 明确强制使用IPv4或者IPv6，默认会根据制定的host名自动解析，根据结果来判断使用IPv6还是IPv4，如果同时支持，则默认使用IPv4<br />-I, --icmp 使用ICMP回应作为探针<br />-T, --tcp 使用TCP SYN作为探针<br />-d, --debug 启用Socket级别的调试信息<br /> Enable socket level debugging (when the Linux kernel supports it)<br />-f first_ttl, --first=first_ttl 第一次使用的TTL，默认1<br />-g gateway, --gateway=gateway 指定一个IP源路由选项<br />-i interface, --interface=interface 发送数据报使用的网络接口，默认根据路由表选择<br />-m max_ttl, --max-hops=max_ttl 最大跃点数（TTL），默认30<br />-n 显示结果时不把IP映射为主机名<br />-w waittime, --wait=waittime 等待响应的时间，默认5秒<br />-q 发送探针的数量<br />-s source_addr, --source=source_addr 手工指定源IP地址，默认根据网络接口的IP地址确定<br />-z sendwait, --sendwait=sendwait 发送探针报文的最小间隔，默认0<br />--mtu 沿着追踪路径检测最大传输单元（MTU）</p>
<p><span style="background-color: #c0c0c0;">举例：</span></p>
<pre class="crayon-plain-tag">1  * * *
 2  119.57.167.17  21.994 ms  21.737 ms  22.433 ms
 3  * * *
21  * * *
22  103.3.62.198  336.846 ms *  342.442 ms
#从第一跳一直检测到目标主机，或者超过最大跃点数限制
# 默认发送三个探针，出现星号表示超时前，当没有收到前跳对应的节点的回应报文</pre>
</td>
</tr>
<tr>
<td class="blog_h2">mtr</td>
<td>
<p>mtr是一个包含traceroute和ping功能的单一网络诊断工具，mtr命令启动后，会诊断当前主机和目标主机之间的网络状况，它会特意利用较低TTL发送封包，突然增加的数据报丢失率或者响应时间通常提示较差的网络状况或者网络负载过高。支持IP ECHO、UDP、TCP三种类型的封包
<p><span style="background-color: #c0c0c0;">格式：</span></p>
<pre class="crayon-plain-tag">mtr  [-hvrctglspeniuTP46]   [--help]   [--version]   
     [--report]   [--report-wide]   [--report-cycles COUNT]   
     [--curses]   [--split]   [--raw]  [--mpls]  [--no-dns]  
     [--show-ips]  [--gtk] [--address IP.ADD.RE.SS] 
     [--interval SECONDS] [--psize BYTES | -s BYTES] [--tcp] 
     [--port PORT] [--timeout SECONDS] HOSTNAME [PACKETSIZE]</pre>
<p><span style="background-color: #c0c0c0;">选项：</span></p>
<p>-r --report 以报告模式运行，将运行-c指定的次数，然后打印统计信息并退出<br />-w --report-wide 宽格式，不会截断主机名<br />-c --report-cycles COUNT ping包的数量，每个ping的周期为1秒<br />-s --psize BYTES 发送数据报的字节数，包含IP和ICMP头<br />-n --no-dns 显示数字的IP地址，不去查DNS<br />-b --show-ips 同时显示主机名和IP地址<br />-o --order FIELDORDER 设置输出列的顺序，例如 -o "LSD NBAW" 字符含义如下：L丢失率；D丢弃包数；R接收包数；S发送包数；N最新RTT；B最小RTT；W最大RTT；V标准偏差；G几何平均数；J当前抖动；M平均抖动；X最差抖动；I到达间隔抖动<br />-l --raw 使用原始输出格式<br />-a --address IP.ADD.RE.SS 绑定输出数据包到某个网络接口<br />-i SECONDS --interval SECONDS ICMP ECHO请求的发送间隔<br />-u 使用UDP数据报代替ICMP ECHO<br />-T --tcp 使用TCP SYN 包代替ICMP ECHO<br />-P PORT --port PORT 目标TCP端口<br />--timeout SECONDS 放弃连接之前保持TCP套接字打开的秒数<br />-4 -6 仅仅使用 IPv4或者 IPv6</p>
</td>
</tr>
<tr>
<td class="blog_h2">ping</td>
<td>
<p>发送因特网控制报文协议（ICMP）的ECHO_REQUEST数据报到网络上的主机<br /><span style="background-color: #c0c0c0;">格式：</span><br />ping <br />　　[-aAbBdDfhLnOqrRUvV] [-c count] [-F flowlabel] [-i interval] [-I interface] <br />　　[-l preload] [-m mark] [-M pmtudisc_option] [-N nodeinfo_option] [-w deadline] <br />　　[-W timeout] [-p pattern]　[-Q tos] [-s packetsize] [-S sndbuf] [-t ttl] <br />　　[-T timestamp option] [hop ...] destination</p>
<p><span style="background-color: #c0c0c0;">选项：</span><br />-c count 发送count个数据报后，停止发送，如果指定-w，会等待所有应答返回，直到超时<br />-D 在每一行的开始打印时间戳 Print timestamp (unix time + microseconds as in gettimeofday) before each line.<br />-f 只显示点号，当发送一个数据报时，打印一个点，收到一个响应时，打印一个退格键，如果不指定-i，则尽可能快的发送数据报<br />-i interval 两次发送数据报时的间隔，默认1秒<br />-I interface 指定地址或者网络接口的名称，数据报从该接口发出<br />-n 在输出中使用数字，不解析为主机名<br />-O 打印未到达的响应，一般与-D联用<br />-q 安静模式，只在开始和结束时打印统计信息<br />-r 跳过默认的路由表，直接往目标主机发送报文 <br />-s packetsize 发送的数据字节数，默认56，加上8字节的ICMP头，共计64字节<br />-w deadline 指定超时的秒数，ping在退出前会等待</p>
<p><span style="background-color: #c0c0c0;">举例：</span></p>
<pre class="crayon-plain-tag">ping -f blog.gmem.cc</pre>
</td>
</tr>
<tr>
<td class="blog_h2">whois</td>
<td>执行DNS注册信息查询</td>
</tr>
<tr>
<td class="blog_h2">curl</td>
<td>
<p>向服务器传输、从服务器读取数据。支持DICT, FILE, FTP, FTPS, GOPHER, HTTP, HTTPS, IMAP, IMAPS, LDAP, LDAPS, POP3,<br /> POP3S, RTMP, RTSP, SCP, SFTP, SMTP, SMTPS, TELNET和TFTP等协议
<p><span style="background-color: #c0c0c0;">格式：</span> <pre class="crayon-plain-tag">curl [options] [URL...]</pre></p>
<p><span style="background-color: #c0c0c0;">选项：</span></p>
<p># 显示进度条<br />-0 使用HTTP1.0<br />--http1.1 使用HTTP1.1<br />--http2.0 使用HTTP2.0<br />-1 使用TLSv1<br />-2 使用SSLv2<br />-3 使用SSLv3<br />-4 使用IPv4<br />-6 使用IPv6<br />-a 在用于FTP/SFTP上传时，附加到目标文件，而非替换它<br />-A 设置UserAgent<br />--anyauth 自动识别身份验证方式<br />-b 发送Cookie信息<br />-c 保存Cookie信息<br />-d 指定请求体参数<br />-D 输出Header<br />-e 设置Referer<br />-G 强制以GET方法提交<br />-H 设置请求头<br />-L 自动处理重定向<br />-X 指定使用的HTTP方法<br />--resolve host:port:ip 覆盖系统默认DNS解析<br />-w 指定输出的内容，可以用%{variable_name}格式指定输出变量。支持的变量包括：</p>
<p style="padding-left: 30px;">content_type  MIME类型<br />http_code  响应状态码<br />time_namelookup 到解析域名成功所消耗的时间<br />time_connect 到建立TCP连接所消耗的时间<br />time_total  总计消耗时间</p>
<p>-s  安静模式，不显示进度和错误信息<br />-v  显示冗长的调试性信息</p>
<p><span style="background-color: #c0c0c0;">示例：</span></p>
<pre class="crayon-plain-tag"># 输出响应到控制台
curl https://blog.gmem.cc
# 输出响应到文件
curl -o index.html https://blog.gmem.cc

# 设置HTTP头
curl -H "Host: ci.gmem.cc"  https://localhost

# HTTPS覆盖服务器DNS名
curl -sv --resolve git.pacloud.io:443:127.0.0.1 https://git.pacloud.io

# 下载文件到当前目录
curl -O https://www.gmem.cc/100.bin

# 通过SFTP下载
curl -u alex sftp://bj.gmem.cc/path/to/file

# 通过HTTP上传
curl --insecure -u "USER:PSWD" --data-binary "@/path/to/file" http://gmem.cc

# 获取HTTP头
curl -I http://www.gmem.cc

# 访问FTP服务器，列出文件和目录
curl ftp://ftp.gmem.cc --user username:password
# 上传文件到FTP服务器
curl -T file.zip ftp://ftp.gmem.cc/ --user username:password

# 设置Referer
curl -e "https://blog.gmem.cc/" https://gmem.cc

# POST
curl -d "name=alex&amp;password=111" http://blog.gmem.cc/login

# 保存Cookie
curl -c cookie.txt https://gmem.cc
# 发送Cookie
curl -b "key=value"  https://gmem.cc
curl -b cookie.txt https://gmem.cc

# 保存头
curl -D header.txt url

# 获取状态码

# 指定HTTP方法
curl -X PUT -d arg=val -d arg2=val2 localhost:8080

# 覆盖DNS解析
curl --resolve httpbin.k8s.gmem.cc:443:10.102.172.91 https://httpbin.k8s.gmem.cc/status/418

# 指定客户端证书
curl --cacert /home/alex/Documents/puTTY/ca.crt --cert alex.cert --key alex.key ... 

# 仅仅输出响应状态码
curl -s -o /dev/null -I -w "%{http_code}" http://10.0.11.11

# 设置UA
curl -A "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_2) AppleWebKit/537.17 (KHTML, like Gecko) Chrome/24.0.1312.52 Safari/537.17" url
curl -H "User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/44.0.2403.89 Safari/537.36" url</pre>
</td>
</tr>
<tr>
<td class="blog_h2">wget</td>
<td>
<p>非交互的从web或ftp站点上取得或下载文件
<p><span style="background-color: #c0c0c0;">格式：</span><br />wget [option]... [URL]...</p>
<p><span style="background-color: #c0c0c0;">基本选项：</span><br />-b --background 启动后转入后台运行<br /><span style="background-color: #c0c0c0;">日志选项：</span><br />-d --debug 打印调试输出<br />-q --quiet 安静模式，没有任何输出<br />-v --verbose 冗长模式，输出更多信息<br />-nv --non-verbose 关掉冗长模式，但不是安静模式<br />-o --output-file=LOG 把日志写到LOG文件中<br />-a --append-output=LOG 把日志追加到FILE文件中<br /><span style="background-color: #c0c0c0;">输入选项：</span><br />-i --input-file=FILE 读取输入文件，并下载其中的URL<br />-F --force-html 把输入文件当作HTML格式文件对待<br />-B --base=URL 基地址，用于解析输入文件中的相对地址<br /><span style="background-color: #c0c0c0;">下载选项：</span><br /> --bind-address=a 指定本地使用地址或主机名<br />-t --tries=NUMBER 设定最大尝试连接次数，0表示无限制<br />-O --output-document=F 把下载内容写到文件F中<br />-nc --no-clobber 不要覆盖存在的文件<br /> --backups=backups 备份被覆盖的文件，backups指定最大备份数量<br />-c --continue 接着下载没下载完的文件，断点续传<br /> --progress=dot/bar 设定进度条标记<br />-N --timestamping 不要重新下载文件除非比本地文件更新<br />-S --server-response 打印服务器的响应头<br />-T --timeout=SECONDS 设定响应超时的秒数<br />-w --wait=SECONDS 两次尝试之间间隔SECONDS秒<br />-Y --proxy=on/off 打开或关闭代理<br />-Q --quota=NUMBER 设置下载的容量限制，可以附带K/M/G单位<br /> --limit-rate=RATE 限定每秒下载输率，可以附带K/M/G单位<br />-4 --inet4-only 只使用IPv4<br />-6 --inet6-only 只使用IPv6<br /> --user=user<br /> --password=password 使用FTP或者HTTP用户名及密码<br /> --ask-password 手工输入密码<br /> --no-iri 禁用国际化的URL，默认禁用<br /><span style="background-color: #c0c0c0;">目录选项：</span><br />-nd --no-directories 当递归的下载时不创建目录层次，将导致所有文件存放在当前目录<br />-x --force-directories 与-nd相反，强制创建相应的目录层次<br />-nH --no-host-directories 禁止生成主机前缀目录，默认的http://gmem.cc会创建gmem.cc/目录<br /> --cut-dirs=number 忽略number层递归的远程目录的创建<br />-P --directory-prefix=p 下载文件保存到p/目录下<br /><span style="background-color: #c0c0c0;">HTTP选项：</span><br /> --default-page=name URL目录默认地址，用于代替index.html<br />-E --adjust-extension 根据Mime类型来调整文件扩展名<br /> --http-user=user<br /> --http-password=pswd 覆盖user/password，提供HTTP验证用户密码<br /> --no-http-keep-alive 关闭HTTP的keep-alive特性，默认的，连续下载多个文件会使用同一TCP连接<br /> --no-cache 禁用服务器端缓存，将发送no-cache请求头<br /> --no-cookies 禁用cookies<br /> --load-cookies file 从文件载入cookies<br /> --save-cookies file 保存cookiles<br /> --keep-session-cookies 让--save-cookies同时保存会话级cookies，默认会话级cookie在会话结束即失效<br /> --ignore-length 忽略响应头Content-Length<br /> --header=header-line 设置请求头，可以指定该选项多次<br /> --max-redirect=number 最大重定向次数<br /> --proxy-user=user<br /> --proxy-password=pswd 代理服务器验证使用<br /> --referer=url 设置请求头Referer: url<br /> --save-headers 保存服务器发送的请求头道文件<br />-U --user-agent=agent 指定请求头User-Agent<br /> --post-data=string<br /> --post-file=file 使用POST发送所有请求，并把请求体设置为参数指定的内容<br /> --method=HTTP-Method 指定使用的HTTP方法，例如POST或者GET<br /><span style="background-color: #c0c0c0;">HTTPS选项：</span> <br /> --secure-protocol=p 使用的安全协议，例如auto, SSLv2, SSLv3, TLSv1, PFS<br /> --https-only 递归下载时，仅下载HTTPS链接<br /> When in recursive mode, only HTTPS links are followed.<br /> --no-check-certificate 不验证服务器证书，也不要去URL的主机名与证书匹配<br /> --certificate=file 指定客户端证书所在的文件<br /> --certificate-type=type 客户端证书的类型，例如PEM,DER<br /> --private-key=file 指定私钥文件，允许私钥与证书存放在不同文件<br /> --private-key-type=type 私钥类型，例如PEM,DER<br /> --ca-certificate=file 指定CA证书文件<br /> --ca-directory=directory 指定CA证书的目录（PEM格式）<br /> --random-file=file<br /><span style="background-color: #c0c0c0;">递归下载：</span><br />-r, --recursive 递归下载<br />-l, --level=NUMBER 最大递归深度<br /> --delete-after 在下载完毕后局部删除文件<br />-k, --convert-links 转换非相对链接为相对链接<br />-K, --backup-converted 在转换文件X之前，将之备份为 X.orig<br />-m, --mirror 等价于 -r -N -l inf -nr.<br />-p, --page-requisites 下载为了展示HTML页面所必须的所有文件，例如图片<br />-A, --accept=LIST 分号分隔的被接受扩展名的列表<br />-R, --reject=LIST 分号分隔的不被接受的扩展名的列表<br />-D, --domains=LIST 分号分隔的被接受域的列表<br /> --exclude-domains=LIST 分号分隔的不被接受的域的列表<br /> --follow-ftp 跟踪HTML文档中的FTP链接<br /> --follow-tags=LIST 分号分隔的被跟踪的HTML标签的列表<br />-G, --ignore-tags=LIST 分号分隔的被忽略的HTML标签的列表<br />-H, --span-hosts 当递归时转到外部主机<br />-L, --relative 仅仅跟踪相对链接<br />-I, --include-directories=LIST 允许目录的列表<br />-X, --exclude-directories=LIST 不被包含目录的列表<br />-np, --no-parent 不要追溯到父目录</p>
<p><span style="background-color: #c0c0c0;">举例：</span></p>
<pre class="crayon-plain-tag">#下载JDK7
wget 
  --no-cookies 
  --no-check-certificate 
  --header "Cookie: gpw_e24=http%3A%2F%2Fwww.oracle.com%2F; oraclelicense=accept-securebackup-cookie" 
   "http://download.oracle.com/otn-pub/java/jdk/7u67-b01/jdk-7u67-linux-x64.tar.gz" 
   -O jdk-7u67-linux-x64.tar.gz
#下载Tomcat7
wget 
   "http://mirrors.hust.edu.cn/apache/tomcat/tomcat-7/v7.0.61/bin/apache-tomcat-7.0.61.tar.gz" 
   -O apache-tomcat-7.0.61.tar.gz</pre>
</td>
</tr>
<tr id="network-command-route">
<td class="blog_h2">route</td>
<td>
<p>显示或修改内核路由表信息
<p><span style="background-color: #c0c0c0;">格式：</span><br /> route [-CFvnee]<br /> route [-v] [-A family] add [-net|-host] target [netmask Nm] [gw Gw] [metric N] [mss M] [window W] [irtt I] [reject] [mod] [dyn] [reinstate] [[dev] If]<br /> route [-v] [-A family] del [-net|-host] target [gw Gw] [netmask Nm] [metric N] [[dev] If]<br /> route [-V] [--version] [-h] [--help]</p>
<p><span style="background-color: #c0c0c0;">选项：</span><br />-A family 使用指定的地址组，例如inet<br />-F 在内核的FIB路由表上操作，默认值 <br />-C 在内核的路由表缓存上操作<br />-n 显示基于数字的地址，而不是尝试将其解析为符号主机名 <br />-e 使用netstat(8)格式显示路由表<br />-ee 显示所有输出列<br />del 删除一条路由<br />add 添加一条路由<br />target 路由的目标网络或者主机，支持IP和主机名<br />-net 指定目标类型是网络<br />-host 指定目标类型是主机<br />netmask NM 添加网络的路由时使用，子网掩码<br />gw GW 通过网关（路由器）来路由，路由器必须直接可达<br />metric M 设置路由表的metric字段<br />mss M 设置通过此路由的TCP连接的最大段大小(Maximum Segment Size，MSS)，单位字节，默认为设备的MTU减去头部<br />window W 设置通过此路由的TCP连接的TCP窗口大小（TCP window size），单位字节，一般仅在AX.25 网络使用<br />irtt I 设置通过此路由的TCP连接的初始往返时间（initial round trip time，irtt），单位毫秒，一般仅在AX.25 网络使用<br />reject 安装一个阻断路由，用于强制一个路由查找失败<br />mod, dyn, reinstate 安装一个动态或者修改的路由，主要用于诊断用途<br />dev If 强制路由域指定的网络接口关联。否则内核会自己尝试判断使用哪个网络接口，如果该选项位于命令行尾部，dev字样可以省略</p>
<p><span style="background-color: #c0c0c0;">举例：</span></p>
<pre class="crayon-plain-tag">#添加一个普通的环回条目，使用子网掩码255.0.0.0，关联到网卡lo
route add -net 127.0.0.0 netmask 255.0.0.0 dev lo
#添加一个路由，使本地网络192.56.76.0通过网卡eth0访问
route add -net 192.56.76.0 netmask 255.255.255.0 dev eth0
#添加一条默认路由（默认路由在其它路由不匹配时生效）
#通过此路由的数据报都发往路由器mango-gw
#通往mango-gw的静态路由必须被事先设置
route add default gw mango-gw
#添加一条针对网络10.x.x.x的拒绝路由
route add -net 10.0.0.0 netmask 255.0.0.0 reject

#删除当前默认路由，默认路由的目的显示为 "default" 或者 0.0.0.0
route del default
#删除经有网关docker通向网络172.27.0.0/16的路由 
route del -net 172.27.0.0 netmask 255.255.0.0 gw docker</pre>
<p><span style="background-color: #c0c0c0;">输出：</span><br />包含以下列：<br />Destination 目标网络或者主机<br />Gateway 网关地址，如果没有设置，则为*（0.0.0.0）<br />Genmask 目的（即路由到的）网络的子网掩码。目标是H显示255.255.255.255，默认路由显示0.0.0.0。之所以叫Genmask使因为此字段显示了此路由的覆盖性（Generality）<br />Flags 标记，包括<br />　　U (该路由可用)<br />　　H (目标是主机)<br />　　G (使用网关，该标记非常重要，用于区分是直接还是间接路由，前者不需要G)<br />　　R (动态路由的复原路由)<br />　　D (该路由由重定向报文创建)<br />　　M (该路由已被重定向报文修改)<br />　　A (通过addrconf添加的路由)<br />　　C (缓存条目)<br />　　! (拒绝路由)</p>
<p>Metric　到目标的“距离”，使用hops计数表示<br />Ref　正在使用路由的活动进程个数<br />Use　显示的是通过该路由发送的分组数<br />Iface　数据报发往的网络接口<br />MSS　通过此路由的TCP连接的最大段大小<br />Window　通过此路由的TCP连接的TCP窗口大小<br />irtt　通过此路由的TCP连接的初始往返时间，内核使用该值猜测理想TCP协议参数</p>
</td>
</tr>
<tr>
<td class="blog_h2">netcat<br />nc</td>
<td>
<p>通过TCP和UDP在网络中读写数据</p>
<p><span style="background-color: #c0c0c0;">示例：</span></p>
<pre class="crayon-plain-tag"># 端口扫描：扫描172.31.100.7的21-25之间的端口
# -z 连接成功后立即关闭
# -v 输出详细信息
# -n 不要进行DNS反查
nc -z -v -n 172.31.100.7 21-25

# 开启服务器
nc -l 1567
# 开启客户端
nc 172.31.100.7 1567

# 文件传输
nc -l 1567 &lt; file.txt
nc -n 172.31.100.7 1567 &gt; file.txt

# 磁盘克隆
dd if=/dev/sda | nc -l 1567
nc -n 172.31.100.7 1567 | dd of=/dev/sda</pre>
</td>
</tr>
<tr>
<td>socat</td>
<td>
<p>多用途的套接字转发器，能够建立两个双向套接字，并在其间中继数据
<p>socat命令实例的生命周期分为以下阶段：</p>
<ol>
<li>init阶段：解析选项、初始化日志</li>
<li>open阶段：打开第一个地址，然后打开第二个地址。该步骤通常是非阻塞的</li>
<li>transfer阶段：通过select()监控两个流的文件描述符上的读写，并进行中继</li>
<li>closing阶段：当某一个流到达EOF，该阶段启动，传输EOF到另外一个流</li>
</ol>
<p><span style="background-color: #c0c0c0;">格式：</span></p>
<pre class="crayon-plain-tag">socat [options] &lt;address&gt; &lt;address&gt;</pre>
<p>-d 打印更多信息，指定-d多次，则信息更详细，最多4个<br />-D 进入transfer模式之前，打印文件描述符信息<br />-lf 打印日志到文件而非stderr<br />-x 同时将中继的数据写入到stderr<br />-u 非双向模式，从第一个地址读，写入第二个<br />-U 非双向模式，从第二个地址读，写入第一个</p>
<p><span style="background-color: #c0c0c0;">地址规格：</span></p>
<p style="padding-left: 30px;">地址类型关键字:[地址参数1:地址参数...][,地址选项1,地址选项2...]</p>
<p>地址类型关键字大小写不敏感，对于某些地址类型，关键字可以省略</p>
<p>如果地址规格以数字开头，则被假设为FD（原始文件描述符）地址，如果在第一个:或,之前出现 /，则假设关键字为GOPEN（一般性文件打开）</p>
<p><span style="background-color: #c0c0c0;">地址类型：</span></p>
<p>CREATE:&lt;filename&gt;  以create()打开指定的路径，并使用FD进行写（以create打开的不支持读）操作<br />EXEC:&lt;command-line&gt;  创建子进程，通过execvp()调用一个程序<br />FD:&lt;fdnum&gt;  打开文件描述符<br />GOPEN:&lt;filename&gt; 打开文件<br />OPEN:&lt;filename&gt;  使用open()调用打开文件，针对UDS会出错<br />IP-SENDTO:&lt;host&gt;:&lt;protocol&gt;  打开原始IP套接字，进行发送<br />IP4-SENDTO:&lt;host&gt;:&lt;protocol&gt;<br />IP6-SENDTO:&lt;host&gt;:&lt;protocol&gt;<br />IP-RECVFROM:&lt;protocol&gt;  打开原始IP套接字，进行接收<br />IP4-RECVFROM:&lt;protocol&gt;<br />INTERFACE:&lt;interface&gt;  连接到网卡，使用链路层通信<br />STDIN：打开标准输入<br />STDOUT：打开标准输出<br />TCP:&lt;host&gt;:&lt;port&gt; 连接到TCP服务器<br />TCP-LISTEN:&lt;port&gt; 打开TCNP端口并监听<br />UDP:&lt;host&gt;:&lt;port&gt; 发送到UDP服务器<br />UDP-LISTEN:&lt;port&gt; 打开UDP端口并监听<br />UNIX-CONNECT:&lt;filename&gt;  连接到UDS套接字<br />UNIX-LISTEN:&lt;filename&gt; 监听UDS套接字<br />ABSTRACT-CONNECT:&lt;string&gt;  和UNIX类似，仅仅针对抽象命名空间<br />ABSTRACT-LISTEN:&lt;string&gt;<br />ABSTRACT-SENDTO:&lt;string&gt;<br />ABSTRACT-RECVFROM:&lt;string&gt;<br />ABSTRACT-RECV:&lt;string&gt;<br />ABSTRACT-CLIENT:&lt;string&gt;</p>
<p><span style="background-color: #c0c0c0;">示例：</span></p>
<pre class="crayon-plain-tag"># 从文件读取信息
socat - /tmp/hello
# 写入信息到文件
echo hello | socat - /tmp/hello

# 连接到远程端口
socat - TCP:192.168.1.252:3306
# 监听端口
socat TCP-LISTEN:7000 -

# 监听抽象UDS
socat ABSTRACT-LISTEN:xtables -

# 端口转发 
socat -d -d -lf /var/log/socat.log 
  # 监听端口         绑定地址           
  TCP4-LISTEN:15672,bind=192.168.1.252,reuseaddr,fork 
  # 转发到的地址
  TCP4:172.17.0.15:15672</pre>
</td>
</tr>
<tr>
<td class="blog_h2">netstat</td>
<td>
<p>显示当前网络的统计和信息， 比如网络连接、路由表、网卡统计、组播关系
<p><strong><span style="background-color: #c0c0c0;">格式：</span></strong></p>
<pre class="crayon-plain-tag">netstat [address_family_options] [--tcp|-t] [--udp|-u] [--raw|-w] [--listening|-l] [--all|-a] [--numeric|-n] [--numeric-hosts] [--numeric-ports] [--numeric-users] [--symbolic|-N] [--extend|-e[--extend|-e]] [--timers|-o] [--program|-p] [--verbose|-v] [--continuous|-c]
netstat {-route|-r} [address_family_options] [--extend|-e[--extend|-e]] [--verbose|-v] [--numeric|-n] [--numeric-hosts] [--numeric-ports] [--numeric-users] [--continuous|-c]
netstat {-interfaces|-i} [--all|-a] [--extend|-e[--extend|-e]] [--verbose|-v] [--program|-p] [--numeric|-n] [--numeric-hosts] [--numeric-ports] [--numeric-users] [--continuous|-c]
netstat {-groups|-g} [--numeric|-n] [--numeric-hosts] [--numeric-ports] [--numeric-users] [--continuous|-c]
netstat {-masquerade|-M} [--extend|-e] [--numeric|-n] [--numeric-hosts] [--numeric-ports] [--numeric-users] [--continuous|-c]
netstat {-statistics|-s} [--tcp|-t] [--udp|-u] [--raw|-w]
netstat {-version|-V}
netstat {-help|-h} address_family_options: [-4] [-6] [--protocol={inet,unix,ipx,ax25,netrom,ddp}[,...]] [--unix|-x] [--inet|--ip] [--ax25] [--ipx] [--netrom] [--ddp]</pre>
<p><strong><span style="background-color: #c0c0c0;">子命令描述：</span></strong><br />本命令打印Linux网络系统的信息，信息的类型由第一个参数控制：<br />(none) 默认的，显示开启的Socket的信息，如果不指定任何地址族（address families）则所有配置的地址族均显示<br />--route , -r 显示内核路由表<br />--groups , -g 显示IPv4、IPv6组播关系<br />--interfaces, -i 显示网卡的表格<br />--masquerade , -M 显示masqueraded connections（Linux下类似于one-to-many的NAT的功能，允许内网机器通过单台连接到互联网机器上网）<br />--statistics , -s 显示各协议的统计信息</p>
<p><strong><span style="background-color: #c0c0c0;">选项：</span></strong><br />-A, --protocol=family 只显示选定的地址族（Socket种类），逗号分隔，包括inet, unix, ipx, ax25, netrom, ddp<br />--wide , -W 不截断IP地址<br />-n ,--numeric 显示数字的地址、端口、用户名，不指定可能显示主机名、知名端口名称<br />--numeric-hosts 显示数值的地址，不影响端口和用户名的解析<br />--numeric-ports 显示数值的端口，不影响主机和用户名的解析<br />--numeric-users 显示数值的用户ID，不影响主机和用户名的解析<br />--protocol=family , -A 指定地址族，逗号分隔<br />-c, --continuous 每秒刷新一次<br />-e, --extend 显示额外的信息，使用两次显示最大化信息<br />-o, --timers 包含和网络计时器相关的信息<br />-p, --program 显示每个Socket归属的PID和程序名<br />-l, --listening 仅显示监听Socket<br />-a, --all 显示监听和非监听Socket<br />-F 打印来自FIB的路由信息<br />--verbose , -v 显示冗长信息<br />-C 打印来自路由缓存的路由信息</p>
<p><span style="background-color: #c0c0c0;"><strong>输出：</strong></span></p>
<p><span style="background-color: #c0c0c0;">--- 默认输出 ---</span></p>
<pre class="crayon-plain-tag">root@gmem:~# netstat
Active Internet connections (w/o servers)
Proto Recv-Q Send-Q Local Address           Foreign Address         State
tcp        0      0 li759-7.members.l:59042 74.125.23.1:xmpp-client ESTABLISHED
tcp        0      0 localhost:48305         localhost:64001         TIME_WAIT
tcp        0    268 li759-7.members.lin:ssh 119.57.167.18:2065      ESTABLISHED
tcp        0      0 li759-7.members.li:http 119.57.167.18:5058      FIN_WAIT2

Active UNIX domain sockets (w/o servers)
Proto RefCnt Flags       Type       State         I-Node   Path
unix  11     [ ]         DGRAM                    8076     /dev/log
unix  2      [ ]         DGRAM                    8344
unix  3      [ ]         STREAM     CONNECTED     7974     @/com/ubuntu/upstart</pre>
<p><span style="background-color: #c0c0c0;">Active Internet connections (TCP, UDP, raw)</span><br />Proto　Socket使用的协议(tcp, udp, raw) <br />Recv-Q　通过该Socket接收到的，未被用户程序拷贝的字节数<br />Send-Q　通过该Socket接收到的，未被远程主机确认的字节数<br />Local Address　本地通信地址、端口<br />Foreign Address　远程通信地址、端口<br />State Socket的状态：<br />　　ESTABLISHED Socket包含一个建立的连接<br />　　SYN_SENT 正在尝试建立连接<br />　　SYN_RECV 已经从网络接收到连接请求<br />　　FIN_WAIT1 Socket被关闭，并且连接正在关闭<br />　　FIN_WAIT2 连接被关闭，Socket正在等待远端（remote end ）的关闭动作<br />　　TIME_WAIT Socket正在等待接收（于关闭后）仍然在网络上的数据包<br />　　CLOSE Socket没有被使用<br />　　CLOSE_WAIT 远端（remote end ）已经关闭，等待Socket的关闭<br />　　LAST_ACK 远端（remote end ）已经关闭，Socket被关闭，等待确认<br />　　LISTEN Socket正在监听传入连接<br />　　CLOSING 双方Socket都在关闭，但是本端仍有数据没发送<br />　　UNKNOWN 状态未知<br />User　Socket所有者的用户名或者UID<br />PID/Program　斜线分隔Socket所有者的PID和程序名</p>
<p><span style="background-color: #c0c0c0;">Active UNIX domain Sockets</span><br />Proto　Socket使用的协议(通常unix) <br />RefCnt　引用计数（附着到该Socket的进程数）<br />Flags　包括： SO_ACCEPTON (ACC)， SO_WAITDATA (W)， SO_NOSPACE (N)<br />Type Socket类型<br />　　SOCK_DGRAM Socket以数据报（无连接）模式使用<br />　　SOCK_STREAM Socket以数据流（有连接）模式使用<br />　　SOCK_RAW  原始Socket<br />　　SOCK_RDM 仅可靠传输消息<br />　　SOCK_SEQPACKET 顺序数据包<br />　　UNKNOWN <br />Path　附着到该Socket的进程路径</p>
<p><span style="background-color: #c0c0c0;">--- --route输出 ---</span></p>
<pre class="crayon-plain-tag">root@gmem:~# netstat -r
Kernel IP routing table
Destination     Gateway         Genmask         Flags   MSS Window  irtt Iface
default         gw-li759.linode 0.0.0.0         UG        0 0          0 eth0
106.185.46.0    *               255.255.255.0   U         0 0          0 eth0</pre>
<p>Destination　目标网络或者主机<br /> Gateway 　网关地址<br /> Genmask 　目标网络的子网掩码<br /> Flags　标记<br /> MSS 　通过此路由的TCP连接的最大段大小<br /> Window 　通过此路由的TCP连接的TCP窗口大小<br /> irtt 　通过此路由的TCP连接的初始往返时间<br /> Iface　所使用的网络接口</p>
<p><span style="background-color: #c0c0c0;">--- --groups输出 ---</span></p>
<pre class="crayon-plain-tag">root@gmem:~# netstat --groups
IPv6/IPv4 Group Memberships
Interface       RefCnt Group
--------------- ------ ---------------------
lo              1      all-systems.mcast.net
eth0            1      all-systems.mcast.net
lo              1      ip6-allnodes</pre>
<p>Interface　参与组播的网络接口<br />RefCnt　参与到此多播组的进程数量<br />Group　多播组的名称或地址</p>
<p><strong><span style="background-color: #c0c0c0;">举例：</span></strong></p>
<pre class="crayon-plain-tag">#列出所有处于监听状态的TCP端口，使用数字来显示地址与端口
#如果不指定n参数，可能会以“知名端口”名来显示端口，不利于直观的查看
#例如8080端口可能显示为sunrpc
netstat -ltn
netstat -a  #列出所有端口
netstat -at #列出所有tcp端口
netstat -au #列出所有udp端口 
netstat -l  #列出所有处于监听状态的 Sockets
netstat -s  #显示所有端口的统计信息
netstat -st # 显示TCP端口的统计信息
netstat -p  #在输出中显示PID和进程名称
netstat -antp -4 #显示所有IPv4的监听、非监听Socket，并且不显示主机名
netstat -r  #显示核心路由信息
netstat -ap | grep ssh   #搜索程序运行的端口
netstat -an | grep ':80' #搜索占用端口的进程
netstat -i  #显示网络接口列表</pre>
</td>
</tr>
<tr>
<td class="blog_h2">tcpdump</td>
<td>
<p>网络包嗅探器。把匹配指定expression的包头都显示出来。在tcpdump运行结束后，会报告以下内容：<br />捕获的包个数（tcpdump接收被处理的包个数）<br />内核丢弃的包个数（由于缺少缓冲区）
<p><span style="background-color: #c0c0c0;">格式：</span></p>
<p>tcpdump <br />　　[ -AbdDefhHIJKlLnNOpqRStuUvxX ] [ -B buffer_size ] [ -c count ]<br />　　[ -C file_size ] [ -G rotate_seconds ] [ -F file ]<br />　　[ -i interface ] [ -j tstamp_type ] [ -m module ] [ -M secret ]<br />　　[ -P in|out|inout ]<br />　　[ -r file ] [ -V file ] [ -s snaplen ] [ -T type ] [ -w file ]<br />　　[ -W filecount ]<br />　　[ -E spi@ipaddr algo:secret,... ]<br />　　[ -y datalinktype ] [ -z postrotate-command ] [ -Z user ]<br />　　[ expression ]</p>
<p><span style="background-color: #c0c0c0;">选项：</span></p>
<p>-A 以ASCII形式打印每个包（除去连接层头部）<br />-B 设值操作系统捕获缓冲区大小，单位KB<br />-c 接收到指定数量的包后退出<br />-C 在把原始包写入文件前，检查当前文件是否大于file_size，如果是，关闭并打开新文件。后续文件的名称依据-w选项确定，后缀以1开始的序号，file_size的单位是100万字节<br />-D 打印可捕获包的网络接口的列表，对于每个接口，打印一个数字、接口名称，可能附加一个文字描述<br />-e 在dump的每一行打印链路层头部，可以用于为以太网、IEEE 802.x等协议打印MAC地址<br />-F 使用文件作为过滤表达式（filter expression）的输入。如果指定该参数，命令行提供的表达式被忽略<br />-h 打印tcpdump、libpcap版本和用法，并退出<br />-i 指定需要监听的网络接口<br />-j 设置时间戳类型为tstamp_type<br />-J 列出网络接口支持的时间戳类型并退出<br />-K 不去尝试验证IP、TCP、UDP的校验和<br />-L 列出网卡已知的数据链路类型，并退出<br />-n 不把地址（主机地址、端口等）转换为名称<br />-N 不去打印主机名所属域部分<br />-P 选择需要捕捉的包的类型（发送还是接收），有效的值包括in、out、inout<br />-p 不要把网卡改为混杂模式<br />-q 快速模式，打印较少的协议信息<br />-r 从文件中读取包（文件是通过-w选项创建的）<br />-S 打印绝对（而不是相对）的TCP序列号<br />-t 不在每一行上打印时间戳<br />-tt 在每一行打印未格式化的时间戳<br />-ttt 打印与前一行的时间偏移量，以微秒为单位<br />-tttt 使用默认格式打印时间戳<br />-ttttt 打印与第一行的时间偏移量，以微秒为单位<br />-u 打印未编码的NFS句柄<br />-v 冗余输出IP包的选项字段被打印，同时启用额外的包完整性检查，例如验证IP、ICMP头的校验和。使用-w时每10秒打印捕获的包个数<br />-vv 更冗余的输出<br />-vvv 更更冗余的输出<br />-w 打印原始包到文件，而不是解析、打印到标准输出<br />-W 与-C联用，限制文件的数量，如果超过了，循环覆盖第一个文件<br />-x 当解析并打印时，除了打印包的头部，还以HEX形式打印包除去链路层头的数据部分<br />-xx 当解析并打印时，除了打印包的头部，还以HEX形式打印包的数据部分<br />-X 当解析并打印时，除了打印包的头部，还以HEX、ASCII形式打印包除去链路层头的数据部分<br />-XX 当解析并打印时，除了打印包的头部，还以HEX、ASCII形式打印包的数据部分<br />-y 在捕获包到datalinktype时设置datalinktype</p>
<p>关于表达式<br />表达式用于过滤哪些包需要被输出，如果不指定表达式，则所有包被输出，表达式语法参考pcap-filter</p>
<p><span style="background-color: #c0c0c0;">关于iptables：</span></p>
<p>对于<span style="background-color: #c0c0c0;">出站流量来说，tcpdump是最后一个看见流量的软件</span>，也就是说，只要tcpdump看到流量，就说明本机没有软件层次上的防火墙措施。<span style="background-color: #c0c0c0;">如果iptables DROP掉了包，则tcpdump不会抓到包</span></p>
<p style="padding-left: 30px;">iptables ⇨ tcpdump ⇨ 网络接口 ⇨网线</p>
<p>对于<span style="background-color: #c0c0c0;">入站流量来说，tcpdump是第一个看见流量的软件</span></p>
<p style="padding-left: 30px;">网线  ⇨ 网络接口 ⇨ tcpdump ⇨ netfilter/iptables</p>
<p><span style="background-color: #c0c0c0;">举例：</span></p>
<pre class="crayon-plain-tag"># 要在Vmware Guest上使用tcpdump，需要在Host上设置网卡的权限
sudo chmod a+rw /dev/vmnet8

# 打印来自、发往主机：zircon的包
tcpdump host zircon
# 打印 zircon与vm1或者vm2之间的包，注意花括号需要转义
tcpdump host zircon and \( vm1 or vm2 \)
# 打印zircon与除vm3以外所有主机的IP包
tcpdump ip host zircon and not vm3
# 打印所有通过网关snup的FTP流量
tcpdump 'gateway snup and (port ftp or ftp-data)'
# 打印既不是来源于、也不是发送到本地网络的IP数据报
tcpdump ip and not net 192.168.0.0/16
# 打印主机192.168.0.201与本机端口7777的IP数据报
tcpdump ip host 192.168.0.201 and port 7777 -n -p
# 对于每一个非本地主机参与的TCP连接，打印起始（SYN）与结束（FIN）包
tcpdump 'tcp[tcpflags] &amp; (tcp-syn|tcp-fin) != 0 and not src and dst net 192.168.0.0/16'
# 打印来自或者去往80端口的IPv4的HTTP包
tcpdump 'tcp port 80 and (((ip[2:2] - ((ip[0]&amp;0xf)&lt;&lt;2)) - ((tcp[12]&amp;0xf0)&gt;&gt;2)) != 0)'
# 打印通过网关snup，且大于576字节的IP数据报
tcpdump 'gateway snup and ip[2:2] &gt; 576'
# 打印不是通过以太网广播、多播的IP广多播包
tcpdump 'ether[0] &amp; 1 = 0 and ip[16] &gt;= 224'
# 打印非echo请求应答（ping）的ICMP包
tcpdump 'icmp[icmptype] != icmp-echo and icmp[icmptype] != icmp-echoreply'

# 监听所有网络接口
tcpdump -i any port 2379</pre>
</td>
</tr>
<tr>
<td class="blog_h2">ssh</td>
<td>
<p>OpenSSH客户端
<p><span style="background-color: #c0c0c0;">格式：</span><br />ssh <br />　　[-1246AaCfgKkMNnqsTtVvXxYy] <br />　　[-b bind_address] [-c cipher_spec] [-D [bind_address:]port] <br />　　[-E log_file] [-e escape_char] [-F configfile] [-I pkcs11] [-i identity_file]<br />　　[-L  [bind_address:]port:host:hostport] [-l login_name] [-m mac_spec] <br />　　[-O ctl_cmd] [-o option] [-p port] [-Q cipher | cipher-auth | mac | kex | key]<br />        [-R [bind_address:]port:host:hostport] [-S ctl_path] [-W host:port] <br />        [-w local_tun[:remote_tun]] <br />        [user@]hostname [command]</p>
<p><span style="background-color: #c0c0c0;">描述：</span><br />SSH客户端用于<span style="background-color: #c0c0c0;">登陆到远程机器，并在远程机器上执行命令</span>。支持在两个不相互信任的机器之间，通过不安全网络建立安全连接。<br />如果提供command选项，那么会在远程机器上执行命令而不是登陆为Shell<br />SSH客户端亦可充当<span style="background-color: #c0c0c0;">SOCKS代理服务器</span>，进行<span style="background-color: #c0c0c0;">端口转发</span>，或者实现<span style="background-color: #c0c0c0;">反向连接（到内网机器）</span></p>
<p><span style="background-color: #c0c0c0;">选项：</span><br />-1 强制ssh使用协议1<br />-2 强制ssh使用协议2<br />-4 强制ssh仅使用IPv4<br />-6 强制ssh仅使用IPv6<br />-q 安静模式，服务器的Banner不会显示<br />-b 仅在多IP机器上使用，指定连接的源地址<br />-C 要求对所有数据进行压缩。压缩算法于gzip一致<br />-c 指定连接的加密算法<br />-D 指定本地应用级的端口转发，发往本地bind_address:port的套接字连接一律通过SSH隧道转发。应用协议用来确定在远程机器上连接到何处，支持的协议是SOCKS4、SOCKS5，SSH充当SOCKS服务器<br />-E 将调试日至转发到文件而不是stderr<br />-F 指定备选的用户级别的配置文件，会导致全局配置文件<pre class="crayon-plain-tag">/etc/ssh/ssh_config</pre> 被忽略，默认用户级别配置文件为<pre class="crayon-plain-tag">~/.ssh/config</pre> <br />-f 让ssh在执行命令前转到后台运行。如果配置项ExitOnForwardFailure=true，则启用此选项的ssh客户端会在所有远程端口转发成功建立后才传入后台<br />-g 允许远程主机连接到本地已转发（forwarded）端口<br />-I 指定ssh使用的PKCS#11共享库<br />-i 指定用于公钥身份验证的私钥文件。对于协议1，默认文件<pre class="crayon-plain-tag">~/.ssh/identity</pre> ，对于协议2，默认文件<pre class="crayon-plain-tag">~/.ssh/id_dsa</pre> 、<pre class="crayon-plain-tag">~/.ssh/id_ecdsa</pre> 、<pre class="crayon-plain-tag">~/.ssh/id_ed25519</pre> 、<pre class="crayon-plain-tag">~/.ssh/id_rsa</pre> 。可以在配置文件中针对每个主机设置私钥文件<br />-L 将本机[bind_address:]port转发到远程host:hostport<br />-l 登陆到远程机器时使用的用户名<br />-N 不执行远程命令，在仅仅用ssh进行端口转发时指定<br />-n 重定向标准输入到/dev/null，当ssh在后台运行时，必须指定，指定-f时自动指定此选项<br />-o 覆盖配置文件中的选项，例如-o "IdentityFile=gmem.key"<br />-p 远程主机的监听端口<br />-R 反向端口转发，远程机器（服务器）[bind_address:]port被自动转发到本地机器host:hostport。该选项启用后，ssh在远程机器（服务器）上开启port的监听，并把针对远程机器bind_address地址port端口的请求全部通过SSH隧道转发到本地。忽略bind_address或者将其指定为*则绑定远程机器的所有IP地址<br />注意：如果服务器使用的是OpenSSH，必须启用</p>
<pre class="crayon-plain-tag">GatewayPorts yes</pre>
<p>否则总是绑定到127.0.0.1<br />-T 不分配伪终端（pseudo-tty）</p>
<p>-t 强制分配伪终端<br />-v 冗长模式，打印调试信息</p>
<p><span style="background-color: #c0c0c0;">端口转发功能：</span></p>
<p>SSH客户端支持三种端口转发（SSH隧道）：</p>
<p>-L 本机网络接口:本机端口:远程网络接口:远程端口。正向转发，本机可以通过本机端口访问远程服务<br />-R 远程网络接口:远程端口:本机网络接口:本机端口。反向转发，远机可以通过本机端口访问本机服务<br />-D 本机网络接口:本机端口。动态转发，本地产生一个Socks代理，通过代理的请求，发送到远机的相同端口。例如本地代理端口8087，本地客户端访问xxxx端口都会被转发给远程主机的xxxx端口</p>
<p><span style="background-color: #c0c0c0;">注意：</span><br />服务器端是OpenSSH时，默认情况下root不能通过密码登录到SSH，需要修改：</p>
<pre class="crayon-plain-tag">PermitRootLogin yes</pre>
<p><span style="background-color: #c0c0c0;">举例：</span></p>
<pre class="crayon-plain-tag"># 基于公钥认证机制登陆
ssh -i ~/Documents/puTTY/gmem.key root@vpn.gmem.cc

# 启用正向端口转发，将本机2222端口转发到192.168.104.91:22
ssh -nNTf -L 0.0.0.0:2222:192.168.104.91:22 -o "ExitOnForwardFailure yes" root@192.168.104.91

# 启用反向端口转发
ssh -nNT -R vpn.gmem.cc:2022:localhost:22 root@vpn.gmem.cc
    -o "ExitOnForwardFailure yes"   # 转发失败则退出remote port forwarding failed for listen...

# 连接到目标机器，执行两个命令，然后退出
ssh -i /root/Documents/puTTY/gmem.key root@tk.gmem.cc "uname;echo OK"</pre>
</td>
</tr>
<tr>
<td class="blog_h2">sshpass</td>
<td>
<p>通过命令行传递SSH密码
<p>执行下面的命令安装此工具：</p>
<pre class="crayon-plain-tag">sudo apt-get install sshpass</pre>
<p><span style="background-color: #c0c0c0;">示例：</span></p>
<pre class="crayon-plain-tag">sshpass -p password ssh root@host</pre>
</td>
</tr>
<tr>
<td class="blog_h2">scp</td>
<td>
<p>安全拷贝（远程文件拷贝）
<p><span style="background-color: #c0c0c0;">格式：</span><br />scp <br />　　[-1246BCpqrv] [-c cipher] [-F ssh_config] [-i identity_file] <br />　　[-l limit] [-o ssh_option] [-P port] [-S program] <br />　　[[user@]host1:]file1 ... <br />　　[[user@]host2:]file2</p>
<p><span style="background-color: #c0c0c0;">描述：</span><br />该命令使用SSH来进行网络上文件的拷贝，使用与SSH一样的身份验证并提供与SSH一样的安全性保证，如果需要身份验证，scp会提示输入密码。<br />可以将本地文件拷贝到远程服务器，反之亦可，在两台远程服务器之间拷贝文件也是支持的。<br />当目标文件存在时，scp会覆盖其内容，但是保留inode；如果目标文件不存在，则首先创建一个空白文件，并把内容填充进去</p>
<p>Windows下可以安装WinSSHD以支持SCP。</p>
<p><span style="background-color: #c0c0c0;">选项：</span><br />-1 强制scp使用协议1<br />-2 强制scp使用协议2<br />-4 强制scp仅使用IPv4<br />-6 强制scp仅使用IPv6<br />-B 执行批处理模式（阻止密码输入提示）<br />-C 启用压缩<br />-c cipher 指定用于加密传输数据的密钥<br />-F ssh_config 指定传输给ssh的配置文件<br />-i identity_file 指定ssh私钥文件，用于基于公钥的的身份验证<br />-l limit 限制使用带宽（Kbit/s）<br />-P port 指定远程主机的端口<br />-p 保留原始文件的修改时间、访问时间等信息<br />-q 安静模式，禁用进度、诊断信息<br />-r 递归的复制整个目录，自动以树遍历顺序跟踪符号连接的目标<br />-S program 用于加密连接的程序<br />-v 冗长模式，导致scp和ssh打印调试信息</p>
<p><span style="background-color: #c0c0c0;">举例：</span></p>
<pre class="crayon-plain-tag"># 将远程文件复制到本机当前目录（注意Windows路径的转写）
scp Suigintou@192.168.0.89:/e:/Software/Developer/pdtenv/Tomcat7.tar.gz  .
# 复制目录下所有sh文件，当前目录同名文件自动覆盖
scp root@192.168.0.90:/usr/local/Kingsmart/Tomcat7/*.sh .
# 将本地文件复制到远程机器
scp -i ~/gmem.key /tmp/gmem.sql root@tk.gmem.cc:/tmp/gmem.sql</pre>
</td>
</tr>
<tr>
<td class="blog_h2">sftp</td>
<td>
<p>SFTP客户端。该客户端使用SSH协议进行通信
<p><span style="background-color: #c0c0c0;">选项：<br /></span>很多SSH、SCP命令的配置可以使用，这里不列出<br />-D sftp_server_path  直接连接到本地SFTP服务器</p>
<p><span style="background-color: #c0c0c0;">交互式命令：</span><br />bye  exit  退出<br />cd   修改服务器的当前目录<br />chgrp  修改服务器文件的组<br />chmod  修改服务器文件的权限<br />chown  修改服务器文件的所有者<br />df  显示当前目录所在文件系统的使用情况信息。-h人类可读，-i显示inode信息<br />get [-afPpr] remote-path [local-path]<br />下载远程文件到本地，如果local-path不指定则文件名由远程给出。remote-path可以包含通配符以匹配多个文件，local-path可以是目录。-a 尝试断点续传，-f在传输完成后调用fsync，-P/-p拷贝权限和访问时间信息，-r递归下载子目录<br />lcd  修改本地的当前目录<br />lls  列出本地文件<br />lmkdir  在本地创建目录<br />ln  创建符号连接<br />lpwd  打印本地当前目录<br />ls  列出远程文件<br />lumask  设置本地umask<br />mkdir  创建远程目录<br />progress  显示进度信息<br />put [-fPpr] local-path [remote-path]   上传本地文件到服务器<br />pwd  显示当前目录<br />reget [-Ppr] remote-path [local-path]  断点续传<br />rename oldpath newpath  重命名<br />rm path  删除文件<br />rmdir path  删除目录</p>
<p><span style="background-color: #c0c0c0;">举例：</span></p>
<pre class="crayon-plain-tag"># 使用公钥认证，连接到交互式客户端
sftp -o "IdentityFile=/root/Documents/puTTY/gmem.key" root@tokyo.gmem.cc

# 进入指定本地目录
lcd /var/lib
# 进入指定的远程目录
cd /var/lib

# 列出远程文件
ls

# 下载远程目录到本地
get -ar mysql

# 修改远程文件的组、权限、所有者
chgrp grp /path/to
chmod mode /path/to
chown own /path/to


# 退出交互式客户端
exit</pre>
</td>
</tr>
<tr>
<td class="blog_h2">nmap</td>
<td>
<p>执行网络探测与端口扫描<br />该工具可以用来快速扫描大型网络
<p><span style="background-color: #c0c0c0;">格式：</span><br />nmap [Scan Type...] [Options] {target specification}</p>
<p><span style="background-color: #c0c0c0;">目标选项：</span><br />可以指定主机名、IP地址或者网络，例如：scanme.nmap.org, microsoft.com/24, 192.168.0.1; 10.0.0-255.1-254<br />-iL　从文件中读取目标<br />-iR　随机选取目标<br />--exclude　排除目标<br />--excludefile　从文件中读取排除目标<br /><span style="background-color: #c0c0c0;">目标发现选项:</span><br />-sL　简单的列出待扫描的目标<br />-sn　使用PING扫描，禁用端口扫描<br />-Pn　认为所有目标主机在线<br />-PS/PA/PU/PY[portlist]　对端口列表执行TCP SYN/ACK,UDP或SCTP扫描<br />-PE/PP/PMICMP　执行echo, timestamp,或者netmask request探针<br />-PO[protocol list]　执行IP协议PING<br />-n/-R　从不/总是进行DNS查找<br />--dns-servers　指定逗号分隔的DNS列表<br />--system-dns　使用操作系统DNS<br />--traceroute　跟踪每个主机的路由情况<br /><span style="background-color: #c0c0c0;">扫描技术选项:</span><br />-sS/sT/sA/sW/sM　执行TCP SYN/Connect()/ACK/Window/Maimon扫描<br />-sU　执行UDP扫描<br />-sN/sF/sX　执行TCP Null, FIN, Xmas扫描<br />--scanflags　定制TCP扫描标记<br />-sI　执行空闲扫描<br />-sO　IP协议扫描<br /><span style="background-color: #c0c0c0;">端口选项：</span><br />-p　仅扫描指定的端口，合法的实例：-p22; -p1-65535; -p U:53,111,137,T:21-25,80,139,8080,S:9<br />-F　快速扫描，比标准扫描探测更少的端口<br />-r　顺序的扫描端口<br />--top-ports num　扫描num个最知名的端口<br /><span style="background-color: #c0c0c0;">服务检测：</span><br />-sV　探测打开的端口，以确定服务的类型与版本<br /><span style="background-color: #c0c0c0;">操作系统检测：</span><br />-O　启用操作系统检测<br /><span style="background-color: #c0c0c0;">输出选项：</span><br />-oN/-oX/-oS/-oG file　输出一般格式,XML格式,kIddi3,Grepable格式到文件<br />--reason　显示当口处于某个状态的原因<br />--open　仅显示打开状态的端口<br />--packet-trace　显示所有收发的数据包<br />--append-output　附加到输出文件的尾部而不是覆盖<br />-v　增加输出的冗长级别<br />-vv进一步增加输出的冗长级别</p>
<p><span style="background-color: #c0c0c0;">其它选项：</span><br />-6　启用IPv6扫描<br />--send-eth　发送原始以太网数据桢<br />--send-ip　发送IP数据报<br />-A　启用操作系统探测、版本探测、路由跟踪</p>
<p><span style="background-color: #c0c0c0;">举例：</span></p>
<pre class="crayon-plain-tag">#对gmem.cc进行全面扫描
nmap -v -A gmem.cc
#alex@amethystine:~$ nmap -v -A gmem.cc
#Starting Nmap 6.40 ( http://nmap.org ) at 2015-05-21 15:15 CST
#NSE: Loaded 110 scripts for scanning.
#NSE: Script Pre-scanning.
#执行PING扫描
#Initiating Ping Scan at 15:15
#Scanning gmem.cc (106.185.46.7) [2 ports]
#Completed Ping Scan at 15:15, 0.07s elapsed (1 total hosts)
#执行DNS解析
#Initiating Parallel DNS resolution of 1 host. at 15:15
#Completed Parallel DNS resolution of 1 host. at 15:15, 0.01s elapsed
#Initiating Connect Scan at 15:15
#扫描端口，可以看到该服务器可能开启了MySQL、Apache、SSH服务
#Scanning gmem.cc (106.185.46.7) [1000 ports]
#Discovered open port 80/tcp on 106.185.46.7
#Discovered open port 22/tcp on 106.185.46.7
#Discovered open port 1723/tcp on 106.185.46.7
#Discovered open port 3306/tcp on 106.185.46.7
#Discovered open port 3690/tcp on 106.185.46.7
#Completed Connect Scan at 15:16, 13.28s elapsed (1000 total ports)
#扫描应用服务
#Initiating Service scan at 15:16
#Scanning 5 services on gmem.cc (106.185.46.7)
#Completed Service scan at 15:16, 15.58s elapsed (5 services on 1 host)
#NSE: Script scanning 106.185.46.7.
#Initiating NSE at 15:16
#Completed NSE at 15:16, 2.77s elapsed
#Nmap scan report for gmem.cc (106.185.46.7)
#Host is up (0.10s latency).
#rDNS record for 106.185.46.7: li759-7.members.linode.com
#Not shown: 995 closed ports
#PORT     STATE SERVICE  VERSION
#探测到SSH服务
#22/tcp   open  ssh      (protocol 2.0)
#| ssh-hostkey: 1024 2c:89:42:27:6d:12:b0:17:72:79:3f:ad:51:e0:04:ed (DSA)
#| 2048 1b:1e:2d:e0:10:c1:89:62:4e:c2:bc:7f:dd:ae:67:a1 (RSA)
#|_256 62:5f:c1:16:c7:42:b6:46:0d:d9:69:b0:88:c1:4b:6d (ECDSA)
#探测到Apache服务
#80/tcp   open  http     Apache httpd 2.4.7 ((Ubuntu))
#|_http-methods: POST OPTIONS GET HEAD
#|_http-title: Site doesn't have a title (text/html)
#探测到VPN服务
#1723/tcp open  pptp     linux (Firmware: 1)
#探测到MySQL服务
#3306/tcp open  mysql    MySQL 5.5.35-1ubuntu1
#| mysql-info: Protocol: 10
#| Version: 5.5.35-1ubuntu1
#| Thread ID: 8572
#| Some Capabilities: Long Passwords, Connect with DB, Compress, ODBC, Transactions, Secure Connection
#| Status: Autocommit
#|_Salt: &amp;a81/9l7
#探测到SVN服务
#3690/tcp open  svnserve Subversion
#NSE: Script Post-scanning.
#Initiating NSE at 15:16
#Completed NSE at 15:16, 0.00s elapsed
#Read data files from: /usr/bin/../share/nmap
#Service detection performed. Please report any incorrect results at http://nmap.org/submit/ .
#Nmap done: 1 IP address (1 host up) scanned in 31.95 seconds


#对本地局域网进行PING扫描
nmap -v -sn 192.168.0.1-254</pre>
</td>
</tr>
<tr>
<td class="blog_h2">ifconfig</td>
<td>
<p>查看或者配置网络接口
<p><span style="background-color: #c0c0c0;">描述：</span><br />该命令用于配置内核常驻（kernel-resident）的网络接口，可以在系统启动时建立网络连接，如果不给定任何参数，该命令会显示当前活动的网络接口的列表</p>
<p><span style="background-color: #c0c0c0;">格式：</span><br />ifconfig [-v] [-a] [-s] [interface]<br />ifconfig [-v] interface [aftype] options | address ...</p>
<p><span style="background-color: #c0c0c0;">选项：</span><br />-a　显示所有网络接口，包括已经停用的<br />-s　显示简短列表，类似netstat -i<br />interface　网络接口的名称<br />aftype　地址族，用于解析和现实所有协议地址，支持inet (TCP/IP, default), inet6 (IPv6), ax25 (AMPR Packet Radio), ddp (Appletalk Phase 2), ipx (Novell IPX) 以及 netrom (AMPR Packet radio)<br />up　该标记导致网络接口被激活，如果为网络接口分配了IP地址，则自动隐含该标记<br />down　该标记导致网络接口被停用<br />[-]arp　启用或者停用该网络接口的APR协议支持 <br />[-]promisc　启用或者停用网络接口的混杂模式，如果启用，网络上所有数据报被该网络接口接收<br />[-]allmulti　启用或者停用网络接口的全组播模式，如果启用，网络上所有多播包被该网络接口接收<br />metric N　在计算数据包转发次数时，所要加上的数目<br />mtu N　设置最大传输单元<br />dstaddr addr　设置PPP协议远端的IP地址<br />netmask addr　设置该网络接口的子网掩码<br />add addr/prefixlen　为网络接口分配一个IPv6地址<br />del addr/prefixlen　为网络接口移除一个IPv6地址<br />[-]broadcast [addr]　设置该网络接口的广播地址，或者清除该网络接口的IFF_BROADCAST标记<br />[-]pointopoint [addr]　启用点对点模式，与另外一台计算机直连<br />hw class address　如果设备驱动支持，可以设置该网络接口的硬件地址<br />multicast　设置该网络接口的多播标记<br />address　设置分配给该网络接口的IP地址</p>
<p><span style="background-color: #c0c0c0;">举例：</span></p>
<pre class="crayon-plain-tag">#设置eth1的广播地址
ifconfig eth1 broadcast 192.168.0.255
#设置eth0的IP地址
ifconfig eth0 192.168.0.90
#停用eth1
ifconfig eth1 down</pre>
</td>
</tr>
<tr>
<td class="blog_h2">ip</td>
<td>
<p>显示或者配置路由、网卡、策略路由或者隧道
<p>关于Linux路由的更多知识，参考：<a href="/network-faq#route">Linux网络知识集锦</a></p>
<p><span style="background-color: #c0c0c0;">格式：</span></p>
<pre class="crayon-plain-tag"># 如果不清楚对象支持哪些命令，可以 ip object help
ip [ OPTIONS ] OBJECT { COMMAND | help }
ip [ -force ] -batch filename</pre>
<p><span style="background-color: #c0c0c0;">选项：</span><br />-V, -Version 显示版本并退出<br />-b, -batch &lt;FILENAME&gt; 批处理模式，从指定的文件或者标准输入读取命令并调用，第一个错误导致退出<br />-force 批处理模式中出现错误时不退出<br />-s, -stats, -statistics 输出更多的信息，该选项使用多次会导致更多的信息被打印<br />-l, -loops &lt;COUNT&gt; 命令 ip addr flush 最大循环次数，默认0表示循环直到所有地址被移除<br />-f, -family &lt;FAMILY&gt; 指定使用的地址族<br />-4 等价于 -family inet<br />-6 等价于 -family inet6<br />-B 等价于 -family bridge<br />-D 等价于 -family decnet<br />-I 等价于 -family ipx<br />-0 等价于 -family link<br />-o, -oneline 每个记录单独一行显示，换行符替换为反斜杠（'\'）<br />-r, -resolve 使用系统的DNS解析器来打印主机地址</p>
<p><span style="background-color: #c0c0c0;">对象：</span><br />所有对象名称都支持前缀简写，例如address可以简写为addr或者a<br />address 设备的协议（IPv4或者IPv6）地址<br />addrlabel 协议地址标签<br />l2tp 第二层隧道协议，在IP协议上建立以太网隧道<br />link 网络设备，其add子命令用于添加虚拟设备（virtual link）<br />maddress 多播地址<br />monitor 监听网络连接信息<br />mroute 多播路有缓存条目<br />mrule 多播路有策略数据库中的规则<br />neighbour 管理ARP和NDISC缓存条目<br />netns 管理网络名字空间<br />route 路由表条目<br />rule 路由策略数据库中的规则<br />tunnel IP协议隧道<br />tuntap  TUN/TAP设备，TUN/TAP分别是模拟网络层/链路层的内核虚拟设备<br />xfrm 管理IPSec策略</p>
<p><span style="background-color: #c0c0c0;">举例：</span></p>
<pre class="crayon-plain-tag"># 给网络接口eth0分配一个IP地址，设置会在系统重启后丢失
ip addr add 192.168.0.89 dev eth0
# 显示IP地址、MAC地址等信息
ip addr show
# 仅仅显示特定网络接口的信息
ip addr show dummy0

# 移除IP地址
ip addr del 192.168.0.89/24 dev eth0
# 禁用网络接口
ip link set eth1 down
# 启用网络接口
ip link set eth1 up

# 显示所有设备
ip link ls
# 显示指定类型的设备
ip link show type bridge|veth|tap
# 显示详细信息，例如设备类型
ip -d link show
# 6: kube-ipvs0: &lt;BROADCAST,NOARP&gt; mtu 1500 qdisc noop state DOWN mode DEFAULT group default 
#  link/ether 2e:be:57:1f:f0:d5 brd ff:ff:ff:ff:ff:ff promiscuity 0 
#  dummy addrgenmode eui64 
#  类型
# 10: cali11f1d8af43c@if4: &lt;BROADCAST,MULTICAST,UP,LOWER_UP&gt; mtu 1440 qdisc noqueue state UP mode DEFAULT group default 
#  link/ether ee:ee:ee:ee:ee:ee brd ff:ff:ff:ff:ff:ff link-netnsid 3 promiscuity 0 
#  veth addrgenmode eui64 
#  类型

# 添加一个网桥
ip link add br0 type bridge
# 删除一个网桥
ip link delete br0 type bridge

# 添加一个macvtap设备，其lower device为eth0
ip link add link eth0 name macvtap0 type macvtap
# 为macvtap设置MAC地址并启动
ip link set macvtap0 address 1a:46:0b:ca:bc:7b up

# 添加一个TAP设备，归属于root用户
ip tuntap add tap0 mode tap user root

# 添加一个veth对，同属默认网络命名空间
ip link add veth0 type veth peer name veth1

# 设置tap0的master设备为br0，即把tap0束缚（enslave）到br0。用于把一个虚拟/真实设备连接到网桥
# 被连接到网桥的设备，其状态必须为up
ip link set tap0 master br0
# 释放tap0的被束缚状态。用于解除一个虚拟/真实网络设备到网桥的连接
ip link set tap0 nomaster

# 显示路由表
ip route show
# 显示指定路由表的内容
ip route list table 133

# 添加静态路由
ip route add 10.10.20.0/24 via 192.168.0.1 dev eth0  # via网关的间接路由
ip route add 10.0.0.0/8 dev br0                      # 直接路由
# 移除静态路由
p route del 10.10.20.0/24

# 添加默认路由（网关）
ip route add default via 192.168.0.1

# 添加网络命名空间
ip netns add test
# 将设备移动到网络命名空间
ip link set veth1 netns test
# 在网络命名空间下执行命令
ip netns exec test ip link show veth1

# 添加策略路由，具有123标记的封包，查找100表
ip rule add fwmark 123 lookup 100

# 列出策略路由
ip -f inet rule list
# 0:      from all lookup local 
# 具有0x539的封包，查找133表
# 32765:  from all fwmark 0x539 lookup 133 
# 32766:  from all lookup main 
# 32767:  from all lookup default</pre>
</td>
</tr>
<tr>
<td class="blog_h2">ip route</td>
<td>
<p>管理路由表
<p><span style="background-color: #c0c0c0;">格式：</span></p>
<pre class="crayon-plain-tag"># 列出或刷新选择器匹配的路由
ip route { list | flush } SELECTOR

# 保存和恢复路由
ip route save SELECTOR
ip route restore

# 查询路由
ip route get ADDRESS [ from ADDRESS iif STRING  ] [ oif STRING ] [ tos TOS ]

# 增删改换路由
ip route { add | del | change | append | replace } ROUTE


# SELECTOR语法
[ root PREFIX ] [ match PREFIX ] [ exact PREFIX ] [ table TABLE_ID ] [ proto RTPROTO ] [ type TYPE ] [ scope SCOPE ]

# ROUTE语法
ROUTE = [ TYPE ] PREFIX [ tos TOS ] [ table TABLE_ID ] [ proto RTPROTO ] [ scope SCOPE ] [ metric METRIC ]
        [ [ via ADDRESS ] [ dev STRING ] [ weight NUMBER ] [ onlink | pervasive ] OPTIONS FLAGS [ nexthop NH ] ... ]
# 其中TYPE包括
[ unicast | local | broadcast | multicast | throw | unreachable | prohibit | blackhole | nat ]</pre>
<p><span style="background-color: #c0c0c0;">路由类型：</span></p>
<ol>
<li>unicast，此路由条目描述到达PREFIX所覆盖的目的地址的路径</li>
<li>unreachable，PREFIX覆盖的网络不可达，发送ICMP消息host unreachable</li>
<li>blackhole，PREFIX覆盖的网络不可达，静默的丢弃</li>
<li>prohibit，PREFIX覆盖的网络不可达，发送ICMP消息communication administratively prohibited</li>
<li>local，目的地指向本机，包被环回并本地递送</li>
<li>broadcast，目的地是广播地址，包作为link broadcasts发送</li>
</ol>
<p><span style="background-color: #c0c0c0;">示例：</span></p>
<pre class="crayon-plain-tag"># 添加一个local类型的路由到100表中，此路由让一切路由都走lo网卡
ip route add local 0.0.0.0/0 dev lo table 100 </pre>
</td>
</tr>
<tr>
<td>ip rule</td>
<td>
<p>管理路由策略数据库。典型的路由算法仅仅根据目的地址来决定如何路由，如果需要更加高级的路由策略 —— 例如基于源地址、IP协议、传输协议端口甚至协议载荷，则需要使用该命令。这种高级路由叫做policy routing
<p>为了实现策略路由，原先的基于目的地址的、以最长匹配规则排序的路由表，被替换为路由策略数据库（RPDB）。通过执行数据库中的一些规则，来决定如何路由</p>
<p>每个策略路由规则由选择器SELECTOR和动作断言ACTION PREDICTATE构成。<span style="background-color: #c0c0c0;">RPDB按照规则的优先级降序（数字越小优先级越高）的被扫描</span>，每个规则的SELECTOR针对封包的{source address, destination address, incoming interface, tos, fwmark}进行匹配判断，如果匹配成功，则ACTION被执行。</p>
<p>ACTION PREDICTATE可以<span style="background-color: #c0c0c0;">返回成功</span>，这种情况下它要么给出路由目的地址，要么给出失败提示，且RPDB查找终止。否则（不成功）则继续匹配下一条RPDB规则</p>
<p>在内核启动时，它会初始化具有三条规则的RPDB：</p>
<ol>
<li>优先级0；选择器：匹配任何封包；动作：查找路由表local（ID 255）。local是一个特殊的路由表，包含本地地址、广播地址的高优先级的控制路由。此规则不能删除或修改</li>
<li>优先级RPDB；选择器：匹配任何封包；动作：查找路由表main（ID 254）。main表是一个普通的路由表，包含所有非策略性路由规则。此表可以被删除或覆盖</li>
<li>优先级32767；选择器：匹配任何封包；动作：查找路由表default（ID 253）。default表是空白的，用于没有匹配到的封包的后处理</li>
</ol>
<p>每个RPDB条目都包含一些额外的属性，例如每个规则都有向路由表的指针。NAT和masquerading规则包含一个属性，用于选择转换/掩码的IP地址。</p>
<p>RPDB包含以下几种类型的规则：</p>
<ol>
<li>unicast，返回规则所引用的路由表中的一个条目</li>
<li>blackhole，安静的丢弃封包</li>
<li>unreachable，生成一个Network is unreachable错误</li>
<li>prohibit，生成一个Communication is administratively prohibited错误</li>
<li>nat，将源地址转换为其它值</li>
</ol>
<p><span style="background-color: #c0c0c0;">格式：</span></p>
<pre class="crayon-plain-tag">ip [ OPTIONS ] rule  { COMMAND | help }
ip rule  [ list | add | del | flush ] SELECTOR ACTION</pre>
<p>其中SELECTOR可以是（以下项中的多个）：</p>
<ol>
<li>from PREFIX，匹配源地址的前缀</li>
<li>to PREFIX，匹配目的地址的前缀</li>
<li>tos TOS，匹配Type of Service</li>
<li>fwmark FWMARK[/MASK]，匹配防火墙标记，也就是iptables的MARK</li>
<li>iif STRING，匹配封包的来源网卡，这意味着你可以为本地发起的、转发的封包设置完全独立的路由规则</li>
<li>oif STRING，匹配封包的出口网卡，仅仅对来自本地的、绑定到特定设备的套接字有效</li>
<li>pref NUMBER，优先级，同义词priority、order</li>
</ol>
<p>其中ACTION可以是：</p>
<ol>
<li>table TABLE_ID，表ID可以是local | main | default | NUMBER，如果匹配规则，则到哪个表中查找路由</li>
<li>nat ADDRESS</li>
<li>prohibit | reject | unreachable</li>
<li>realms [SRCREALM/]DSTREALM ]</li>
</ol>
<p>ACTION后面可以跟着SUPPRESSOR：[ suppress_prefixlength NUMBER ] [ suppress_ifgroup GROUP ]</p>
<p><span style="background-color: #c0c0c0;">示例：</span></p>
<pre class="crayon-plain-tag"># 添加一个规则，匹配标记为1的封包，到100表中查找
ip rule add fwmark 1 lookup 100</pre>
</td>
</tr>
<tr>
<td class="blog_h2">bridge</td>
<td>
<p>显示/操控网桥地址和设备
<p><span style="background-color: #c0c0c0;">举例：</span></p>
<pre class="crayon-plain-tag"># 显示所有连接到网桥的网络接口（端口，Port）的信息
bridge link 
bridge link show dev eth0

# 在端口上设置网桥相关的属性
bridge link set
  dev eth0           # 针对哪个端口
  cost COST          # STP路径成本
  priority PRIO      # STP端口优先级
  state STATE        # 端口状态：0禁用 1STP监听 2 STP学习 3STP转发 4STP阻塞
  root_block on|off  # 端口是否为STP的根端口
  hairpin on|off     # 流量是否可以从接收它的端口发回去，默认否，流量不会从接收端口转发回去



# FDB包含了网桥每个端口（连接）上已知的MAC地址
# 添加FDB项
bridge fdb add
  LLADDR             # MAC地址
  dev DEV            # MAC地址关联的网络接口
  dst IPADDR         # MAC地址所在的VXLAN隧道端点(VTEP)的IP地址
  vni VNI            # VXLAN VNI网络标识符（VXLAN段ID），连接到VTEP是需要
  port PORT          # 远程VTEP的UDP端口
  via DEVICE         # 为了将数据报送达远程VTEP，需要通过的设备

  self               # 关联到软件FDB（默认）
  embedded           # 关联到offloaded FDB
  router             # 关联到路由器

# 显式FDB项
bridge fdb show



# MDB包含端口上已知的IP多播组地址
# 添加MDB项
bridge mdb add      
  dev DEV            # 组播地址关联的接口
  port PORT          # 连接到此端口上的link是多播组成员
  grp GROUP          # 组播地址</pre>
</td>
</tr>
<tr>
<td>brctl</td>
<td>
<p>操控网桥
<p><span style="background-color: #c0c0c0;">格式：</span><pre class="crayon-plain-tag">brctl [commands]</pre></p>
<p><span style="background-color: #c0c0c0;">子命令：</span></p>
<pre class="crayon-plain-tag">addbr     	    &lt;bridge&gt;  # 新建一个网桥
delbr     	    &lt;bridge&gt;  # 删除一个网桥
addif     	    &lt;bridge&gt; &lt;device&gt; # 将一个网卡接入网桥
delif     	    &lt;bridge&gt; &lt;device&gt; # 从网桥中删除一个设备
setbridgeprio	    &lt;bridge&gt; &lt;prio&gt; # 设置网桥优先级
setfd     	    &lt;bridge&gt; &lt;time&gt; # 设置转发延迟
setmaxage 	    &lt;bridge&gt; &lt;time&gt; # 设置报文最大生命周期
show      	    [ &lt;bridge&gt; ] # 显示网桥列表
showmacs  	    &lt;bridge&gt; # 显示MAC列表
showstp   	    &lt;bridge&gt; # 显示网桥的STP信息
stp       	    &lt;bridge&gt; {on|off} # 开关STP</pre>
<p><span style="background-color: #c0c0c0;">示例：</span> </p>
<pre class="crayon-plain-tag"># 停止eth0
sudo ip link set eth0 down

# 添加eth0到libvirt网桥，使用桌面系统时要禁用NM对eth0的管理
sudo brctl addif virbr0 eth0

# 为网桥添加一个新IP，此IP原来属于eth0
sudo ip addr add 10.0.1.1/24 dev virbr0

# 启动eth0
sudo ip link set eth0 up</pre>
</td>
</tr>
<tr>
<td class="blog_h2">iwconfig</td>
<td>
<p>支持与网线网络接口相关的配置
</td>
</tr>
<tr>
<td class="blog_h2">iwlist</td>
<td>
<p>获取无线网络的详细信息</p>
<p><span style="background-color: #c0c0c0;">举例：</span></p>
<pre class="crayon-plain-tag">iwlist wlan1 scan</pre>
</td>
</tr>
<tr>
<td class="blog_h2">wpa_cli</td>
<td>
<p>WPA命令行客户端
<p>举例：</p>
<pre class="crayon-plain-tag"># 查看当前无线网络的详细信息
sudo wpa_cli status
# Selected interface 'wlan1'
# bssid=e8:ed:f3:fc:b3:bf
# ssid=dangdang-ydgw
# id=0
# mode=station
# pairwise_cipher=CCMP
# group_cipher=CCMP
# key_mgmt=WPA2-PSK
# wpa_state=COMPLETED</pre>
</td>
</tr>
<tr>
<td class="blog_h2">ifup</td>
<td>
<p>激活一个网络接口。该命令与下面两个命令与/etc/network/interfaces文件一起工作
</td>
</tr>
<tr>
<td class="blog_h2">ifdown</td>
<td>
<p>停用一个网络接口</p>
</td>
</tr>
<tr>
<td class="blog_h2">ifquery </td>
<td>
<p>解析一个网络接口的配置</p>
</td>
</tr>
<tr>
<td class="blog_h2">iptables</td>
<td>参考<a href="/iptables">重温Iptables</a></td>
</tr>
<tr>
<td class="blog_h2">ipset</td>
<td>
<p>IP Sets的管理工具</p>
<p>在iptables中，如果我们去匹配多个无规律的IP地址的话就会写入多条iptables的规则，当如果需要匹配几百甚至上千个IP地址的话，那么性能就会受到严重的影响。IP Sets可以解决这个问题</p>
<p>IP Sets是内核框架，可以被ipset命令管理。根据类型的不同，一个IP Set可以存放多个IP地址、网络号、TCP/UDP端口、MAC地址、网络接口名，以及所有这些的组合。当用一个条目来比对，看是否匹配IP Set时，速度极快</p>
<p>应用场景：</p>
<ol>
<li>存储一个IP地址集合，并且和一个Iptables规则进行匹配</li>
<li>动态的基于IP地址、端口更新iptables规则，而不影响性能</li>
<li>表述一个复杂的规则集，然后在一个iptables规则中引用</li>
</ol>
<p><span style="background-color: #c0c0c0;"><strong>子命令：</strong></span></p>
<pre class="crayon-plain-tag"># 创建具有指定名称、指定类型的IPSet
# 其中TYPENAME格式为：method:datatype[,datatype[,datatype]]
ipset create SETNAME TYPENAME [ CREATE-OPTIONS ]
# 创建一个名为test的hash:ip类型（以哈希形式存储的IP）的IPSet，新条目的默认超时300s（超时后自动移除）。
ipset create test hash:ip timeout 300
# 创建hash:net类型的IPSet
ipset create foo hash:net
# 创建hash:ip,port类型的IPSet
ipset create bar hash:ip,port


# 添加一个条目到IPSet
ipset add SETNAME ADD-ENTRY [ ADD-OPTIONS ]
# 向test中添加条目192.168.0.1，超时60s
ipset add test 192.168.0.1 timeout 60
# 添加到hash:net类型的IPSet
ipset add foo 192.168.0.0/24
# 添加到hash:ip,port类型的IPSet
ipset add foo 192.168.1.0/24,80-82
ipset add foo 192.168.1.1,udp:53
ipset add foo 192.168.1.1,vrrp:0
ipset test foo 192.168.1.1,80


# 从IPSet中删除一个条目
ipset del SETNAME DEL-ENTRY [ DEL-OPTIONS ]
# 测试一个条目是否属于IPSet
ipset test SETNAME TEST-ENTRY [ TEST-OPTIONS ]
# 删除指定的IPSet，如果不指定名称，删除所有IPSet
ipset destroy [ SETNAME ]
# 列出指定的IPSet的头信息和条目列表
ipset list [ SETNAME ]
# 保存IPSet到文件
ipset save [ SETNAME ]
# 从文件恢复IPSet
ipset restore
# 刷空IPSet的条目
ipset flush [ SETNAME ]
# 重命名IPSet
ipset rename SETNAME-FROM SETNAME-TO
# 交换IPSet的内容
ipset swap SETNAME-FROM SETNAME-TO</pre>
<p><strong><span style="background-color: #c0c0c0;">CREATE/ADD选项</span></strong></p>
<p style="padding-left: 30px;">timeout 指定条目的超时<br />nomatch 对于hash:net类型，如果添加新条目是指定此选项，进行匹配时就好像该条目并没有添加一样<br />comment  指定注释</p>
<p><strong><span style="background-color: #c0c0c0;">IPSet类型：</span></strong></p>
<p style="padding-left: 30px;">bitmap:ip  使用一段内存存储IPv4主机或网络地址，最多存储65536个条目<br />bitmap:ip,mac  存储IP+MAC地址对<br />bitmap:port 存储端口<br />hash:ip 使用哈希表存储主机地址或网络地址，0 IP不能存储进来<br />hash:net 存储不同大小的网络地址<br />hash:net,net 存储一对网络地址<br />hash:ip,port 存储IP地址和端口</p>
<p><strong>在iptables中使用：</strong></p>
<p>你可以使用匹配扩展set来引用IPSet：</p>
<pre class="crayon-plain-tag">ipset create bannedip hash:ip
# 如果封包的源地址属于Ipset bannedip，则丢弃封包
iptables -I INPUT -m set --match-set bannedip src -j DROP
ipset add bannedip 4.5.6.7
ipset add bannedip 1.2.3.4</pre>
</td>
</tr>
<tr>
<td class="blog_h2">iptables-save</td>
<td>
<p>导出iptables配置到标准输出
</td>
</tr>
<tr>
<td class="blog_h2">iptables-restore</td>
<td>
<p>从文件恢复iptables配置</p>
</td>
</tr>
<tr>
<td class="blog_h2">conntrack</td>
<td>
<p>此命令提供netfilter的连接跟踪系统的全功能用户空间接口，代替/proc/net/ip_conntrack的功能。使用该命令你可以检索、列出、探查、维护Linux内核的连接跟踪子系统，例如：</p>
<ol>
<li>Dump出完整或过滤后的连接列表</li>
<li>从状态表中删除连接</li>
<li>添加新的连接</li>
<li>监控连接跟踪事件</li>
</ol>
<p>连接跟踪系统在内部，维护两个表：</p>
<ol>
<li>conntrack：默认表，包含当前被追踪的、经过本系统的连接。除非你使用iptables的<pre class="crayon-plain-tag">NOTRACK</pre>目标，否则所有连接都在其中</li>
<li>expect：期望表，连接跟踪期望（Connection tracking expectations ）用于“expect“ RELATED连接到一个现有的连接。Expectation主要被connection tracking helpers（也叫Application level gateways, ALGs）使用，处理FTP、SIP、H.323这样的复杂协议</li>
</ol>
<p><span style="background-color: #c0c0c0;">格式：</span></p>
<pre class="crayon-plain-tag"># 列出
conntrack -L [table] [options] [-z]
# 检索
conntrack -G [table] parameters
# 删除
conntrack -D [table] parameters
# 创建
conntrack -I [table] parameters
# 更新
conntrack -U [table] parameters
# 显示实时事件
conntrack -E [table] [options]
# 刷出整个表
conntrack -F [table]
# 显示计数器
conntrack -C [table]
# 显示内核连接跟踪系统的统计信息
conntrack -S</pre>
<p><span style="background-color: #c0c0c0;">一般选项：</span></p>
<p>-z, --zero  读取后自动清零计数器，仅仅和<pre class="crayon-plain-tag">-L</pre>联用<br />-o, --output [extended,xml,timestamp,id,ktimestamp]  以特定格式显示输出<br />-e, --event-mask [ALL|NEW|UPDATES|DESTROY][,...]过滤事件类型，和<pre class="crayon-plain-tag">-E</pre>联用<br />-b, --buffer-size 设置Netlink套接字缓冲大小</p>
<p><span style="background-color: #c0c0c0;">过滤器参数：</span></p>
<p>-s, --orig-src IP_ADDRESS 最初通信方向的源地址<br />-d, --orig-dst IP_ADDRESS 最初通信方向的目的地址<br />-r, --reply-src IP_ADDRESS 应答方向的源地址<br />-q, --reply-dst IP_ADDRESS 应答方向的目的地址 <br />-p, --proto PROTO L4协议类型，例如TCP UDP<br />-f, --family PROTO  L3协议族ipv4, ipv6，仅仅和<pre class="crayon-plain-tag">-L</pre>联用。默认IPv4<br />-t, --timeout TIMEOUT 指定超时<br />-m, --mark MARK[/MASK] 连接跟踪标记ctmark<br />-c, --secmark SECMARK 连接跟踪selinux安全标记<br />-u, --status [ASSURED|SEEN_REPLY|FIXED_TIMEOUT|EXPECTED|UNSET][,...]  连接跟踪状态<br />-n, --src-nat 仅仅匹配SNAT连接<br />-g, --dst-nat 仅仅匹配DNAT连接<br />-j, --any-nat 匹配任何NAT连接<br />-w, --zone 根据连接跟踪Zone过滤，参考iptables的CT目标<br />--tuple-src 指定expectation的源地址元组<br />--tuple-dst IP_ADDRESS 指定expectation的目的地址元组<br />--mask-src IP_ADDRESS   指定expectation的源地址掩码<br />--mask-dst IP_ADDRESS 指定expectation的目的地址掩码</p>
<p><span style="background-color: #c0c0c0;">TCP过滤参数：</span></p>
<p>--sport, --orig-port-src  最初通信方向的源端口<br />--dport, --orig-port-dst 最初通信方向的目的端口<br />--reply-port-src 应答方向的源端口<br />--reply-port-dst  应答方向的目的端口<br />--state [NONE | SYN_SENT | SYN_RECV | ESTABLISHED | FIN_WAIT | CLOSE_WAIT | LAST_ACK | TIME_WAIT | CLOSE | LISTEN]  TCP状态</p>
<p><span style="background-color: #c0c0c0;">UDP过滤参数：</span></p>
<p>--sport, --orig-port-src 最初通信方向的源端口<br />--dport, --orig-port-dst 最初通信方向的目的端口<br />--reply-port-src 应答方向的源端口<br />--reply-port-dst 应答方向的目的端口</p>
<p><span style="background-color: #c0c0c0;">ICMP过滤参数：</span></p>
<p>--icmp-type TYPE  ICMP类型<br />--icmp-code CODE ICMP代码<br />--icmp-id ID  ICMP ID</p>
<p><span style="background-color: #c0c0c0;">示例：</span></p>
<pre class="crayon-plain-tag"># 以 /proc/net/ip_conntrack 格式显示连接跟踪表
conntrack -L
conntrack -L -o extended
conntrack -L -o xml

# 仅仅列出IPv6
conntrack -L -f ipv6 -o extended

# 列出SNAT连接
conntrack -L --src-nat

# 列出事件，显示时间戳
conntrack -E -o timestamp
# 注意，输出中包含ASSURED字样的，表示此连接不会被消除，即使达到最大可跟踪连接数量限制后

# 删除所有源地址1.2.3.4的连接
conntrack -D -s 1.2.3.4

# 标记所有源地址1.2.3.4的连接
conntrack -U -s 1.2.3.4 -m 1 </pre>
</td>
</tr>
<tr>
<td class="blog_h2">pen</td>
<td>
<p>负载均衡器，支持基于TCP的协议的负载均衡，例如HTTP、SMTP
<p>此LB能够跟踪每个请求，并将其转发给客户端上一次访问的服务器（会话绑定），这种LB算法比RR更加高级</p>
<p><span style="background-color: #c0c0c0;">格式：</span></p>
<pre class="crayon-plain-tag">pen options [host:]port
  h1[:p1[:maxc1[:hard1[:weight1[:prio1]]]]] 
  [h2[:p2[:maxc2[:hard2[:weight2[:prio2]]]]]] ...</pre>
<p><span style="background-color: #c0c0c0;">选项：</span></p>
<p>-C 指定控制端口，此端口接收发送给LB的命令<br />-F 指定配置文件<br />-H 为HTTP请求添加X-Forwarded-For头<br />-b 将不响应服务器列入黑名单的持续时间，单位秒<br />-T 会话跟踪持续时间，单位秒<br />-S 最大服务器数<br />-C 最大客户端数<br />-e host:port 如果所有服务器不可用，使用该紧急服务器<br />-f 在前台运行<br />-n 使用非阻塞IO<br />maxc1 服务器1的最大客户端数量<br />hard1  服务器1的最大客户端数量（硬限制）<br />weight1 此服务器的权重，用于基于权重的负载均衡算法<br />prio1 此服务器的优先级，用于基于优先级的负载均衡算法</p>
<p><span style="background-color: #c0c0c0;">示例：</span></p>
<pre class="crayon-plain-tag"># 监听所有网络接口的18000，转发给目标主机的8000，在前台运行，启动调试日志
pen -fd 0.0.0.0:18000 172.27.170.143:8000</pre>
</td>
</tr>
<tr>
<td class="blog_h2">snmp</td>
<td>
<p>snmp包提供了若干命令，它们的<span style="background-color: #c0c0c0;">格式</span>如下：
<pre class="crayon-plain-tag">snmp_command 
  -u bootstrap -l authPriv -a MD5 
  -x DES -A temp_password -X temp_password 
  
  remote_host snmp_sub_command_or_options</pre>
<p>它们<span style="background-color: #c0c0c0;">公共的选项</span>如下：</p>
<p>-v 指定需要使用的SNMP协议的版本<br />-c 指定SNMPv1、v2使用的团体名<br />-u 指定用于身份验证的用户名<br />-l 指定连接的安全性级别：noAuthNoPriv 不验证不加密；authNoPriv 验证不加密；authPriv 验证加密<br />-a 身份验证协议：MD5、SHA<br />-x 数据加密协议：DES、AES<br />-A 身份验证短语<br />-X 数据加密短语</p>
<p><span style="background-color: #c0c0c0;">命令举例：</span></p>
<pre class="crayon-plain-tag">#执行SNMP get操作，显示系统信息
snmpget 
  -u bootstrap -l authPriv -a MD5 
  -x DES -A password -X password 
  192.168.0.90 1.3.6.1.2.1.1.1.0</pre>
</td>
</tr>
<tr>
<td class="blog_h2">justniffer</td>
<td>
<p>这是一个TCP包嗅探器，它能够重建TCP流，并且对请求/应答风格的协议做了优化。justniffer还能重建HTTP内容并保存到磁盘
<p><span style="background-color: #c0c0c0;">安装：</span></p>
<pre class="crayon-plain-tag">sudo add-apt-repository ppa:oreste-notelli/ppa 
sudo apt-get update
sudo apt-get install justniffer</pre>
<p><span style="background-color: #c0c0c0;">格式： </span></p>
<pre class="crayon-plain-tag">justniffer 
  [ [-i interface] or [-f &lt;tcpdump file&gt;] ]  [-F]
  [-p &lt;packet filter&gt;]  [-u or -x] 
  [ [-r] or [-l &lt;log format&gt;] or [-a &lt;log format&gt;]  ] 
  [-c &lt;config file&gt;]  [-e &lt;external program&gt;]  [-U &lt;user&gt; ]   
  [-n &lt;not-found&gt; ]  [-s &lt;max concurrent tcp streams&gt; ]  
  [-d &lt;max concurrent IP fragments&gt; ]</pre>
<p><span style="background-color: #c0c0c0;">选项：</span></p>
<p>-i 需要嗅探的接口名称，例如eth0<br />-f 从文件中读取tcpdump，用于离线分析。目标文件必须是pcap文件（tcpdump、wireshark等产生）。jusstniffer需要完整的dump，而默认的tcpdump只会收集每个包的前64字节，因此你需要<pre class="crayon-plain-tag">tcpdump -i eth0 -s 0 -w file.cap</pre> <br />-F 强制从文件读取tcpdump，即使dump不是完整的<br />-p 包过滤器，pcap filter格式，例如<pre class="crayon-plain-tag">"tcp port 23"</pre> 、<pre class="crayon-plain-tag">"host 8.8.8.8 and tcp port 80"</pre> <br />-l 日志格式，你可以使用很多<pre class="crayon-plain-tag">%</pre> 开头的占位符。如果不指定使用CLF（Common Log Format，大部分Web服务器的日志格式）<br />-a 附加日志格式到CLF后面<br />-r 显示原始流，等价于<pre class="crayon-plain-tag">-l %request%response</pre> <br />-s 最大并发的TCP流数量<br />-d 最大并发的IP分片数量<br />-x 使用HEX编码不可打印字符<br />-e 对于请求/应答模式的协议，通过管道，对每个请求/应答调用外部命令<br />-c 从文件读取配置</p>
<p><span style="background-color: #c0c0c0;">日志格式：</span></p>
<p>%close.originator([not applicable string])<br />连接关闭方：client,server,timedout，如果不可用，显示入参内的字符串（不指定使用短横线）<br />%close.time<br />从最后一个响应到关闭，消耗的时间<br />%close.timestamp[2]([format])<br />被关闭时间戳（close timestamp）替换，可以指定时间格式，如果有后缀2，则显示seconds.microseconds格式<br />%connection<br />连接持续性指示符，unique请求/应答是TCP连接中唯一的；start是第一个；last是最后一个；continue是中间的 <br />%connection.time([not applicable string])<br />从连接建立到现在，流逝的时间<br />%connection.timestamp[2]([format])<br />被连接时间戳（connection timestamp）替换，可以指定时间格式<br />%dest.ip<br />被目标地址替换<br />%dest.port<br />被目标端口替换<br />%source.ip<br />被源地址替换<br />%source.port<br />被源端口替换<br />%request<br />完整的请求，可能多行，可能包含不可打印字符<br />%request.timestamp[2]([format])<br />被请求时间戳替换<br />%request.size<br />请求的大小，包含请求头<br />%request.line<br />用于HTTP，请求行，例如"GET /index.html HTTP/1.1"<br />%request.method<br />用于HTTP，请求方法，例如POST<br />%request.url<br />用于HTTP，请求地址<br />%request.protocol<br />请求的协议<br />%request.header<br />请求头，多行。可以使用%request.header.*访问单个HTTP请求头<br />%response<br />完整的响应，可能多行，可能包含不可打印字符<br />%response.size<br />响应的大小，包含响应头<br />%response.timestamp[2]([format])<br />响应时间戳<br />%response.line<br />用于HTTP，响应行<br />%response.protocol<br />响应协议<br />%response.code<br />用于HTTP，响应状态码<br />%response.message<br />用于HTTP，响应状态码的字符串表示<br />%response.header<br />响应头，多行。可以使用%response.header.*访问单个HTTP响应头<br />%session.requests<br />被TCP会话的请求序列号替换<br />%session.time<br />被TCP会话lifespan替换<br />%tab<br />打印一个TAB<br />%streams<br />打印当前TCP流的数量<br />%newline<br />打印换行符<br />%% <br />打印 %</p>
<p><span style="background-color: #c0c0c0;">时间戳格式：</span><br />%Y   年<br />%m  月，01-12<br />%d   日，01-31<br />%H   时，00-23<br />%M  分，00-59<br />%S   秒，00-60<br />%F   等价于 %Y-%m-%d<br /> %T  等价于 %H:%M:%S</p>
<p><span style="background-color: #c0c0c0;">举例：</span></p>
<pre class="crayon-plain-tag"># 嗅探针对repository.sonatype.org的HTTP请求，打印请求URL和响应状态码
sudo justniffer -i wlan1 -p "host repository.sonatype.org and port 80"
    -l "%connection.timestamp(%F %T) %source.ip:%source.port %request.url %response.code"</pre>
</td>
</tr>
<tr>
<td class="blog_h2">setserial</td>
<td>
<p>获取或者设置Linux的串口信息。<br />在正常的初始化过程中，仅仅1-4号串口基于默认I/O端口和IRQ值初始化，要初始化额外的串口或者把1-4号串口修改为非标准配置，可以使用该程序
<p><span style="background-color: #c0c0c0;">格式：</span><br />setserial [ -abqvVWz ] device [ parameter1 [ arg ] ] ...<br />setserial -g [ -abGv ] device1 ...</p>
<p><span style="background-color: #c0c0c0;">选项：</span><br />device 需要操作的设备，例如/dev/ttyS0, /dev/ttyS1, /dev/ttyS2, /dev/ttyS3<br />-a  获取串口设备信息时，打印所有可用信息<br />-b 获取串口设备信息时，打印概要配置信息<br />-g 获取串行端口的配置信息<br />-q 打印较少的信息<br />-v 打印冗长信息，输出额外的状态信息<br />-z 在设置串口标志位前置零</p>
</td>
</tr>
<tr>
<td class="blog_h2">ethtool</td>
<td>
<p>查看以太网接口的信息，例如连接速度。示例：</p>
<p><pre class="crayon-plain-tag">ethtool eth0
ethtool eth0 | grep Speed </pre>
</td>
</tr>
</tbody>
</table>
<div class="blog_h1"><span class="graybg">系统管理命令</span></div>
<table class="fixed-word-wrap full-width" style="width: 100%;" border="1" cellspacing="0" cellpadding="5">
<thead>
<tr>
<td style="width: 100px; text-align: center;">命令</td>
<td style="text-align: center;">说明 </td>
</tr>
</thead>
<tbody>
<tr>
<td class="blog_h2">users</td>
<td>显示所有的登录的用户</td>
</tr>
<tr>
<td class="blog_h2">last</td>
<td>显示最近登陆的用户列表</td>
</tr>
<tr>
<td class="blog_h2">groups</td>
<td>列出用户（如果不指定用户则默认当前用户）和他所属于的组，例如<pre class="crayon-plain-tag">groups alex</pre> </td>
</tr>
<tr>
<td class="blog_h2">id</td>
<td>
<p>显示用户标识符信息，举例：</p>
<pre class="crayon-plain-tag">id alex
#输出，gid显示了用户的主要组（Primary group），默认主要组和用户名相同
#uid=1000(alex) gid=1000(alex) groups=1000(alex),4(adm),27(sudo)</pre>
</td>
</tr>
<tr>
<td class="blog_h2">useradd</td>
<td>
<p>创建一个新用户或更新默认新用户信息
<p><span style="background-color: #c0c0c0;">格式：</span><br />useradd [options] LOGIN<br />useradd -D<br />useradd -D [options]</p>
<p><span style="background-color: #c0c0c0;">选项：</span></p>
<p>-b 指定基目录，基目录/账户名就是家目录，基目录默认/home<br />-c  password文件中的注释字段<br />-d 指定家目录<br />-e 账户被禁用的日期，格式YYYY-MM-DD<br />-f 密码过期后，账户被彻底禁用之前的天数。0 表示立即禁用，-1 表示禁用这个功能<br />-g 用户初始登陆组（主要组）的组名或ID。组名必须已经存在。组号码必须指代已经存在的组。如果不指定该参数，默认会创建一个和用户名字一样的组，该行为受/etc/login.defs中USERGROUPS_ENAB参数的控制：该参数为no时，新用户被添加到<pre class="crayon-plain-tag">/etc/default/useradd</pre> 中GROUP变量指定的组<br />-G 用户所属附属组，逗号分隔<br />-M 不创建家目录<br />-N 不创建同名组，而是加入到-g指定的组或者使用/etc/default/useradd中的GROUP变量<br />-p 加密过的密码<br />-r 创建一个系统账户。不在/etc/shadow中保存密码年龄信息、不创建家目录，UID在SYS_UID_MIN到SYS_UID_MAX之间选择<br />-s 用户使用的登录Shell<br />-u 基于数字的用户ID，必须非负整数，一般要求唯一<br />-U, --user-group 创建与用户同名的群组</p>
</td>
</tr>
<tr>
<td class="blog_h2">userdel</td>
<td>
<p>删除用户</p>
<p><span style="background-color: #c0c0c0;">选项：</span><br />-f  强制删除，甚至在用户当前正在登录的场景下<br />-r  删除用户的家目录及其中的文件</p>
</td>
</tr>
<tr>
<td class="blog_h2">usermod</td>
<td>
<p>修改用户帐号。 可以修改密码、 组身份、 截止日期等。修改后的用户可能需要<span style="background-color: #c0c0c0;">重新登录</span>才能生效</p>
<p><span style="background-color: #c0c0c0;">选项：</span><br />-a  添加用户到额外的组中，仅和-G联用<br />-c password文件中的注释字段<br />-d 为用户指定新的家目录<br />-e 账户被禁用的日期，格式YYYY-MM-DD<br />-f 密码过期后，账户被彻底禁用之前的天数。0 表示立即禁用，-1 表示禁用这个功能<br />-G 用户所属附属组，逗号分隔<br />-l  修改用户的登录名<br />-L  锁定一个用户的密码<br />-U 解锁一个用户的密码<br />-m  移动家目录到新的位置</p>
<p><span style="background-color: #c0c0c0;"><span style="background-color: #c0c0c0;">示例：</span></span></p>
<pre class="crayon-plain-tag"># 把alex附加到ssl-cert组
sudo usermod -a -G ssl-cert alex</pre>
</td>
</tr>
<tr>
<td class="blog_h2">gpasswd</td>
<td>
<p>管理配置文件/etc/group和/etc/gshadow<br /><span style="background-color: #c0c0c0;"><span style="background-color: #c0c0c0;">示例：</span></span>
<pre class="crayon-plain-tag"># 从ssl-cert组中删除alex
sudo gpasswd -d alex ssl-cert</pre>
</td>
</tr>
<tr>
<td class="blog_h2">groupmod</td>
<td>修改指定组</td>
</tr>
<tr>
<td class="blog_h2">newgrp</td>
<td>修改当前用户的GID</td>
</tr>
<tr>
<td class="blog_h2">passwd</td>
<td>
<p>设置、修改、或者删除用户的密码。普通用户只能修改自己的密码，root则可以修改任何用户的密码。
<p><span style="background-color: #c0c0c0;">格式：</span><br />passwd [options] [LOGIN]</p>
<p><span style="background-color: #c0c0c0;">选项：</span><br />-a 仅和-S联用，显式所有用户的状态<br />-d 删除用户密码<br />-e 立即使密码过期<br />-i INACTIVE 用于在密码过期INACTIVE天后自动禁用用户，用户将不能登陆<br />-l 锁定，禁止修改密码<br />-m 修改密码的最小时间间隔（天）<br />-S 显示账户的状态信息<br />-u 解锁，允许修改密码<br />-x 密码最长有效期限</p>
<p><span style="background-color: #c0c0c0;">举例：</span></p>
<pre class="crayon-plain-tag"># 修改root密码
sudo passwd root
# 系统会提示输入新密码Enter new UNIX password:  </pre>
</td>
</tr>
<tr>
<td class="blog_h2">who</td>
<td>显示本系统上的登陆用户</td>
</tr>
<tr>
<td class="blog_h2">w</td>
<td>
<p>显示哪些人登录了，他们在做什么
<p><span style="background-color: #c0c0c0;">格式：<br /></span></p>
<pre class="crayon-plain-tag">w [options] user [...]</pre>
<p> <span style="background-color: #c0c0c0;">示例：</span></p>
<pre class="crayon-plain-tag"># 第一行：当前时间，系统运行时间，登录用户数，1、5、15分钟负载
 22:23:26 up 60 days, 21:06,  1 user,  load average: 0.04, 0.01, 0.00
#用户     终端名    远程主机         登录时间  空闲时间 JCPU   PCPU 当前执行的命令行
USER     TTY      FROM             LOGIN@   IDLE   JCPU   PCPU WHAT
root     pts/1    123.120.25.149   17:09    0.00s  0.06s  0.00s w
# JCPU：所有附着在此TTY上的进程所消耗的时间
# PCPU：WHAT指定的那个进程消耗的时间</pre>
</td>
</tr>
<tr>
<td class="blog_h2">logname</td>
<td>显示当前用户的名称，类似的命令：whoami</td>
</tr>
<tr>
<td class="blog_h2">hostname</td>
<td>显示系统的主机名字</td>
</tr>
<tr>
<td class="blog_h2">hostid</td>
<td>显示主机的 32 位的16 进制ID</td>
</tr>
<tr>
<td class="blog_h2">uname</td>
<td>显示操作系统的信息，例如内核版本</td>
</tr>
<tr>
<td class="blog_h2">arch</td>
<td>显示当前系统的指令集架构，相当于uname -m</td>
</tr>
<tr>
<td class="blog_h2">id</td>
<td>打印当前进程的真实和有效用户ID、组ID</td>
</tr>
<tr>
<td class="blog_h2">tty</td>
<td>显示当前登录终端的设备映射文件</td>
</tr>
<tr>
<td class="blog_h2">init</td>
<td>init命令是所有进程的父进程。在系统启动的最后一步调用</td>
</tr>
<tr>
<td class="blog_h2">runlevel</td>
<td>显示当前和最后的运行级别</td>
</tr>
<tr>
<td class="blog_h2">reboot</td>
<td>重新启动主机</td>
</tr>
<tr>
<td class="blog_h2">shutdown</td>
<td>关闭主机，类似的还有halt</td>
</tr>
<tr>
<td class="blog_h2">trap</td>
<td>捕获信号并设置信号处理逻辑，参考<a href="/bash-study-note/#trap">Bash学习笔记</a></td>
</tr>
<tr>
<td class="blog_h2">pgrep,pkill</td>
<td>
<p>查找或杀死进程<br />这两个命令用于根据进程的名称或者其他属性来查找、杀死进程
<p><span style="background-color: #c0c0c0;">格式：</span><br />pgrep [options] pattern<br />pkill [options] pattern</p>
<p><span style="background-color: #c0c0c0;">选项：</span><br />-signal　仅pkill，需要发送给目标进程的信号<br />-c　打印匹配的进程数量而不是输出详细信息<br />-d　仅pgrep，指定用于分隔进程ID的字符串<br />-f　对整个命令行进行匹配而不是进程名称<br />-g　仅选择有效GID与该选项指定的GID匹配的进程，多个GID用逗号分隔<br />-G　仅选择真实GID与该选项指定的GID匹配的进程，多个GID用逗号分隔<br />-l　仅pgrep，连同PID一起列出进程名称<br />-a　仅pgrep，连同PID一起列出进程完整命令行<br />-n　仅选择最新启动的进程<br />-o　仅选择最早启动的进程<br />-P　仅选择父进程是该选项指定的PID的进程<br />-u　仅选择有效UID与该选项指定的UID匹配的进程，多个UID用逗号分隔<br />-U　仅选择真实UID与该选项指定的UID匹配的进程，多个UID用逗号分隔<br />-v　取反匹配<br />-w　仅pgrep，显示所有线程的id<br />-x　仅选择名称（如果指定-f则是命令行）完全匹配模式的进程<br />pattern　用于匹配名称或者命令行的正则表达式</p>
<p><span style="background-color: #c0c0c0;">退出状态：</span><br />0　一个或更多的进程被匹配 <br />1　无进程匹配 <br />2　语法错误 <br />3　其它严重错误</p>
<p><span style="background-color: #c0c0c0;">举例：</span></p>
<pre class="crayon-plain-tag">#立即杀死所有MySQL和Java进程
sudo pkill -9 '(mysql|java)'
#列出MySQL进程的PID和命令行路径
pgrep -a mysql</pre>
</td>
</tr>
<tr>
<td class="blog_h2"><a id="service"></a>service</td>
<td>
<p>启动或停止一个System V系统服务（/etc/init.d中的脚本）或者Upstart Job（/etc/init中的配置文件）
<p><span style="background-color: #c0c0c0;">格式：</span></p>
<pre class="crayon-plain-tag">service SCRIPT COMMAND [OPTIONS]
# 显示所有服务的状态
service --status-all</pre>
<p>SCRIPT要么对应<pre class="crayon-plain-tag">/etc/init.d/SCRIPT</pre> ，要么对应<pre class="crayon-plain-tag">/etc/init/SCRIPT.conf</pre> ，如果这两个目录都存在SCRIPT则Upstart Job的优先级更高</p>
<p>可以调用哪些COMMAND则取决于脚本，service将COMMAND和OPTIONS直接传递给对应的脚本</p>
<p>每个脚本至少应该定义start、stop命令，COMMAND restart相当于先运行stop，紧接着运行start</p>
</td>
</tr>
<tr>
<td class="blog_h2">monit</td>
<td>
<p>监控进程、程序、文件的状态。可以完成自动重启</p>
<p>参考<a href="/monit-under-monit">Ubuntu下使用monit</a></p>
</td>
</tr>
<tr>
<td class="blog_h2">chkconfig</td>
<td>
<p>新近的Ubuntu版本已经不支持该命令，使用<span style="background-color: #c0c0c0;">update-rc.d</span>命令代替之</p>
<p>显示和管理在启动过程中所开启的服务，该命令提供简单的方式管理/etc/rc[0-6].d目录中的符号链接<br />chkconfig可以添加、移除、列出、修改服务，以及检查服务的启动状态<br />如果不指定--level，on/off选项应用于2-5运行级别，reset则应用于所有级别<br />注意：每个服务可以包含start、stop脚本，当切换运行级别时，已经启动的服务不会重新启动，已经停止的服务也不会重新停止</p>
<p><span style="background-color: #c0c0c0;">格式：</span></p>
<pre class="crayon-plain-tag">chkconfig [--list] [--type type][name]
chkconfig --add name
chkconfig --del name
chkconfig --override name
chkconfig [--level levels] [--type type] name &lt;on|off|reset&gt;
chkconfig [--level levels] [--type type] name</pre>
<p><span style="background-color: #c0c0c0;">选项：</span><br />--level levels 指定操控的运行级别<br />--add name 添加一个服务，服务脚本必须预先存放为/etc/init.d/name<br />--del name 删除一个服务，/etc/rc[0-6].d中的符号链接全部删除<br />--list name 列出服务在各运行级别的启停信息</p>
</td>
</tr>
<tr>
<td class="blog_h2">sysv-rc-conf</td>
<td>
<p>提供图形界面来管理System V风格的启动脚本：</p>
<pre class="crayon-plain-tag">sudo apt-get install sysv-rc-conf
sudo sysv-rc-conf </pre>
</td>
</tr>
<tr>
<td class="blog_h2">update-rc.d</td>
<td>
<p>安装或者移除System V风格的初始化脚本的符号链接
<p><span style="background-color: #c0c0c0;">格式：</span></p>
<pre class="crayon-plain-tag">update-rc.d [-n] [-f] name remove
update-rc.d [-n] name defaults
update-rc.d [-n] name disable|enable [ S|2|3|4|5 ]</pre>
<p><span style="background-color: #c0c0c0;">选项：</span><br />-n  不做任何事情，只显示会做什么<br />-f 强制移除符号链接，即使/etc/init.d/name仍然存在</p>
</td>
</tr>
<tr>
<td class="blog_h2"><a id="initctl"></a>initctl</td>
<td>
<p>管理Upstart任务，通过此命令管理员可以与基于Upstart的init进程交互。某些发行版中，此命令可以和service替换使用，例如<pre class="crayon-plain-tag">initctl start srv</pre> 效果等同于<pre class="crayon-plain-tag">service srv start</pre> </p>
<p><span style="background-color: #c0c0c0;">格式：</span></p>
<pre class="crayon-plain-tag">initctl [OPTION]...  COMMAND [OPTION]...  ARG...</pre>
<p><span style="background-color: #c0c0c0;">子命令：</span><br />start JOB [KEY=VALUE]...   启动Job的新实例。KEY=VALUE用于指定Job的环境变量，对于多实例的Job通常基于环境变量设置它的实例名<br />stop JOB [KEY=VALUE]...  请求停止一个Job实例<br />restart JOB [KEY=VALUE]...  重启一个Job实例，首先将其Goal设置为stop，然后设置Goal为start<br />reload JOB [KEY=VALUE]...  发送SIGHUP信号给运行中的Job实例<br />status JOB [KEY=VALUE]...  显示Job的状态<br />list  列出已知的Job及其实例<br />emit EVENT [KEY=VALUE]...  请求发布EVENT类型的事件，KEY=VALUE用于指定事件中的环境变量，这些变量会自动export到受事件影响的Job的脚本代码中</p>
</td>
</tr>
<tr>
<td class="blog_h2"><a id="systemctl"></a>systemctl</td>
<td>
<p>控制和管理基于Systemd的服务，以及Systemd init机制本身。</p>
<p><span style="background-color: #c0c0c0;">格式：</span></p>
<pre class="crayon-plain-tag"># NAME 服务的名称，必须是unitName.unitType，例如mysql.service
# 如果unitType为service，则.unitType部分可以省略
systemctl [OPTIONS...] COMMAND [NAME...]</pre>
<p><span style="background-color: #c0c0c0;">子命令：</span><br />start  启动一个服务， systemctl start x.service等价于sysvinit的service x start，下同<br />stop  停止一个服务<br />restart  停止，然后再启动一个服务。即使执行命令之前，服务没有在运行，它也会被启动<br />reload  如果支持，用于重新载入一个服务<br />condrestart  如果服务正在运行，则重启之<br />status  打印服务的状态<br />list-unit-files   列出所有Unit定义，附加--type=service则仅列出服务<br />enable  允许服务自启动，systemctl enable x.service等价于sysvinit的chkconfig x on<br />disable  禁止服务自启动<br />is-enabled  检查服务是否可以自启动<br />daemon-reload  重新加载Systemd的配置<br />reboot  重启机器<br />poweroff 关机<br />suspend  待机<br />hibernate  休眠<br />hybrid-sleep 混合休眠模式（同时休眠到硬盘并待机）</p>
<p>示例：</p>
<pre class="crayon-plain-tag"># 列出所有正在运行的单元
systemctl list-units
# 列出所有单元，包括没有配置文件或者启动失败的
systemctl list-units --all
# 列出所有没有运行的单元
systemctl list-units --all --state=inactive
# 列出所有加载失败的单元
systemctl list-units --failed
# 列出所有正在运行的服务
systemctl list-units --type=service

# 查看蓝牙服务的状态
systemctl status bluetooth.service

# 查看单元是否启用、禁用
# enabled 允许自动启动
# disabled 不允许自动启动
# static 该单元的配置不包含install段，只能作为其它配置文件的依赖
# masked 该单元禁止被设置为自启动
systemctl list-unit-files

# 启动MySQL服务
systemctl mysql start
# 杀死Apache服务的所有进程
ystemctl kill apache.service 

# 让Systemd加载最新的配置文件
sudo systemctl daemon-reload</pre>
</td>
</tr>
<tr>
<td class="blog_h2">journalctl</td>
<td>
<p>查询systemd日志，即systemd-journald.service写入磁盘的日志内容。如果调用时不添加任何参数，则输出所有已经收集的日志内容。你可以指定多个FIELD=VALUE格式过滤条件，例如_SYSTEMD_UNIT=tomcat8.service。如果：
<ol>
<li>多个过滤条件针对不同的FIELD，则这些条件进行AND</li>
<li>多个过滤条件针对相同的FIELD，则这些条件进行OR</li>
<li>在两组过滤条件之间添加 + 符号，则前后条件进行OR</li>
</ol>
<p>所有用户被授权访问自己私有的日志。默认的仅仅root和systemd-journal组的用户能够访问系统日志、其它用户的日志</p>
<p><span style="background-color: #c0c0c0;">格式：</span>journalctl [OPTIONS...] [MATCHES...]</p>
<p><span style="background-color: #c0c0c0;">选项：</span><br />-r  反转输出顺序，最新的日志最先显示<br />-n NUM  显示最新的NUM条日志，默认10<br />-f 持续追加日志到标准输出，类似于tail -f<br />-k, --dmesg 仅显示内核消息，等价于_TRANSPORT=kernel<br />-u, --unit=UNIT|PATTERN，根据systemd配置单元过滤，等价于_SYSTEMD_UNIT=*<br />--user-unit= 显示特定用户会话单元（session unit）的消息，等价于_UID=*<br />-p 根据优先级过滤消息，可以指定数字或者级别名称，0-7分别为emerg,alert,crit,err,warning,notice,info,debug。可以指定范围，例如 3..4。等价于PRIORITY=*<br />--since=, --until= 显示指定时间之后，或者之前的消息，日期格式：2012-10-30 18:17:16，如果时间部分省略默认00:00:00，日期还可以使用yesterday、today等单词<br />--system  仅仅显示内核和系统消息<br />--user  仅仅显示当前用户的配置单元的消息<br />-M  仅仅显示本机上一个正在运行的容器的消息，必须指定容器名</p>
<p><span style="background-color: #c0c0c0;">示例：</span></p>
<pre class="crayon-plain-tag"># 显示tomcat8服务今天的日志
journalctl -u tomcat8 --since today
# 显示指定进程的日志
journalctl _PID=12558
# 显示特定程序的日志
journalctl /usr/bin/bash
# 显示最新的20条日志
journalctl -n 20
# 持续跟踪新的日志写入
journalctl -f
# 查看磁盘用量
journalctl --disk-usage
# 删除老的日志，直到磁盘占用空间不大于1G
sudo journalctl --vacuum-size=1G
# 删除老的日志，保留最近1年的
sudo journalctl --vacuum-time=1years

# 显示Kubelet的INFO及其一上级别的信息
journalctl -u kubelet -f  -p 0..7

# 指定时间范围
journalctl --since "2018-08-16 18:30:00" --until "2018-08-16 18:40:0"</pre>
</td>
</tr>
<tr>
<td class="blog_h2">systemd-analyze</td>
<td>
<p>分析系统的启动耗时
<p><span style="background-color: #c0c0c0;">示例：</span></p>
<pre class="crayon-plain-tag"># 查看启动耗时的概要信息
systemd-analyze         
# 查看每个服务的启动耗时信息，按照耗时从高到低排列
systemd-analyze blame</pre>
</td>
</tr>
<tr>
<td class="blog_h2">hostnamectl</td>
<td>
<p>查看或者设置主机名信息
<p><span style="background-color: #c0c0c0;">示例：</span></p>
<pre class="crayon-plain-tag"># 设置主机名
sudo hostnamectl set-hostname</pre>
</td>
</tr>
<tr>
<td class="blog_h2">localectl</td>
<td>
<p>进行本地化配置
<p><span style="background-color: #c0c0c0;">示例：</span></p>
<pre class="crayon-plain-tag"># 设置语言和编码方式
sudo localectl set-locale LANG=en_GB.utf8
# 设置键盘映射方式
sudo localectl set-keymap en_GB </pre>
</td>
</tr>
<tr>
<td class="blog_h2">timedatectl</td>
<td>
<p>时区、日期、时间设置
<p><span style="background-color: #c0c0c0;">示例：</span></p>
<pre class="crayon-plain-tag"># 列出所有可用时区
timedatectl list-timezones 
# 设置时区
sudo timedatectl set-timezone America/New_York
# 设置日期、时间，格式分别为YYYY-MM-DD、HH:MM:SS
sudo timedatectl set-time "2016-11-11"
sudo timedatectl set-time "16:16:00"</pre>
</td>
</tr>
<tr>
<td>chronyc</td>
<td>
<p>时钟同步命令
<p>示例：</p>
<pre class="crayon-plain-tag"># 查看 NTP 服务器的在线和离线状态
chronyc activity

# 检查 NTP 访问是否对特定主机可用
chronyc accheck

# 该命令会显示有多少 NTP 源在线/离线
chronyc activity

# 手动添加一台新的 NTP 服务器
chronyc add server

# 在客户端报告已访问到服务器
chronyc clients

# 手动移除 NTP 服务器或对等服务器
chronyc delete

# 手动设置守护进程时间
chronyc settime

# 校准时间服务器，显示系统时间信息
chronyc tracking

# 检查 NTP 访问是否对特定主机可用
chronyc accheck

# 查看时间同步源
chronyc sources -v

# 查看时间同步源状态
chronyc sourcestats -v

# 立即进行时钟同步
chronyc -a makestep</pre>
</td>
</tr>
<tr>
<td class="blog_h2">loginctl</td>
<td>
<p>查看当前登录的用户或会话
<p><span style="background-color: #c0c0c0;">示例：</span></p>
<pre class="crayon-plain-tag"># 显示登录的会话
loginctl list-sessions
# 显示登录的用户
loginctl list-users</pre>
</td>
</tr>
<tr>
<td class="blog_h2">su</td>
<td>
<p>改变用户身份，以另外一个账户登录，如果不加参数，则改变为root
<p><span style="background-color: #c0c0c0;">格式：</span><br />su [options] [username]<br /><span style="background-color: #c0c0c0;">选项：</span><br />-c,  指定需要执行的命令<br />-, -l, --login 提供类似于username直接登陆的执行环境，如果使用“-”，必须作为最后一个options<br />-s, --shell 需要调用的Shell<br />-m, -p  保留当前的环境变量，除了$PATH、$IFS</p>
</td>
</tr>
<tr>
<td class="blog_h2">sudo</td>
<td>
<p>以root或其他用户身份来执行一个命令。只能应用于程序，不能应用于Bash内置命令，例如：<pre class="crayon-plain-tag">sudo cd /var/lib/mysql</pre>不会达到预期效果。</p>
<p><span style="background-color: #c0c0c0;">格式：</span><br /> sudo -h | -K | -k | -V<br /> sudo -v [-AknS] [-g group] [-h host] [-p prompt] [-u user]<br /> sudo -l [-AknS] [-g group] [-h host] [-p prompt] [-U user] [-u user] [command]</p>
<p><span style="background-color: #c0c0c0;">选项：</span><br />-E 提示需要保留当前环境变量<br />-e 编辑一个或者多个文件，而不是执行命令<br />-g 指定主要组（primary group）而不是使用目标用户的主要组<br />-H 设置HOME环境变量为目标用户的HOME目录<br />-i 执行用户的默认登陆Shell，这意味着.profile、.login等会被读取并执行<br />-u 指定目标用户</p>
<p><span style="background-color: #c0c0c0;">举例：</span></p>
<pre class="crayon-plain-tag"># 以root身份执行命令，不永久提升
sudo ls /dev
# 永久提升当前用户为root，不执行命令
sudo -i
exit     #需要退出root的登陆才能返回当前用户</pre>
</td>
</tr>
<tr>
<td class="blog_h2">mount</td>
<td>
<p>挂载一个文件系统， 通常都用来安装外部设备， 比如软盘或CDROM。Unix系统中所有可访问的文件，都组织在单棵树中，这棵树的根叫做  / 。树中的文件可以分布在多个设备上。mount命令的职责就是将设备附到文件系统树的某个节点上。
<p>大部分设备都由特殊的设备文件来代表。例外情况如NFS，它由gmem.cc:/dir这样的URI表示。引用设备文件时，也可以使用LABEL或UUID。</p>
<p>注意：</p>
<ol>
<li>作为挂载点的目录，必须预先创建</li>
<li>如果挂载点目录中有文件，挂载成功后，此文件不可见</li>
<li>上述不可见的文件，在umount后重新出现</li>
<li>挂载后，挂载点于目录文件系统根目录具有一致的Unix权限</li>
</ol>
<p><span style="background-color: #c0c0c0;">绑定挂载</span></p>
<p>从内核2.4开始，允许将文件系统树的某一部分，重新挂载到另外一个位置：</p>
<p style="padding-left: 30px;">mount --bind olddir newdir<br />mount -B olddir newdir</p>
<p>在fstab中，进行绑定挂载的格式是：/olddir /newdir none bind</p>
<p>执行绑定挂载后，olddir的内容可以在newdir处访问，它们一模一样。</p>
<p>绑定挂载也可以用来挂载单个文件。</p>
<p>默认情况下，绑定挂载不会处理子挂载，也就是说，/olddir的某个子目录被作为挂载点的情况，其内容无法体现在/newdir中，要解决此问题，可以使用：</p>
<p style="padding-left: 30px;">mount --rbind olddir newdir</p>
<p><span style="background-color: #c0c0c0;">移动操作</span></p>
<p>从2.5.1开始，支持将一个挂载的子树移动到另外一个位置：</p>
<p style="padding-left: 30px;">mount --move olddir newdir<br />mount -M olddir newdir</p>
<p>注意olddir必须是一个挂载点</p>
<p><span style="background-color: #c0c0c0;">共享子树</span></p>
<p>从2.6.15开始，可以将挂载、及其子挂载标记为shared, private, slave 或 unbindable。可以在容器技术中使用：</p>
<p style="padding-left: 30px;">mount --make-shared mountpoint<br /> mount --make-slave mountpoint<br /> mount --make-private mountpoint<br /> mount --make-unbindable mountpoint</p>
<p><span style="background-color: #c0c0c0;">格式：</span><br />mount -t type device dir<br />mount [-lhV]<br />mount -a [-fFnrsvw] [-t vfstype] [-O optlist]<br />mount [-fnrsvw] [-o option[,option]...] device|dir<br />mount [-fnrsvw] [-t vfstype] [-o options] device dir</p>
<p><span style="background-color: #c0c0c0;">选项：</span></p>
<p>-a　--all 挂载所有fstab中包括的所有文件系统<br />-f　--fake 执行所有步骤，除了系统调用，用于和-v联用来观察mount命令的具体行为<br />-r　--read-only 挂载为只读模式，与-o ro同义<br />-w　--rw 挂载为读写模式，与-o rw同义<br />-L 　label 挂载具有指定标签的分区<br />-U 　uuid 挂载具有指定UUID的分区<br />-t　 --types vfstype 指示文件系统的类型，如果不指定，mount命令会尝试猜测文件系统的类型<br />-o　--options 使用逗号分隔的选项，例如mount LABEL=mydisk -o noatime,nouser</p>
<p><span style="background-color: #c0c0c0;">举例：</span></p>
<pre class="crayon-plain-tag">#把第一块硬盘的第3个分区挂载为/kssi 
mount /dev/hda3 /kssi 
#挂载一个iso镜像文件 
mount -o loop /home/alex/unbunt-14.02.iso /mnt/cdrom</pre>
</td>
</tr>
<tr>
<td class="blog_h2">umount</td>
<td>
<p>卸载一个当前已经 mount 的文件系统
<p>举例：</p>
<pre class="crayon-plain-tag">#根据设备路径卸载 
umount /dev/hda3 
#根据挂载目录卸载 
umount /kssi</pre>
</td>
</tr>
<tr>
<td class="blog_h2">getconf </td>
<td>
<p>查询系统配置变量
<p><span style="background-color: #c0c0c0;">格式：</span><br />getconf -a<br />getconf [-v specification] system_var<br />getconf [-v specification] path_var pathname</p>
<p><span style="background-color: #c0c0c0;">选项：</span><br />-a 显示所有配置变量及其值<br />system_var 系统配置变量的名称，在sysconf中定义<br />path_var 由pathconf定义的系统配置变量</p>
<p><span style="background-color: #c0c0c0;">举例：</span></p>
<pre class="crayon-plain-tag">#获取内存页的大小
getconf PAGESIZE</pre>
</td>
</tr>
<tr>
<td class="blog_h2">mkswap</td>
<td>创建一个交换分区或文件，随后必须马上使用swapon来启用</td>
</tr>
<tr>
<td class="blog_h2">swapon</td>
<td rowspan="2">启用/禁用交换分区或文件，通常在启动和关机的时候才有效</td>
</tr>
<tr>
<td class="blog_h2">swapoff</td>
</tr>
<tr>
<td class="blog_h2">mke2fs</td>
<td>创建ext2文件系统</td>
</tr>
<tr>
<td class="blog_h2">tune2fs</td>
<td>调整ext2文件系统。 可以用来修改文件系统参数</td>
</tr>
<tr>
<td class="blog_h2">dumpe2fs</td>
<td>打印非常详细的文件系统信息</td>
</tr>
<tr>
<td class="blog_h2">tune2fs </td>
<td>
<p>显示或调整ext2/ext3/ext4文件系统的参数
<p><span style="background-color: #c0c0c0;">举例：</span></p>
<pre class="crayon-plain-tag">#查看硬盘分区的块大小
tune2fs -l /dev/xvda | grep 'Block size'</pre>
</td>
</tr>
<tr>
<td class="blog_h2">du</td>
<td>递归的显示磁盘文件的使用状况。默认从当前工作目录递归</td>
</tr>
<tr>
<td class="blog_h2">hdparm</td>
<td>列出或修改硬盘参数</td>
</tr>
<tr>
<td class="blog_h2">fdisk</td>
<td>
<p>在存储设备上创建和修改一个分区表。该命令理解DOS风格的分区表、BSD|SUN风格的disklables。fdisk不理解GUID分区表（GPTs），它也不是为了大型分区设计的，你可以使用GNU parted代替它
<p>硬盘可以被划分为1-N个逻辑磁盘——分区（partitions），关于分区的信息记录在分区表中，分区表位于磁盘的0扇区</p>
<p>Linux至少需要一个分区，作为其<span style="background-color: #c0c0c0;">根文件系统</span>。Linux可以使用交换文件或者交换分区，然而后者效率高，因此Linux系统的第二个分区常常是<span style="background-color: #c0c0c0;">swap</span>分区。在Intel兼容硬件上启动机器的BIOS最多只能访问磁盘的前1024个柱面（cylinders），因此，大磁盘用户常常划分从若干MB的小分区，挂载到<span style="background-color: #c0c0c0;">/boot</span>，存储内核镜像、一部分启动时需要的辅助文件</p>
<p><span style="background-color: #c0c0c0;">格式：</span></p>
<pre class="crayon-plain-tag">fdisk [-uc] [-b sectorsize] [-C cyls] [-H heads] [-S sects] device
fdisk -l [-u] [device...]
fdisk -s partition...</pre>
<p><span style="background-color: #c0c0c0;">选项：</span></p>
<p>-b sectorsize    指定磁盘的扇区大小<br />-c[=mode]    指定兼容模式：dos或nondos（默认）<br />-l 列出指定设备的分区表并退出<br />-s partition...    打印指定的每个分区的尺寸（按block计）</p>
<p><span style="background-color: #c0c0c0;">示例 - 在线修改分区表：</span></p>
<pre class="crayon-plain-tag"># 这个例子中，我们希望扩展根分区的大小
# 目标机器是一台虚拟机，我们首先扩展了它的磁盘尺寸
qemu-img resize xenial-base.qcow2 256G


# 但是查看磁盘空间，发现没有变化。这是因为分区表的问题
df -H
Filesystem      Size  Used Avail Use% Mounted on
/dev/vda1        33G  2.6G   29G   9% /


# 开始修改分区表

# 首先关闭swap
swapoff -a

# 查看当前分区表
fdisk -l /dev/vda
# 可以看到磁盘是256G
Disk /dev/vda: 256 GiB, 274877906944 bytes, 536870912 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disklabel type: dos
Disk identifier: 0x873848e8

Device     Boot    Start      End  Sectors  Size Id Type
/dev/vda1  *        2048 65107967 65105920   31G 83 Linux
/dev/vda2       65110014 67106815  1996802  975M  5 Extended
/dev/vda5       65110016 67106815  1996800  975M 82 Linux swap / Solaris
# 但是分区表仅仅用到 67106815 * 512 / 1024 / 1024 / 1024 = 32GiB，也就是未扩展前的磁盘大小

# 进入交互模式
fdisk /dev/vda

# 依次删除所有分区
fdisk /dev/vda
Command (m for help): d
Partition number (1,2,5, default 5):   5        # 删除分区5，交换分区
Command (m for help): d
Partition number (1,2,5, default 5):   2        # 删除分区2
Command (m for help): d                         # 不需要选择，删除分区1

# 重新创建主分区
Command (m for help): n 
Select (default p): p                           # 创建主分区
Partition number (1-4, default 1):  1           # 创建根分区vda1
First sector (2048-536870911, default 2048):    # 保持第一扇区大小不变
Last sector, +sectors or +size{K,M,G,T,P} (2048-536870911, default 536870911): +252G
                                                # 填写+252G 留下4G给交换分区
# 重新创建交换分区
Command (m for help): n                         # 然后依次回车
Command (m for help): t                         # 修改分区2的类型
Partition number (1,2, default 2): 2
Partition type (type L to list all types): 82   # 修改为交换分区

# 保存更改
Command (m for help): w

# 由于根分区正在被使用，因此分区表修改但未重新载入
The partition table has been altered.
Calling ioctl() to re-read partition table.
Re-reading the partition table failed.: Device or resource busy

The kernel still uses the old table. The new table will be used at the next reboot or after you run partprobe(8) or kpartx(8).

# 不需要重启，使用下面的命令告知内核，载入新的分区表
partprobe

# 可以看到分区表正常了
fdisk -l /dev/vda
Disk /dev/vda: 256 GiB, 274877906944 bytes, 536870912 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disklabel type: dos
Disk identifier: 0x873848e8

Device     Boot     Start       End   Sectors  Size Id Type
/dev/vda1            2048 528484351 528482304  252G 83 Linux
/dev/vda2       528484352 536870911   8386560    4G 82 Linux swap / Solaris

# 工作仍然没有结束，df -H 可以看到文件系统大小仍然是旧的
df -H
Filesystem      Size  Used Avail Use% Mounted on
/dev/vda1        33G  2.6G   29G   9% /# 

# 更新文件系统大小
resize2fs /dev/vda1

# 重新创建交换分区
mkswap /dev/vda2
Setting up swapspace version 1, size = 4 GiB (4293914624 bytes)
no label, UUID=bb073528-4aa6-4af1-8bbd-78267bc90336

# 将新的UUID，替换fstab中的旧的
vim /etc/fstab

# 启动swap
swapon -a</pre>
</td>
</tr>
<tr>
<td class="blog_h2">badblocks</td>
<td>检查存储设备的坏块</td>
</tr>
<tr>
<td class="blog_h2">lsblk</td>
<td>列出所有块设备，将以树状结构显示磁盘和分区</td>
</tr>
<tr>
<td class="blog_h2">blkid</td>
<td>显示各分区的UUID</td>
</tr>
<tr>
<td class="blog_h2">lsusb</td>
<td>列出所有USB总线和使用USB 的设备</td>
</tr>
<tr>
<td class="blog_h2">usbmodules</td>
<td>输出连接USB 设备的驱动模块的信息</td>
</tr>
<tr>
<td class="blog_h2">mkbootdisk</td>
<td>创建启动盘</td>
</tr>
<tr>
<td class="blog_h2">dump,restore</td>
<td>备份和还原文件系统</td>
</tr>
<tr>
<td class="blog_h2">quota</td>
<td>显示用户或组的磁盘配额</td>
</tr>
<tr>
<td>setquota</td>
<td>设置用户或组的磁盘配额</td>
</tr>
<tr>
<td class="blog_h2">ulimit</td>
<td>
<p>设置使用系统资源的上限
<p><span style="background-color: #c0c0c0;">选项：</span></p>
<p>-a：显示目前资源限制的设定<br />-c ：设定core文件的最大值，单位为区块<br />-d ：程序数据节区的最大值，单位为KB<br />-f ：shell所能建立的最大文件，单位为区块<br />-H：设定资源的硬性限制，也就是管理员所设下的限制<br />-m ：指定可使用内存的上限，单位为KB<br />-n ：指定同一时间最多可开启的文件数<br />-p ：指定管道缓冲区的大小，单位512字节<br />-s ：指定栈的上限，单位为KB<br />-S：设定资源的弹性限制<br />-t ：指定CPU使用时间的上限，单位为秒<br />-u ：用户最多可开启的程序数目<br />-v ：指定可使用的虚拟内存上限，单位为KB</p>
</td>
</tr>
<tr>
<td class="blog_h2">lsmod</td>
<td>列出所有安装的内核模块</td>
</tr>
<tr>
<td class="blog_h2">insmod</td>
<td>强制一个内核模块的安装</td>
</tr>
<tr>
<td class="blog_h2">rmmod</td>
<td>强制卸载一个内核模块</td>
</tr>
<tr>
<td class="blog_h2">modinfo</td>
<td>输出一个可装载的内核模块的信息</td>
</tr>
<tr>
<td class="blog_h2">modprobe</td>
<td>
<p>从Linux内核中添加或者删除模块。该命令智能的进行模块的安装/卸载，为了便利，不区分模块名字中的-和_。该命令会查找<pre class="crayon-plain-tag">/lib/modules/`uname -r`</pre> 目录，找到所有模块和相关文件</p>
<p><span style="background-color: #c0c0c0;">格式：</span></p>
<pre class="crayon-plain-tag">modprobe [-v] [-V] [-C config-file] [-n] [-i] [-q] [-b] [modulename] [module params...]
modprobe [-r] [-v] [-n] [-i] [modulename...]
modprobe [-c]
modprobe [--dump-modversions] [filename]</pre>
<p><span style="background-color: #c0c0c0;">选项：</span><br />-a    安装命令行中所有指定的模块<br />-r    移除而不是安装模块</p>
<p>注意，重启后效果消失。要永久修改内核模块加载，使用/etc/modules文件</p>
</td>
</tr>
<tr>
<td class="blog_h2">sync</td>
<td>强制写入所有需要更新的 buffer 上的数据到硬盘上</td>
</tr>
<tr>
<td class="blog_h2">ldd</td>
<td>显示一个可执行文件的共享库的依赖关系</td>
</tr>
<tr>
<td class="blog_h2">rsync</td>
<td>
<p>可以在多台主机之间进行文件同步</p>
<p><span style="background-color: #c0c0c0;">格式：</span></p>
<pre class="crayon-plain-tag"># 本地同步
rsync [OPTION...] SRC... [DEST]

# 远程同步
rsync [OPTION...] [USER@]HOST:SRC... [DEST]     # PULL
rsync [OPTION...] SRC... [USER@]HOST:DEST       # PUSH</pre>
<p><span style="background-color: #c0c0c0;">选项：</span></p>
<p>-a  归档模式，等价于-rlptgoD<br />-r  递归处理目录<br />-l   不跟随符号链接<br />-p 保留文件模式<br />-t  保留修改时间<br />-g  保留文件的group信息<br />-o  保留文件的owner信息<br />-D  --devices --specials 保留设备文件、保留特殊文件<br />-z  传输数据时进行压缩<br />-P 等价于 --partial --progress<br />--partial  保留部分传输的文件<br />--progress 显示传输进度<br />--delete  删除目标目录中比源目录多余的文件<br />--inplace  就地更新，不改变目标文件的inode<br />-t, --times  保持修改时间不变<br />-c, --checksum 基于校验和判断哪些文件需要传输，而非修改时间+尺寸<br />-I, --ignore-times 判断哪些文件需要传输时，仅仅考虑尺寸，不考虑修改时间<br />-v 显示更多日志<br />-e 指定使用的远程Shell<br />-i 为所有更新输出变更摘要<br />-q 安静模式</p>
<p><span style="background-color: #c0c0c0;">示例：</span></p>
<pre class="crayon-plain-tag"># 使用密钥登陆到bj.gmem.cc，然后将本地的www目录拷贝到bj的/var/目录下
rsync -avz -e "ssh -i  /home/alex/Documents/puTTY/gmem.key" --progress www root@bj.gmem.cc:/var/

# 使用校验和来确认文件是否需要同步
rsync -Pav -e "ssh -i /root/Documents/puTTY/gmem.key" --checksum \
    root@hk.gmem.cc:/var/www/html/blog/wp-content/uploads /var/www/html/blog/wp-content</pre>
</td>
</tr>
<tr>
<td class="blog_h2">stat</td>
<td>显示一个文件或目录的详细信息，例如尺寸、修改时间等</td>
</tr>
<tr>
<td class="blog_h2">logger</td>
<td>
<p>附加一个用户产生的消息到系统日志，系统日志默认/var/log/syslog
<p><span style="background-color: #c0c0c0;">格式：</span><br />logger [-dhisV] [-f file] [-n server] [-P port] <br />[-p pri] [-t tag] [-u socket] [message]</p>
<p><span style="background-color: #c0c0c0;">选项：</span><br />-d, --udp 使用UDP而不是TCP<br />-i, --id 记录进程的ID<br />-f, --file file 将文件的内容记录到系统日志，不得与命令行message联用<br />-n, --server server 通过UDP将日志写到远程syslog服务器<br />-P, --port port UDP端口，默认514<br />-p, --priority priority 设定消息进入日志的优先级，使用facility.level的格式，默认user.notice<br />-s, --stderr 同时将消息写出到标准错误<br />-t, --tag tag 为每行日志输出附加标签<br />-u, --socket socket 写到指定的套接字而不是内置的syslog例程</p>
</td>
</tr>
<tr>
<td class="blog_h2">logrotate</td>
<td>管理系统的日志文件。可以在合适的时候轮换、压缩、删除</td>
</tr>
<tr>
<td class="blog_h2">strip</td>
<td>从可执行文件中去掉调试符号引用。这样做可以减小尺寸， 但是就不能调试了</td>
</tr>
<tr>
<td class="blog_h2">lscpu</td>
<td>
<p>打印CPU架构相关信息，示例：</p>
<pre class="crayon-plain-tag"># 显示CPU当前的时钟频率
lscpu | grep MHz </pre>
</td>
</tr>
<tr>
<td class="blog_h2">lshw</td>
<td>打印硬件信息</td>
</tr>
<tr>
<td class="blog_h2">dmidecode</td>
<td>
<p>解码DMI（即SMBIOS，System Management BIOS）信息为人类可读的格式。DMI表包含了系统硬件信息，包括序列号、BIOS版本
<p>信息依据DMI类型分段输出到屏幕上</p>
</td>
</tr>
<tr>
<td class="blog_h2">sysctl</td>
<td>
<p>在运行时配置内核参数，这些内核参数位于/proc/sys/</p>
<p><span style="background-color: #c0c0c0;">格式：</span><br />sysctl [-n] [-e] variable ...<br />sysctl [-n] [-e] [-q] -w variable=value ...<br />sysctl [-n] [-e] [-q] -p &lt;filename&gt;<br />sysctl [-n] [-e] -a<br />sysctl [-n] [-e] -A</p>
<p><span style="background-color: #c0c0c0;">选项：</span><br />variable 内核参数名（键），可以使用点号.代替/<br />variable=value 设置内核参数的值<br />-n 打印值时禁止打印键<br />-e 忽略未知键错误<br />-N 仅打印名称 <br />-q 不把设置的值打印到标准输出<br />-w 执行修改操作<br />-p 从/etc/sysctl.conf加载内核参数设置，设置为-表示从标准输入读取<br />-a 显示当前变量的所有值</p>
<p><span style="background-color: #c0c0c0;">举例：</span></p>
<pre class="crayon-plain-tag">sysctl -a
sysctl -n kernel.hostname
sysctl -w kernel.domainname="example.com"</pre>
</td>
</tr>
<tr>
<td class="blog_h2">dpkg-reconfigure</td>
<td>
<p>重新配置一个已经安装的包，<span style="background-color: #c0c0c0;">举例：</span>
<pre class="crayon-plain-tag"># 重新配置数字证书，可以禁用某些证书
dpkg-reconfigure ca-certificates</pre>
</td>
</tr>
<tr>
<td class="blog_h2">update-ca-certificates</td>
<td>
<p>根据配置文件 /etc/ca-certificates.conf 的内容，更新/etc/ssl/certs下的受信任证书的符号链接
</td>
</tr>
<tr>
<td>update-icon-caches</td>
<td>更新GTK图标缓存：<pre class="crayon-plain-tag">sudo update-icon-caches /usr/share/icons/*</pre></td>
</tr>
<tr>
<td class="blog_h2">openssl</td>
<td>
<p>OpenSSL的命令行工具，OpenSSL是一个实现了 SSL(v2/v3) 和TLS (v1) 的开源组件<br /><span style="background-color: #c0c0c0;">格式：</span><br />openssl command [ command_opts ] [ command_args ]</p>
<p><span style="background-color: #c0c0c0;">举例：</span></p>
<pre class="crayon-plain-tag"># 生成密钥并自签名（根证书）
openssl genrsa -out ca.key 2048
openssl req -x509 -newkey rsa:2048 -keyout ca.key -out ca.crt -days 3650 \
  -subj "/C=CN/ST=BeiJing/L=BeiJing/O=Gmem Studio/OU=IT Support/CN=Gmem SHA256 CA"

# 单个命令同时生成密钥和证书，-nodes禁止 Enter PEM pass phrase 提示
openssl req -nodes -new -x509 -keyout server.key -out server.crt \
  -subj "/CN=Teleport Self-signed Certificate" -addext "subjectAltName = IP:82.157.67.96"

# 解码证书，以查看其内容
openssl x509 -in ca.crt -text -noout
# 解码证书请求，以查看其内容
openssl req -in k8s.csr -text -noout

# 解除私钥密码，将私钥转换为原始RSA Key
openssl rsa -in ca-withpass.key -out ca.key

# 转换为PKCS#8格式的私钥
# 这种格式的私钥以 -----BEGIN PRIVATE KEY----- 开头
# 包含私钥 + OID，OID说明了密钥类型
# 老版本的OpenSSL使用PKCS#1（传统OpenSSL格式），该格式以
# -----BEGIN RSA PRIVATE KEY----- 开头

# PKCS#1 转换为 PKCS#8 
openssl pkcs8 -topk8 -in ~/Documents/puTTY/ca.key -out rootCA-key.pem  -nocrypt
# PKCS#8 转换为 PKCS#1


# 生成非对称秘钥对
openssl genrsa -out www.gmem.cc.key 2048
#生成证书请求（生成网站证书时，Common Name应当是你的域名，不要加端口）
openssl req -new -sha256 -key www.gmem.cc.key -out www.gmem.cc.csr \
  -subj "/C=CN/ST=BeiJing/L=BeiJing/O=Gmem Studio/OU=IT Support/CN=*.gmem.cc"

# 对证书请求签名
openssl x509 -req -days 3650 -in www.gmem.cc.csr -CA ca.crt 
    -CAkey ca.key -CAcreateserial -out www.gmem.cc.crt

# 从证书中导出公钥
openssl x509 -inform pem -in www.gmem.cc.crt -pubkey


# 从Chrome 58开始，不支持仅仅依据CN字段来识别网站主机
# 必须在证书中使用SAN
openssl genrsa -out k8s.key 2048
export SAN_CFG=$(printf "\n[SAN]\nsubjectAltName=DNS:*.k8s.eb.dapp.com,DNS:*k8s.eb.mid,DNS:k8s.eb.dapp.com,DNS:k8s.eb.mid")
openssl req -new -sha256 -key k8s.key -out k8s.csr \
    -subj "/C=CN/ST=BeiJing/O=Beijing Dangdang Information Technology Co., Ltd./CN=TECH-DIGITAL Kubernetes Cluster " \
    -reqexts SAN -config &lt;(cat /etc/ssl/openssl.cnf &lt;(echo $SAN_CFG))

openssl x509 -req -sha256 -in k8s.csr  -out k8s.crt -CA ca.crt -CAkey ca-nopass.key -CAcreateserial -days 3650 \
     -extensions SAN -extfile &lt;(echo "${SAN_CFG}")
# 不使用配置文件生成带有SAN的请求
openssl req  -addext ... 
# 不使用配置文件进行签名
openssl x509 -extfile &lt;(printf "subjectAltName = DNS:localhost, IP:127.0.0.1, IP:82.157.67.96")
# 不使用配置文件进行签名，签名中间CA证书
cat "$(openssl version -d | sed 's/.*"\(.*\)"/\1/g')/openssl.cnf" | sed "s|^\(dir\s*=\s*\)\(.*\)|\1$PWD|g" &gt; openssl.cnf
openssl ca -extensions v3_ca -notext -in installer.csr -out installer.crt -cert ../ca/ca.crt -keyfile ../ca/ca.key -days 3650 -policy policy_anything -batch -create_serial -config openssl.cnf</pre>
</td>
</tr>
<tr>
<td class="blog_h2">cvt</td>
<td>
<p>计算VESA标准的CVT模式代码（mode lines），<span style="background-color: #c0c0c0;">举例：</span>
<pre class="crayon-plain-tag">cvt 1600 900 60
# 输出如下：
# # 1600x900 59.95 Hz (CVT 1.44M9) hsync: 55.99 kHz; pclk: 118.25 MHz
# Modeline "1600x900_60.00"  118.25  1600 1696 1856 2112  900 903 908 934 -hsync +vsync</pre>
</td>
</tr>
<tr>
<td class="blog_h2">xrandr</td>
<td>
<p>注：该命令的修改在重启后失效，要永久生效，参考<a href="/ubuntu-faq#add-modeline">添加自定义的显示模式</a>
<p>RandR扩展的原生命令行接口。RandR（Resize and Rotate）是X11协议的扩展，为屏幕根窗口提供改变大小、旋转、反射效果的能力，同时支持设置刷新率，<span style="background-color: #c0c0c0;"><span style="background-color: #c0c0c0;">举例：</span></span></p>
<pre class="crayon-plain-tag"># 查询当前连接到的显示器，显示分辨率和刷新率等信息
xrandr -q
# 输出
# Screen 0: minimum 1 x 1, current 1600 x 900, maximum 8192 x 8192
# Virtual1 connected primary 1600x900+0+0 (normal left inverted right x axis y axis) 0mm x 0mm
#   1280x768      60.00 +  59.87  
#   ...
#   640x480       59.94  
#   1600x900_600.00 599.89* 
# Virtual2 disconnected (normal left inverted right x axis y axis)

# 新建一个显示模式              这里的内容参考cvt 1600 900 60命令的输出
xrandr --newmode "1600x900"  1837.25  1600 1760 1936 2272  900 903 908 1348 -hsync 命令+vsync

# 为显示器Virtual1添加刚刚新建的模式
xrandr --addmode Virtual1 1600x900

# 立即以指定模式输出
xrandr --output Virtual1 1600x900</pre>
</td>
</tr>
<tr>
<td class="blog_h2">dd</td>
<td>
<p>转换并拷贝文件，该命令根据参数转换数据的格式，并且把输入文件写出到输出文件中
<p><span style="background-color: #c0c0c0;">参数：</span><br />bs=BYTES 每次读写的最大字节数<br />cbs=BYTES 每次转换的字节数<br />conv=CONVS 根据逗号分隔的CONVS符号列表来执行转换<br />count=N 读取N个输入块，块大小为bs<br />ibs=BYTES 每次最多读取的字节数，默认512<br />if=FILE 从目标文件读取，而不是标准输入<br />iflag=FLAGS 根据逗号分隔的FLAG符号列表来读取<br />obs=BYTES 每次最多写入的字节数，默认512<br />of=FILE 写出到文件，而不是标准输出<br />oflag=FLAGS 根据逗号分隔的FLAG符号列表来写出<br />seek=N 在输出文件开始处，跳过N个obs字节的块<br />skip=N  在输入文件开始处，跳过N个ibs字节的块<br />status=WHICH 禁止输出什么信息到标准错误，none禁止所有；noxfer禁止传输状态<br />注意：N和BYTES可以添加后缀：KB（1000）；K（1024）；MB（1000*1000）；M（1024*1024）...等等</p>
<p><span style="background-color: #c0c0c0;">CONVS符号：</span><br />ascii 从EBCDIC到ASCII<br />ebcdic 从ASCII到EBCDIC<br />ibm 从ASCII到备选EBCDIC<br />block 填充空格，使换行符结尾的记录达到cbs大小<br />unblock 把记录结尾的空格改为换行符<br />lcase 转换为小写<br />ucase 转换为大写<br />sparse 对于NUL输入块，尝试seek而不是write<br />swab 交换每对输入字节<br />sync 填充NUL，让每个输入块达到ibs大小，与block/unblock联用，则填充空格而非NUL<br />excl 如果输出文件已经存在，则失败<br />nocreat 不去创建输出文件<br />notrunc 不去截断输出文件<br />noerror 出现读错误后，仍然继续<br />fdatasync 完毕前，同步数据到磁盘<br />fsync 同上，同时同步元数据</p>
<p><span style="background-color: #c0c0c0;">FLAG符号：</span><br />append 仅用于oflag，附加模式<br />direct 使用direct I/O<br />directory 除非是一个目录，否则失败<br />dsync 使用同步I/O<br />sync 使用他不I/O，包括元数据<br />nonblock 使用非阻塞I/O<br />noatime 不更新文件的访问时间<br />nocache 丢弃缓存数据<br />nofollow 不跟随符号链接</p>
<p><span style="background-color: #c0c0c0;">举例：</span></p>
<pre class="crayon-plain-tag"># 导出整个磁盘为镜像文件，注意if选择设备文件（而不是分区）
sudo dd bs=4M of=~/Downloads/raspberrypi-alex.img if=/dev/mmcblk0
# 导入镜像到磁盘，目标磁盘必须大于等于镜像，目标磁盘的所有分区必须预先unmount
sudo dd bs=4M if=~/Downloads/raspberrypi-alex.img of=/dev/mmcblk0&amp;nbsp;

# 写swap分区
sudo dd if=/dev/zero of=/swapfile bs=1M count=1024</pre>
</td>
</tr>
<tr>
<td class="blog_h2">cpufreq-info</td>
<td>
<p>检索cpufreq内核信息
<p><span style="background-color: #c0c0c0;">选项：</span><br />-c  CPU  显示指定CPU（序号）的信息<br />-e  打印调试信息<br />-f   依据cpufreq core得到CPU当前运作频率<br />-w  从硬件获取CPU运作频率，需要ROOT<br />-l    获得硬件限制的CPU频率范围<br />-d   得到使用的cpufreq内核驱动<br />-p   获得当前使用的cpufreq策略<br />-g   列出可用的governors，governors类似于Windows的电源计划：<br />          ondemand    按需快速动态调整CPU频率，会极速的在最大最小频率之间调整<br />          conservative   类似于ondemand，但是频率按时间的变化曲线会比较平缓<br />          performance   运行于最大频率<br />          powersave    运行于最小频率<br />          userspace   运行于用户指定的频率<br />-a   查看哪些CPU以相同的硬件频率运行<br />-s    如果可用，获得cpufreq统计信息<br />-y    显示最大的CPU频率变更延迟时间<br />-m  输出人类可读格式</p>
<p><span style="background-color: #c0c0c0;">示例：</span></p>
<pre class="crayon-plain-tag">cpufreq-info -p
# 800000 2901000 userspace 

cpufreq-info -g
# conservative ondemand userspace powersave performance</pre>
</td>
</tr>
<tr>
<td class="blog_h2">cpufreq-set</td>
<td>
<p>修改CPU频率设置的小工具
<p><span style="background-color: #c0c0c0;">选项：</span><br />-c CPU    指定操作的CPU的序号，如果不指定，针对0号操作<br />-d    governor可以选择的最低频率<br />-u    governor可以选择的最高频率<br />-g GOV    切换使用的governor<br />-f    手工设置频率，需要加载governor：userspace<br />-r    修改所有硬件相关的CPU，2.6.29+忽略此选项</p>
<p>注意：设置在重启后丢失，要持久化，可以修改<pre class="crayon-plain-tag">/etc/init.d/cpufrequtils</pre> <span style="color: #111111;">脚本</span></p>
<p><span style="background-color: #c0c0c0;">示例：</span></p>
<pre class="crayon-plain-tag"># 设置为最大性能
sudo cpufreq-set -g performance
# 设置为省电模式
sudo cpufreq-set -g powersave

# 设置0号CPU的频率
sudo cpufreq-set -f 2901000</pre>
</td>
</tr>
<tr>
<td class="blog_h2"><a id="nsenter"></a>nsenter</td>
<td>
<p>在其它进程的命名空间中，执行程序。可进入的命名空间包括：mount、UTS、IPC、network、PID、user。
<p><span style="background-color: #c0c0c0;">格式：</span></p>
<pre class="crayon-plain-tag"># 如果不指定program，则运行${SHELL}，默认/bin/sh
nsenter [options] [program [arguments]]</pre>
<p> <span style="background-color: #c0c0c0;">选项：</span></p>
<p>-t 进入哪个PID的命名空间<br />-m, --mount[=file] 进入mount命名空间，如果指定file，则从文件读取命名空间，否则使用PID的mount命名空间<br />-u 进入UTS命名空间<br />-i 进入IPC命名空间<br />-n 进入网络命名空间<br />-p 进入PID命名空间<br />-U 进入User命名空间<br />-G, --setgid gid 进入命名空间后，使用的GID，进入User命名空间总是需要设置GID，默认自动设置为0<br />-S, --setuid uid 进入命名空间后，使用的UID，进入User命名空间总是需要设置UID，默认自动设置为0<br />--preserve-credentials 进入User命名空间后不改变凭证信息，默认行为是设置为0，并且清楚补充组（supplementary groups）<br />-r 设置root目录<br />-w 设置工作目录</p>
</td>
</tr>
<tr>
<td>unshare </td>
<td>
<p>运行应用程序，且不共享父进程的某些命名空间。</p>
<p><span style="background-color: #c0c0c0;">格式：</span></p>
<p>unshare [options] program [arguments]</p>
<p><span style="background-color: #c0c0c0;">选项：</span></p>
<p>-m 取消共享mount命名空间<br />-u 取消共享UTS命名空间<br />-i 取消共享IPC命名空间<br />-n 取消共享网络命名空间<br />-p 取消共享PID命名空间<br />-U 取消共享User命名空间</p>
</td>
</tr>
<tr>
<td>lvm</td>
<td>
<p>逻辑卷管理器（Logical Volume Manager）用于管理“逻辑卷”，专注于<span style="background-color: #c0c0c0;">可弹性的扩缩文件系统的大小</span>，它能够把多个物理分区合并为一个逻辑的卷。</p>
<p><span style="background-color: #c0c0c0;">概念：</span></p>
<p>Physical Volume，PV，物理卷：可供存储LVM的块设备，例如一块磁盘、一个MBR/GPT分区、一个回环文件、一个被内核映射的设备。PV包含一个特殊的LVM头</p>
<p>Volume Group，VG，卷组：一组物理卷，可以作为逻辑卷的容器。物理块从VG中分配出来，分配给LV</p>
<p>Logic Volume，LV，逻辑卷：也叫虚拟卷，由单个VG中的很多物理块组成。行为上类似于物理块设备，你可以在其上创建文件系统</p>
<p>Physical Extent，PE，物理块：VG中最小的连续取于（默认4MiB），多个PE组成LV</p>
<p>下面示例一个由两块磁盘构成的LV：</p>
<pre class="crayon-plain-tag">Physical disks

  Disk1 (/dev/sda):
     _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
    |Partition1 50 GiB (Physical volume) |Partition2 80 GiB (Physical volume)     |
    |/dev/sda1                           |/dev/sda2                               |
    |_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ |_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ |

  Disk2 (/dev/sdb):
     _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
    |Partition1 120 GiB (Physical volume)                 |
    |/dev/sdb1                                            |
    |_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _|




LVM logical volumes

  Volume Group1 (/dev/MyVolGroup/ = /dev/sda1 + /dev/sda2 + /dev/sdb1):
     _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
    |Logical volume1 15 GiB  |Logical volume2 35 GiB      |Logical volume3 200 GiB              |
    |/dev/MyVolGroup/rootvol |/dev/MyVolGroup/homevol     |/dev/MyVolGroup/mediavol             |
    |_ _ _ _ _ _ _ _ _ _ _ _ |_ _ _ _ _ _ _ _ _ _ _ _ _ _ |_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _|</pre>
<p><span style="background-color: #c0c0c0;">命令：</span></p>
<pre class="crayon-plain-tag"># 列出可作为物理卷的设备
lvmdiskscan

# 创建物理卷，此命令将会在设备上创建LVM头
pvcreate /dev/sda2

# 显示物理卷列表
pvdisplay
# 获取所有物理卷
pvs

# 分区增大后，使用下面的命令可以自动扩充PV的大小
pvresize /dev/sda1

# 缩小PV
pvresize --setphysicalvolumesize 40G /dev/sda1

# 移动PV上的数据
pvmove /dev/sdb1
# 指定目标
pvmove /dev/sdb1 /dev/sdf1

# 删除PV，解除LVM头，LVM不会再将其看作是PV
pvremove /dev/sdb1



# 创建卷组
# vgcreate &lt;volume_group&gt; &lt;physical_volume&gt;
vgcreate VolGroup00 /dev/sda2

# 扩大卷组，覆盖（添加）其它物理卷
vgextend VolGroup00 /dev/sdb1

# 你也可以在创建卷组是指定多个物理卷
vgcreate VolGroup00 /dev/sda2 /dev/sdb1 /dev/sdc

# 重命名卷组
vgrename /dev/vg02 /dev/my_volume_group

# 显示卷组列表
vgdisplay
# 获取所有卷组
vgs

# 从VG移除PV
vgreduce myVg /dev/sdb1
# 移除所有空的PV
vgreduce --all vg0



# 创建逻辑卷
# lvcreate -L &lt;size&gt; &lt;volume_group&gt; -n &lt;logical_volume&gt;
lvcreate -L 10G VolGroup00 -n lvolhome
# 随后你可以通过 /dev/VolGroup00/lvolhome 访问此逻辑卷

# 限制逻辑卷仅能位于指定的物理卷上
lvcreate -L 10G VolGroup00 -n lvolhome /dev/sdc1

# 使用卷组中所有剩余空间的LV
lvcreate -l 100%FREE VolGroup00 -n lvolhome

# 显示逻辑卷列表
lvdisplay
# 获取所有逻辑卷
lvs

# 重命名逻辑卷
lvrename /dev/vg02/lvold /dev/vg02/lvnew
# 或者
lvrename vg02 lvold lvnew

# 改变LV大小
# 可能需要先通知物理卷的大小改变了
pvresize /dev/vdb
# 修改逻辑卷大小
lvresize -L +10G --resizefs MyVolGroup/mediavol
lvresize -L 15G --resizefs MyVolGroup/mediavol
lvresize -l +100%FREE --resizefs cinder-volumes/cinder-volumes-pool

# 删除逻辑卷，需要先umount，lsblk获取挂载点列表
lvremove VolGroup00/lvolhome

# 改变逻辑卷属性
vgchange 
  # 激活（ay）或禁用（an）逻辑卷，只有激活的才能作为块设备
  -a|--activate y|n|ay</pre>
</td>
</tr>
<tr>
<td>dmsetup</td>
<td>
<p>Device Mapper的用户空间工具，可以实现低级别的逻辑卷管理
<p><span style="background-color: #c0c0c0;">格式：</span></p>
<pre class="crayon-plain-tag"># 为指定的设备销毁非活动表槽（table slot）中的表
dmsetup clear device_name

# 创建具有指定名称的卷
# 如果操作成功，则设备出现在表中，并且为活动设备创建文件/dev/mapper/device_name
dmsetup create device_name [-u|--uuid uuid] [--addnodeoncreate|--addnodeonresume] 
  # 如果提供table或table_file则加载表并激活，否则从stdin读取表（除非-n）
  [-n|--notable|--table {table|table_file}] [--readahead {[+]sectors|auto|none}]

# 列出设备的live table引用的设备列表
dmsetup deps [-o options] [device_name]

# 打印设备的简要信息
dmsetup info [device_name]
# 格式化打印
dmsetup info -c|-C|--columns [--count count] [--interval seconds] [--nameprefixes] 
  [--noheadings] [-o fields] [-O|--sort sort_fields] [--separator separator] [device_name]

# 将table加载到设备的inactive table  slot
dmsetup load device_name [--table {table|table_file}]

# 列出设备名称
dmsetup ls [--target target_type] [--exec command] [--tree] [-o options]

# 向设备发送消息
dmsetup message device_name sector message

# 确保设备位于/dev/mapper的设备文件节点正确
dmsetup mknodes [device_name]

# 移除设备，移除后dmsetup不能再看见它。正在使用中的设备无法移除
# 使用 --force 会替换掉表，并让所有IO失败
# 使用 --deferred 可以延迟打开中的设备的删除，最后一个用户关闭设备后执行移除
dmsetup remove [-f|--force] [--retry] [--deferred] device_name

# 删除所有设备定义，也就是重置驱动
dmsetup remove_all [-f|--force] [--deferred]

# 重命名设备
dmsetup rename device_name new_name
dmsetup rename device_name --setuuid uuid

# 恢复设备，如果加载了inactive table，则表变为live，退出的IO将重新排队等待处理
dmsetup resume device_name [--addnodeoncreate|--addnodeonresume] [--noflush] 
  [--nolockfs] [--readahead {[+]sectors|auto|none}]

# 管理IO统计信息
dmsetup stats command [options]

# 输出状态信息
dmsetup status [--target target_type] [--noflush] [device_name]

# 暂停设备，任何已经被设备映射的、尚未完毕的IO操作会被flush，
# 后续IO操作将被推迟处理，直到从暂停中恢复
dmsetup suspend [--nolockfs] [--noflush] device_name

# 输出设备的当前的表信息
dmsetup table [--target target_type] [--showkeys] [device_name]

# 打印当前加载的目标信息
dmsetup targets

# 等待直到事件计数器超过event_nr
dmsetup wait [--noflush] device_name [event_nr]

# 等待进行中的IO完成，然后将表替换为新的，让所有新IO请求失败
# 如果操作成，设备的表中引用的所有设备被释放
dmsetup wipe_table device_name [-f|--force] [--noflush] [--nolockfs]</pre>
<p><span style="background-color: #c0c0c0;">示例：</span></p>
<pre class="crayon-plain-tag"># 创建空白文件
# 声明大小10G，实际占用空间（seek）4K
dd if=/dev/zero of=/tmp/data.img bs=1K count=1 seek=10M
# 声明大小100M
dd if=/dev/zero of=/tmp/meta.img bs=1K count=1 seek=100K

# 映射为虚拟（loopback）块设备
losetup /dev/loop10 /tmp/meta.img
losetup /dev/loop11 /tmp/data.img

# 基于上述块设备，创建一个mapped device（thin-provisioning池）
dmsetup create thinpool0 \
#          数据设备起始扇区
#            数据设备结束扇区 * 512 = 10G      
#                               元数据设备
#                                           数据设备     
  --table "0 20971522 thin-pool /dev/loop10 /dev/loop11 \
# 最小可以分配的扇区数
#    最少可用的扇区阈值
#          有1个附加参数
#            附加参数，跳过用0填充的块 
  128 65536 1 skip_block_zeroing"

# 设备 /dev/mapper/thinpool0 现在可用

# 在thinpool0上创建一个thin-provisioning卷
#                                        标识符
dmsetup message thinpool0 0 "create_thin 0"
dmsetup create thinvol0 --table "0 2097152 thin /dev/mapper/thinpool0 0"

# 设备 /dev/mapper/thinvol0 现在可用

# 格式化
mkfs.ext4 /dev/mapper/thinvol0

# 挂载
mkdir /tmp/thinvol
mount /dev/mapper/thinvol0 /tmp/thinvol



# 创建快照
#                                        新设备ID（快照设备）
#                                          旧设备ID，就是上文的thinvol
dmsetup message thinpool0 0 "create_snap 1 0"
# 创建快照设备
dmsetup create thinvol-snap0 \
  --table "0 2097152 thin /dev/mapper/thinpool0 1"</pre>
</td>
</tr>
</tbody>
</table>
<div class="blog_h1"><span class="graybg">诊断与监控命令</span></div>
<table class="full-width fixed-word-wrap" style="width: 100%;" border="1" cellspacing="0" cellpadding="5">
<thead>
<tr>
<td style="width: 100px; text-align: center;">命令</td>
<td style="text-align: center;">说明 </td>
</tr>
</thead>
<tbody>
<tr>
<td class="blog_h2">df</td>
<td>
<p>使用列表的形式显示文件系统的使用状况
<p><span style="background-color: #c0c0c0;">格式：</span><br />df [OPTION]... [FILE]...</p>
<p><span style="background-color: #c0c0c0;">选项：</span><br />-a, --all 包含虚拟文件系统<br />-B, --block-size=SIZE 按SIZE缩放长度单位，-BM表示以1,048,576字节为单位<br />--total 进行总计<br />-h, --human-readable 以可读方式显示容量<br />-H, --si 与-h相似，但是单位转换时使用1000而不是1024<br />-i, --inodes 显示inode信息而不是block用量<br />-k 等价于 --block-size=1K<br />-l, --local 仅显示本地文件系统<br />--no-sync 在获取容量使用情况前不使用sync操作，默认行为<br />--output[=FIELD_LIST] 使用FIELD_LIST来指定输出列<br />-P, --portability 使用POSIX输出格式<br />--sync 在获取容量使用情况前使用sync操作<br />-t, --type=TYPE 限制文件系统的类型<br />-T, --print-type 打印文件系统类型<br />-x, --exclude-type=TYPE 排除文件系统类型</p>
<p><span style="background-color: #c0c0c0;">输出：</span><br />Filesystem　文件系统（分区）<br />1K-blocks　 总计块数量<br />Used　已使用块数量<br />Available　 可用块数量<br />Use%　占用百分比<br />Mounted on　挂载点</p>
<p><span style="background-color: #c0c0c0;">举例：</span></p>
<pre class="crayon-plain-tag">alex@amethystine:~$ df
Filesystem     1K-blocks    Used Available Use% Mounted on
/dev/sda1       81405680 7703348  69544124  10% /
none                   4       0         4   0% /sys/fs/cgroup
udev             3041916       4   3041912   1% /dev
tmpfs             610540    1624    608916   1% /run
none                5120       0      5120   0% /run/lock
none             3052692     152   3052540   1% /run/shm
none              102400      32    102368   1% /run/user</pre>
</td>
</tr>
<tr>
<td class="blog_h2">du</td>
<td>
<p>估算磁盘使用状况。该命令会递归的统计目录下每个文件的磁盘占用情况
<p><span style="background-color: #c0c0c0;">格式：</span><br />du [OPTION]... [FILE]...</p>
<p><span style="background-color: #c0c0c0;">选项：</span><br />-0, --null 使用空字符而不是换行符结束输出的每一行<br />-a, --all 统计所有文件，而不仅仅是目录<br />--apparent-size 统计文件尺寸而不是磁盘占用空间，前者<br />-B, --block-size=SIZE 打印输出前，对尺寸进行缩放<br />-b, --bytes 等价于--apparent-size --block-size=1<br />-c, --total 生成总计信息<br />-D, --dereference-args 仅解引用命令行参数列出的文件的符号链接<br />-d, --max-depth=N 仅打印不超过N级子目录的统计信息<br />-h, --human-readable 使用便于阅读的方式打印输出，例如1K 234M 2G<br />-L, --dereference 解引用所有符号链接<br />-l, --count-links 对于硬链接，出现多次时，分别统计大小<br />-P, --no-dereference 默认，不解引用任何符号连接<br />-S, --separate-dirs 不包含子目录的大小<br />--si 类似于-h，但是使用1000而不是1024作为倍率<br />-s, --summarize 仅显示每个参数的统计信息<br />-t, --threshold=SIZE 如果为负数，则排除大小小于SIZE的条目；如果为正数，则排除大小大于SIZE的条目<br />--time 显示目录和文件的最后修改时间<br />--time-style=STYLE 时间显示格式，参考date命令的日期格式<br />-X, --exclude-from=FILE 排除FILE模式匹配的文件<br />exclude files that match any pattern in FILE</p>
<p><span style="background-color: #c0c0c0;">举例：</span></p>
<pre class="crayon-plain-tag">#显示最大的文件或目录
for i in G M K; do du -ah | grep [0-9]$i | sort -nr -k 1; done | head -n 11
#显示最大子目录
du -cks * | sort -rn | head -10</pre>
</td>
</tr>
<tr>
<td class="blog_h2">lsof</td>
<td>
<p>列出打开的文件<br />这里的文件可能是：普通文件、目录、特殊块文件、特殊字符文件、库、流、网络文件（套接字、NFS文件）<br />如果不提供任何选项lsof会列出当前活动进程打开的所有文件
<p><span style="background-color: #c0c0c0;">格式：</span><br />lsof <br />　　[ -?abChKlnNOPRtUvVX ] [ -A A ] [ -c c ] [ +c c ] [ +|-d d ] <br />　　[ +|-D D ] [ +|-e s ] [ +|-f [cfgGn] ] [ -F [f] ] [ -g [s] ] <br />　　[ -i [i] ] [ -k k ] [ +|-L [l] ] [ +|-m m ] [ +|-M ] [ -o [o]]<br />　　[ -p s ] [ +|-r [t[m]] ] [ -s [p:s] ] [ -S [t] ] [ -T [t] ] <br />　　[ -u s ] [ +|-w ] [ -x [fl] ] [ -z [z] ] [ -Z [Z] ] [ -- ] [names]</p>
<p><span style="background-color: #c0c0c0;">选项：</span><br />-a　各选项指定的条件进行逻辑与<br />-b　避免调用可能导致阻塞的内核函数，例如lstat/readlin/stat<br />-c　c 选择执行的命令以c字符开始的进程，可指定多次（逻辑或）<br />+d　s 列出打开的目录s及其直接包含的文件的实例<br />-d　s 指定需要从输出中排除的文件描述符，逗号分隔，例如'cwd,1,3'，可指定多次（逻辑或）<br />+D　D 列出打开的目录D及其目录层次下任何文件的实例<br />-i　i 列出所有Internet地址匹配i的文件，如果不指定i则列出所有网络文件<br />　　Internet地址格式：[46][protocol][@hostname|hostaddr][:service|port]<br />　　46指定IP地址版本<br />　　protocol指定协议名称，例如TCP/UDP<br />　　hostname指定主机名<br />　　hostaddr指定主机地址<br />　　service指定/etc/services中的服务名称<br />　　port指定端口或者端口的列表<br />-l　禁止将UID转换为用户名<br />-n　禁止将网络地址转换为主机名<br />-P　禁止将端口号转换为知名端口<br />-N　选择NFS文件的列表<br />-p　s包含或选择指定PID打开的文件，例如-p 1022,^3391<br />-R　在PPID列显示父进程ID<br />-U　选择UNIX domain Socket文件<br />-u　列出指定用户打开的文件<br />--　用于指示选项的结束<br />names　需要被列出的文件的路径名</p>
<p><span style="background-color: #c0c0c0;">输出：</span><br />COMMAND　关联到进程的UNIX命令的前9个字符<br />PID　打开文件的进程的ID<br />TID　关联的任务ID<br />PPID　打开文件的进程的父进程的ID<br />PGID　进程组ID<br />USER　进程所属用户的ID或者名称<br />FD　显示文件描述符或者：<br />　　　cwd 当前工作目录<br />　　　err FD信息错误<br />　　　jld FreeBSD的jail目录<br />　　　ltx 共享库文本（代码或数据）<br />　　　Mxx HEX内存映射类型xx<br />　　　m86 DOS合并映射文件<br />　　　mem 内存映射文件<br />　　　mmap 内存映射设备<br />　　　pd 父目录<br />　　　rtd 根目录<br />　　　txt 程序文本（代码或数据）<br />　　　v86 VP/ix映射文件<br />　　FD之后会跟随文件打开方式字符：<br />　　　r 读访问<br />　　　w 写访问<br />　　　u 读写访问<br />　　　 空格表示模式未知且无锁定<br />　　　- 模式未知且有锁定<br />　　打开方式后会跟随一个锁定方式字符：<br />　　　r 部分文件读锁定<br />　　　R 全部文件读锁定<br />　　　w 部分文件写锁定<br />　　　W 全部文件写锁定<br />　　　u 任意长度的读写锁定<br />　　　U 未知类型的锁定<br />　　　 空格表示无锁定<br />TYPE　关联文件的节点类型：GDIR, GREG, VDIR, VREG，或者：<br />　　　IPv4 IPv4套接字<br />　　　IPv6 IPv6套接字<br />　　　ax25 Linux AX.25套接字<br />　　　inet Internet domain 套接字<br />　　　rte AF_ROUTE 套接字<br />　　　sock 未知domain的套接字<br />　　　unix UNIX domain套接字<br />　　　x.25 HP-UX x.25套接字<br />　　　BLK 特殊块文件<br />　　　CHR 特殊字符文件　　<br />　　　DEL 已删除的Linux映射文件　<br />　　　DIR 目录<br />　　　DOOR VDOOR文件<br />　　　FIFO FIFO特殊文件<br />　　　KQUEUE BSD风格的内核事件队列文件<br />　　　LINK 符号链接<br />　　　MPB 多路复用的块文件<br />　　　MPC 多路复用的字符文件<br />　　　PIPE 管道<br />NAME　挂载点的名称、或者文件依存的文件系统或者字符、块设备名称；<br />　　　或者网络文件的本地/远程IP地址：localip:port -&gt; remoteip:port<br />　　　或者本地或远程NFS的挂载点名称；</p>
<p><span style="background-color: #c0c0c0;">举例：</span></p>
<pre class="crayon-plain-tag">#查看占用8080端口的进程
lsof  -i  :8080
#列出所有TCP网络连接信息
lsof  -i tcp
#root打开的全部txt文件
lsof -a -u root -d txt
#如果umount文件系统失败，可以查看谁在使用
lsof /media/kssi
#列出alex打开的所有文件
lsof -u alex
#列出apache或者mysqld打开的文件
lsof -c mysqld -c apache
#列出alex执行的mysql打开的文件
lsof -u alex -c mysql
#列出进程打开的文件
lsof -p 1223,3328</pre>
</td>
</tr>
<tr>
<td class="blog_h2">fuser</td>
<td>
<p>找出使用文件或者套接字的进程<br />在默认显示模式下，每个文件名后面会有一个字母来表示访问类型：<br />c　当前目录 <br />e　可执行文件 <br />f　打开文件 <br />F　打开文件以写入 <br />r　根目录 <br />m　内存映射文件或者共享库
<p><span style="background-color: #c0c0c0;">格式：</span><br />fuser [-fuv] [-a|-s] [-4|-6] [-c|-m|-n space] <br />　　　[ -k [-i] [-M] [-w] [-SIGNAL] ] name ...<br />fuser -l<br />fuser -V</p>
<p><span style="background-color: #c0c0c0;">选项：</span><br />-a　--all　显示命令行指定的所有文件，默认只会显示最少被一个进程使用的文件<br />-c　-m --mount NAME 指定一个被挂载的文件系统，该文件系统所有文件被列出<br />-k　--kill 杀死访问文件的进程，除非指定-SIGNAL，否则会使用SIGKILL信号，fuser不会杀死自己<br />-i　--interactive 在杀死进程前要求用户确认<br />-l　--list-signals 列出所有支持的信号名称<br />-w　仅仅杀死执行写访问的进程<br />-n　--namespace SPACE 指定不同的命名空间：默认file，其它包括udp、tcp<br />-SIGNAL 杀死进程时发送的信号<br />-u　--user 在PID后面附加用户名<br />-v　--verbose 冗长模式<br />-4　--ipv4 仅搜索IPv4套接字<br />-6　--ipv6 仅搜索IPv6套接字</p>
<p><span style="background-color: #c0c0c0;">举例：</span></p>
<pre class="crayon-plain-tag">#杀死所有访问/home文件系统的进程
fuser -km /home
#查看使用631端口的进程
fuser -v 631/tcp</pre>
</td>
</tr>
<tr>
<td class="blog_h2">dstat</td>
<td>
<p>收集系统资源统计信息的综合性工具<br />该工具可以用来替换vmstat/iostat/ifstat
<p><span style="background-color: #c0c0c0;">格式：</span><br />dstat [-afv] [options..] [delay [count]]</p>
<p><span style="background-color: #c0c0c0;">选项/输出：</span></p>
<p>-c --cpu 启用CPU统计：<br />      usr　用户态时间占比<br />      sys　内核态时间占比<br />      idl　空闲时间占比<br />      wai　等待时间占比<br />      hiq　硬件中断次数<br />      siq　软件中断次数</p>
<p>-C 0,3,total 包含CPU0、CPU3和总计的CPU使用情况</p>
<p>&nbsp;</p>
<p>-d --disk 启用磁盘使用情况统计，单位字节</p>
<p>-D total,xvda 包含总计、xvda磁盘使用情况</p>
<p>&nbsp;</p>
<p>-g, --page 启用换页统计情况<br />      in　换入的页个数<br />      out　换出的页个数</p>
<p>&nbsp;</p>
<p>-i --int 启用中断次数的统计</p>
<p>&nbsp;</p>
<p>-l --load 启用平均负载统计<br />      1m 一分钟平均负载<br />      5m 五分钟平均负载<br />      15m 十五分钟平均负载<br />所有类UNIX系统在内核中计算负载，<span style="background-color: #c0c0c0;">完全空闲的计算机负载为0，单CPU的饱和负载为1，8核CPU的饱和负载为8</span>。每个使用/等待CPU的进程导致负载+1，每个终结的进程导致负载-1，如果你<span style="background-color: #c0c0c0;">发动1000个死循环线程，负载就会高达千级别</span>。大部分UNIX系统仅仅统计Running或者Runnable（等待被调度）进程，但是<span style="background-color: #c0c0c0;">Linux也将不可中断睡眠的进程（通常在等待磁盘活动完成）统计进来</span>。这意味着，在Linux系统中，卡死的磁盘IO（例如NFS太慢、硬盘坏道、USB 1.0）可能导致负载畸高的同时CPU占用较低</p>
<p>当单CPU的<span style="background-color: #c0c0c0;">负载达到0.7，需要警惕；持续大于1.0，需要尽快找到原因并降下来</span>；大于5.0意味着系统问题严重，接近死机</p>
<p>在单CPU系统中，平均负载1.73 0.60 7.98意味着：</p>
<ol>
<li>最近1分钟，系统超载73%。如果CPU每分钟内最多处理100进程，这意味着最近一分钟它需要处理的进程为173，需要再用一分钟才能处理完</li>
<li>（CPU、磁盘、内存...）速度快1.73倍，它就可以处理完最近一分钟调度的工作</li>
<li>最近5分钟，系统平均有40%的时间空闲</li>
<li>最近15分钟，系统超载698%，7.98的可运行进程</li>
</ol>
<p>&nbsp;</p>
<p>-m --mem 启用内存统计<br />      used　已经使用的内存<br />      buff　系统缓冲区（块设备I/O缓冲）占用内存<br />      cach　已缓存（在内存中的页）的内存<br />      free　空闲的内存</p>
<p>&nbsp;</p>
<p>-n --net 启用网络统计，单位字节<br />      recv　接收数据量<br />      send　发送数据量</p>
<p>-N eth0,total 包含eth0、总计的网络统计</p>
<p>&nbsp;</p>
<p>-p --proc 启用进程统计<br />      run　处于可运行（不一定占用CPU）状态的占比<br />      blk　不可中断睡眠（阻塞）状态的占比<br />      new　新启动进程占比</p>
<p>&nbsp;</p>
<p>-r, --io 启用I/O请求统计，针对所有块设备的IO请求次数<br />      read　读请求<br />      writ　写请求</p>
<p>&nbsp;</p>
<p>-s, --swap<br />      used　已使用的交换分区<br />      free　空闲的交换分区</p>
<p>-S swap1,total 包含swap1、总计的交换分区统计</p>
<p>&nbsp;</p>
<p>-t, --time 输出系统时间</p>
<p>-T, --epoch 输出1970到现在的秒数</p>
<p>&nbsp;</p>
<p>-y, --sys 启用系统统计<br />      int　中断次数<br />      csw　上下文切换次数</p>
<p>&nbsp;</p>
<p>--aio 启用异步I/O统计</p>
<p>&nbsp;</p>
<p>--fs 启用文件系统统计</p>
<p>&nbsp;</p>
<p>--ipc 启用进程间通信统计<br />      msg　消息队列<br />      sem　信号量<br />      shm　共享内存</p>
<p>&nbsp;</p>
<p>--lock 启用文件锁定统计<br />      pos　posix锁<br />      lck　flock锁<br />      rea　读锁<br />      wri　写锁</p>
<p>&nbsp;</p>
<p>-raw 启用原始套接字统计</p>
<p>--socket 启用套接字统计<br />      tot　统计<br />      tcp　TCP<br />      udp UDP<br />      raw RAW<br />      frg IP分片</p>
<p>--tcp 启用TCP统计<br />      lis　处于监听状态的个数<br />      act　建立的连接个数<br />      syn　处于SYN阶段的连接个数<br />      tim　本端已关闭，正在等待网络上数据报的连接个数　<br />      clo　关闭的连接个数</p>
<p>--udp 启用UDP统计enable udp stats (listen, active)<br />      lis　处于监听状态的个数<br />      act　活动的个数</p>
<p>--unix 启用UNIX套接字统计</p>
<p>&nbsp;</p>
<p>--list 列出内部外部插件的名称<br />-a --all 等价于-cdngy，默认开启此选项<br />-f, --full 完整格式，单独显示各网卡和硬盘<br />-v, --vmstat 等价于 -pmgdsc -D total<br />--float 强制显示浮点数<br />--integer 强制显示整数<br />--bw, --blackonwhite 如果Terminal背景为白色，使用该选项调整配色<br />--nocolor 禁用配色<br />--noheaders 禁用重复的表头显示<br />--noupdate 禁止立即刷新，如果delay大于1<br />--output file 输出CSV格式到文件</p>
<p>delay 刷新延迟，默认1秒<br />count 退出前刷新的次数，默认无限</p>
<p><span style="background-color: #c0c0c0;">示例：</span></p>
<pre class="crayon-plain-tag"># 各项系统指标，每分钟显示新行
dstat -tlcmsgdrnpy 60
# 网络相关指标
dstat -tn --socket --tcp --udp --unix 60</pre>
</td>
</tr>
<tr>
<td class="blog_h2">vmstat</td>
<td>
<p>显示虚拟内存的统计信息<br /><span style="background-color: #c0c0c0;">输出：</span><br />procs组：<br />　　r表示等待CPU时间的进程数<br />　　b表示处于不可中断睡眠（等待I/O）的线程数<br />memory组：<br />　　swpd交换到磁盘的块数<br />　　free表示空闲内存块数<br />　　buff表示用于缓冲区的块数<br />　　cache表示用于系统缓存的块数<br />swap组：<br />　　si表示每秒交换进内存的块数<br />　　so表示每秒交换出内存的块数，通常不应该超过10<br />io组：<br />　　bi表示每秒读出块数<br />　　bo表示每秒写入块数<br />system组：<br />　　in表示每秒中断数<br />　　cs表示每秒上下文切换数<br />cpu组： <br />　　us表示运行用户代码（非内核）占比<br />　　sy表示运行系统（内核）代码占比<br />　　id表示空闲占比，wa表示等待I/O占比<br />　　st在虚拟化时表示从虚拟机“偷来”的时间占比
<p>注意：统计按块为单位，GNU/Linux一般为1024字节</p>
</td>
</tr>
<tr>
<td class="blog_h2">pidstat</td>
<td>
<p>报告进程（任务）的统计信息</p>
<p><span style="background-color: #c0c0c0;">格式：</span><pre class="crayon-plain-tag">pidstat options interval count</pre></p>
<p><span style="background-color: #c0c0c0;">选项：</span></p>
<p>-C comm，仅仅显示其命令行包含指定字样的任务的统计信息<br /><span style="background-color: #c0c0c0;">-d 报告磁盘I/O统计信息</span><br /><span style="background-color: #c0c0c0;">-r 报告页面错误和内存使用</span><br /><span style="background-color: #c0c0c0;">-s 报告栈使用情况</span><br /><span style="background-color: #c0c0c0;">-u  报告CPU使用情况</span><br /><span style="background-color: #c0c0c0;">-w 报告上下文切换情况</span><br />-I 在SMP环境下，提示任务的CPU用量应该被除以CPU总数<br />-l 显示进程的完整命令<br />-p 逗号分割，需要报告的PID<br />-T TASK|CHILD|ALL，TASK表示报告每个进程本身、CHILD表示报告进程+子进程，ALL表示同时报告TASK和CHILD<br />-t 同时显示进程的线程的统计信息</p>
</td>
</tr>
<tr>
<td class="blog_h2">free</td>
<td>显示系统的空闲内存</td>
</tr>
<tr>
<td class="blog_h2">iotop</td>
<td>
<p>显示磁盘使用最高的进程，动态刷新</p>
<p>输出列包括在采样周期内：每个进程/线程读写所占用的带宽、每个线程在等待换页、等待IO所消耗的时间百分比（相对于自己的总时间，因此可能有多个进程同时高达99%），每个进程的IO优先级（类型/级别）也会显示</p>
<p>同时输出的还包括统计信息：</p>
<p style="padding-left: 30px;">总磁盘读写，进程/内核线程与内核块设备子系统之间的总计带宽<br />实际磁盘读写，内核块设备子系统与底层硬件（HDD/SSD）之间的实际带宽</p>
<p>由于IO重排序、缓存的存在，实际磁盘读写、总磁盘读写会不一样</p>
<p>快捷键：Left Right切换排序方式、r倒序显示、p切换进程/线程模式、o仅仅显示实际正在IO的进程、i调整IO优先级（ionice）</p>
</td>
</tr>
<tr>
<td class="blog_h2">iostat</td>
<td>
<p>显示输入输出统计信息。该命令的数据源是/proc/diskstats：</p>
<pre class="crayon-plain-tag">cat /proc/diskstats 
   8       0 sda 72447 130694 1438586 11132 14 0 8 88 0 10068 11148
   8       1 sda1 311 4798 7160 36 0 0 0 0 0 28 36
   8       2 sda2 71622 125896 1427320 11052 0 0 0 0 0 9956 10980
   8       3 sda3 364 0 2906 36 1 0 8 0 0 36 36
   8      16 sdb 12186 206560 907224 63264 6085 523283 4234488 2478428 0 74192 2541680
   8      17 sdb1 12008 206560 905800 63048 6028 523283 4234488 2474144 0 69692 2537180</pre>
<p>一共11个字段，除了字段9之外，都从系统启动以来一直累加：</p>
<ol>
<li>rd_ios：读操作的次数。</li>
<li>rd_merges：合并读操作的次数。如果两个读操作读取相邻的数据块时，可以被合并成一个，以提高效率</li>
<li>rd_sectors：读取的扇区数量</li>
<li>rd_ticks：读操作消耗的时间（以毫秒为单位）。每个读操作从__make_request()开始计时，到end_that_request_last()为止，<span style="background-color: #c0c0c0;">包括了在队列中等待的时间</span></li>
<li>wr_ios：写操作的次数</li>
<li>wr_merges：合并写操作的次数</li>
<li>wr_sectors：写入的扇区数量</li>
<li>wr_ticks：写操作消耗的时间（以毫秒为单位）</li>
<li>in_flight：当前未完成的I/O数量。在I/O请求进入队列时该值加1，在I/O结束时该值减1。是I/O请求进入队列时，而不是提交给硬盘设备时，因此不考虑IO请求合并</li>
<li>io_ticks：该设备用于处理I/O的墙上时间，注意io_ticks与rd_ticks和wr_ticks的区别，rd_ticks和wr_ticks是把<span style="background-color: #c0c0c0;">每一个I/O所消耗的时间累加</span>在一起，因为硬盘设备通常可以并行处理多个I/O，所以rd_ticks和wr_ticks往往会比墙上大。而io_ticks表示该设备有I/O（即非空闲）的时间，不考虑I/O有多少，只考虑有没有。在实际计算时，in_flight)不为零的时候io_ticks保持计时，in_flight为零的时候io_ticks停止计时</li>
<li>time_in_queue：对io_ticks的加权值，用当前的I/O数量in-flight乘以墙上时间。虽然该字段的名称是time_in_queue，但<span style="background-color: #c0c0c0;">并不真的只是在队列中的时间，其中还包含了硬盘处理I/O的时间</span>。iostat在计算avgqu-sz时会用到这个字段</li>
</ol>
<p>更多信息参考：<a href="http://linuxperf.com/?p=156">http://linuxperf.com/?p=156</a></p>
<p><span style="background-color: #c0c0c0;">选项：</span></p>
<p>-c 显示CPU利用情况报告<br />-d 显示设备利用情况报告<br />-g 限制指定设备组的统计信息<br />-h 让报告更加易读<br />-k 以KB为单位<br />-m 以MB为单位<br />-p 显示指定的块设备和它的分区的统计信息</p>
<p><span style="background-color: #c0c0c0;">输出：</span><br />rrqm/s wrqm/s <br />表示每秒被合并（OS把队列中的多个逻辑读写请求分组到单个物理读写）的读、写请求<br />r/s w/s <br />每秒发送到设备的读写请求数<br />rsec/s wsec/s 每秒读写的扇区数（扇区是磁盘读写的基本单位，磁盘表面的同心圆曰磁道，磁道的上512字节的弧段曰扇区。现代磁盘的扇区大小可能为4K。Windows下磁盘最小逻辑管理单位叫簇，由若干个扇区组成。NTFS文件系统默认簇大小为4K）<br />rkB/s wkB/s <br />每秒读写的KB数<br />avgrq-sz <br />平均每次设备I/O操作的数据大小 (扇区)<br />avgqu-sz <br />在设备队列中等待的请求数（平均I/O队列长度）<br />await <br />平均每次设备I/O操作的等待的毫秒数<br />svctm <br />平均每次设备I/O操作的服务请求的毫秒数（排除队列等待时间），<span style="background-color: #c0c0c0;">该指标没有价值，可以忽略</span><br />%util <br />一秒中有百分之多少的时间用于I/O操作，或者说一秒中有多少时间I/O队列是非空的。对于串行处理请求的设备，此值接近100%意味着设备能力饱和；对于<span style="background-color: #c0c0c0;">RAID阵列或现代SSD则不能体现出设备的性能限制</span></p>
<p><span style="background-color: #c0c0c0;">示例：</span></p>
<pre class="crayon-plain-tag"># 每秒刷新
iostat -xd 1

# 显示磁盘SDC的TPS、每秒读写KB数
iostat 1 -d -h -y -k -p sdc</pre>
</td>
</tr>
<tr>
<td class="blog_h2">top </td>
<td>
<p>显示CPU占用最高的进程，动态刷新
<p><span style="background-color: #c0c0c0;">命令：</span></p>
<p>d 刷新延迟 H 显示线程 B 粗体显示 z 彩色显示 <br />l 系统负载  t 处理器状态 1按核显示处理器状态 m 内存和交换文件<br />c 显示完整命令 i 显示空闲任务 R 反转排序  V树状显示</p>
<p><span style="background-color: #c0c0c0;">选项：</span></p>
<p>-PN1,N2... 仅仅显示指定进程<br />-H 显示每个线程</p>
<p><span style="background-color: #c0c0c0;">输出：</span></p>
<p>CPU状态：us非niced用户进程耗时，sy内核进程耗时，ni被niced用户进程耗时，id空闲的时间，wa等待IO操作完成消耗的时间，hi处理硬件中断的时间，si处理软件中断的时间，st当前vm被hypervisor偷去的时间</p>
<p>wa应该<span style="background-color: #c0c0c0;">在绝大部分时间内都是0</span>，它表示CPU花在等待IO的时间，如果长时间超过1%提示磁盘IO性能不足</p>
<p><span style="background-color: #c0c0c0;">其它：</span></p>
<p>关于系统负载（load average）：</p>
<ol>
<li><span style="background-color: #c0c0c0;">状态为运行（R）和不可中断睡眠（D）的进程，贡献系统负载</span></li>
</ol>
</td>
</tr>
<tr>
<td class="blog_h2">mpstat</td>
<td>
<p>报告CPU相关的统计信息</p>
<p><span style="background-color: #c0c0c0;">格式：</span></p>
<p>mpstat [ -A ] [ -u ] [ -V ] [ -I { keyword [,...] | ALL } ] [ -P { cpu [,...] | ON | ALL } ] [ interval [ count ] ]</p>
<p><span style="background-color: #c0c0c0;">选项：</span></p>
<p>-A 等价于 -u -I ALL -P ALL<br />-P 指定需要报告的CPU<br />-u 报告CPU用量</p>
<p><span style="background-color: #c0c0c0;">输出：</span></p>
<p>CPU CPU序号，all表示所有CPU的均值<br />%usr 执行用户空间代码消耗的CPU时间占比<br />%nice 执行用户空间并且使用nice优先级的代码耗时占比<br />%sys 执行内核空间代码消耗的CPU时间占比，不包含处理硬件/软件中断的时间<br />%iowait 系统中存在进行中的IO请求，同时CPU空闲的时间占比<br />%irq 处理硬件中断的CPU时间占比<br />%soft 处理软件中断的CPU时间占比<br />%steal  虚拟CPU消耗在非自愿等待的、同时Hypervisor用来执行其它虚拟处理器的时间占比<br />%guest 执行虚拟CPU的时间占比<br />%gnice 执行niced客户机的CPU时间占比<br />%idle 空闲，且没有进行中IO请求的时间占比</p>
<p>注意：</p>
<ol>
<li>%usr + %nice + %sys + %iwoait + %irq + %soft + %steal + %guest + %gnice + %idle = 100%</li>
<li>%iowait不代表CPU不能工作，也不代表存在IO瓶颈。判定是否存在IO瓶颈，应当结合iostat的avserv/avwait/avque等指标</li>
</ol>
</td>
</tr>
<tr>
<td class="blog_h2">atop</td>
<td>
<p>交互式的系统负载监视器，它能够直观的监控最重要的系统硬件资源的使用情况，还能显示哪些进程应该为高资源占用负责</p>
<p>注意：</p>
<ol>
<li>必须启用内核特性storage accounting才能按进程显示磁盘负载</li>
<li>必须安装netatop内核模块才能按进程显示网络负载</li>
</ol>
<p>程序界面每10秒</p>
</td>
</tr>
<tr>
<td class="blog_h2">htop</td>
<td>
<p>显示CPU占用最高的进程，动态刷新，比top提供更多的信息</p>
<p><span style="background-color: #c0c0c0;">状态条：</span></p>
<p>CPU：蓝色代表低优先级线程；绿色代表正常优先级线程；红色代表内核线程</p>
<p>MEM：绿色代表已使用内存页；蓝色代表缓冲(Buffer)页；黄色代表缓存(Cache)页</p>
<p>Load average：包含3个，分别为最近1/5/15分钟的平均负载。所谓负载使用浮点数表示，如果服务器具有4个核心，那么负载达到4.00相当于满载，如果负载达到20.00意味着严重超载，进程等待CPU时间将过长</p>
<p><span style="background-color: #c0c0c0;">选项：</span><br />-d　刷新间隔，单位秒<br />-C　不使用配色<br />-p　--pid=PID,PID... 仅显示给定的PID<br />-s　--sort-key COLUMN 指定排序列<br />-u　--user=USERNAME 仅显示指定用户的进程</p>
<p><span style="background-color: #c0c0c0;">输出：</span><br />Command 完整的进程命令行<br />PID 进程ID<br />PPID 父进程ID<br />PGRP 进程组ID<br />SESSION (SESN) 进程会话ID<br />TTY_NR (TTY) 进程关联的中断<br />TPGID 控制进程的中断的前台进程组的ID<br />STATE (S) 进程状态：<br />　　S 休眠进程（idle）<br />　　R 运行中的进程<br />　　D 不可中断的等待（I/O）<br />　　Z 僵尸（等待父进程读取其退出转变港台）</p>
<p>PROCESSOR (CPU) 　进程最后在哪个CPU执行<br />NLWP 　进程包含的线程数量<br />NICE (NI) 　进程的nice值，从19到-20（数字越小优先级越高）<br />PERCENT_CPU (CPU%) 　进程占用的CPU百分比<br />UTIME (UTIME+) 　用户态CPU执行时间<br />STIME (STIME+)　 内核态CPU执行时间<br />TIME (TIME+)　 用户态、内核态时间总和<br />CUTIME 　子进程的用户态CPU执行时间<br />CSTIME 　子进程的内核态CPU执行时间<br />PRIORITY (PRI)　 内核给进程的内部优先级<br />PERCENT_MEM（MEM%）　 进程占用的内存百分比，基于驻留集RES计算<br />M_SIZE (VIRT)　 整个程序的虚拟内存大小，包含没有映射到内存的页。单位KB<br />M_RESIDENT (RES)　 驻留集尺寸，实际占用物理内存大小<br />M_SHARE (SHR) 　共享页的尺寸，即RES中与其它进程共享的部分<br />M_TRS (CODE) 　进程代码段尺寸，即程序可执行代码的大小<br />M_LRS (LIB) 　进程使用的库占用的尺寸<br />M_DRS (DATA) 　进程数据段+栈的尺寸<br />M_DT (DIRTY) 　进程脏页数量<br />ST_UID (UID) 　进程所有者的UID<br />TARTTIME 　进程启动以来流逝的时间<br />RCHAR (RD_CHAR)　 进程已经读取的字节数<br />WCHAR (WR_CHAR) 　进程已经写入的字节数<br />SYSCR (RD_SYSC)　 read系统调用的次数<br />SYSCW (WR_SYSC) 　write系统调用的次数<br />RBYTES (IO_RBYTES)　 read调用读取的字节数<br />WBYTES (IO_WBYTES) 　write调用写入的字节数<br />IO_READ_RATE (IORR) 　read调用速率，单位KB/s<br />IO_WRITE_RATE (IOWR)　 write调用速率，单位KB/s<br />IO_RATE (IO) 前两者之和，单位KB/s<br />CNCLWB (IO_CANCEL) 　取消的write字节数</p>
</td>
</tr>
<tr>
<td class="blog_h2">ps</td>
<td>
<p>报告一个当前进程的状态快照</p>
<p><span style="background-color: #c0c0c0;">格式：</span><br />ps [options]</p>
<p><span style="background-color: #c0c0c0;">选项：</span><br /><span style="background-color: #c0c0c0;">简单进程选择：</span><br />-A -e 选择所有进程<br />-a 选择除了作为session leader的进程和未关联Terminal的进程<br />a  BSD风格的“仅当前用户的”约束<br />-d 选择除了作为session leader的进程<br />-N --deselect 选择所有不满足条件的进程<br /><span style="background-color: #c0c0c0;">列表进程选择：</span><br />这些选项支持单个以空格或逗号分隔的参数，并且可以指定多次<br />-p --pid 按PID选择，100、-100、-p 100这三种语法都可以<br />-C 根据命令名称选择<br />-G --Group 根据真实GID选择<br />-g --group 根据有效GID选择<br />--ppid 根据父进程PID选择<br />-s --sid 根据会话ID选择<br />-t --tty 根据tty选择，-t -用于选择没有关联到任何终端的进程<br />-U 根据真实UID选择<br />-u 根据有效UID选择</p>
<p><span style="background-color: #c0c0c0;">输出格式控制：</span><br />-f 输出完整格式<br />-F 输出特别完整格式<br />v 显示虚拟内存信息<br />Z 显示寄存器信息<br />-o 使用用户自定义格式<br />--no-headers  不输出表头</p>
<p><span style="background-color: #c0c0c0;">自定义格式：</span></p>
<p>%cpu  CPU用量<br />%mem 内存用量<br />args  命令行及其参数，别名command</p>
<p><span style="background-color: #c0c0c0;">示例：</span></p>
<pre class="crayon-plain-tag"># 显示完整的命令行
ps -ef    # 标准语法
ps aux    # BSD语法

# 显示所有JVM的命令行
jcmd -l | awk '{system("ps --no-headers -p "$1 " -o command " ) }'</pre>
</td>
</tr>
<tr>
<td class="blog_h2">pstree</td>
<td>
<p>显示进程树
<p>格式：</p>
<p><span style="background-color: #c0c0c0;">选项：</span></p>
<p>-a 显示命令行参数<br /> -h 高亮当前进程及其祖先<br /> -H PID 高亮指定进程及其祖先<br /> -l  不要截断过长的行<br /> -n 根据PID对输出排序<br /> -p  显示PID，后面跟PID则仅仅显示子树</p>
<p><span style="background-color: #c0c0c0;">示例：</span></p>
<pre class="crayon-plain-tag"># 显示以进程24741为根节点的子树
pstree -an -p 24741</pre>
</td>
</tr>
<tr>
<td> exportfs</td>
<td>
<p>修改了NFS导出配置后，使用该命令生效：
<pre class="crayon-plain-tag"># 执行导出
exportfs -ar

# 查看导出
exportfs -v</pre>
<p>导出配置示例：</p>
<pre class="crayon-plain-tag">/srv/nfs4          10.0.0.0/8(rw,sync,no_subtree_check,crossmnt,fsid=0)
/srv/nfs4/fast     10.0.0.0/16(rw,sync,no_subtree_check) 10.1.0.0/16(rw,sync,no_subtree_check)
/srv/nfs4/slow     10.0.0.0/16(rw,sync,no_subtree_check) 10.1.0.0/16(rw,sync,no_subtree_check)</pre>
</td>
</tr>
<tr>
<td class="blog_h2">iftop</td>
<td>
<p>显示网络使用最高的套接字，动态刷新
<p><span style="background-color: #c0c0c0;">格式：</span><br />iftop -h | [-nNpblBP] [-i interface] <br />[-f filter code] [-F net/mask] [-G net6/mask6]</p>
<p><span style="background-color: #c0c0c0;">选项：</span><br />-h 打印帮助<br />-n 不进行DNS查找<br />-N 不解析著名端口名<br />-p 运行在混杂模式，不直接发送给目标接口的流量也被统计<br />-P 启用端口显示<br />-l 显示并统计本地IPv6数据报，默认不显示<br />-b 不显示流量的bar图<br />-B 使用bytes/s作为单位而不是bits/sec<br />-i interface 监听指定网络接口上的流量<br />-f filter code 设置过滤器<br />-F net/mask 指定流量分析的IPv4网络范围<br />-G net6/mask6 指定流量分析的IPv6网络范围<br />-c config file 指定配置文件</p>
<p><span style="background-color: #c0c0c0;">输出：</span><br />顶部显示瞬时速度的标尺，其下面是占用网络带宽最高的套接字列表：</p>
<pre class="crayon-plain-tag">#按p可以显示或者隐藏端口号
#按1,2,3,4可以按对应的列排序，按&lt;&gt;分别根据源、目标排序
#按P暂停刷新，按o可以冻结当前顺序
#按f可以动态修改过滤器
#默认显示最近10秒流量占用最高的套接字
#从foo到bar最近1/10/40秒平均速率
foo.com  =&gt;  bar.com      1Kb  500b   100b
                 &lt;=       2Mb    2Mb    2Mb
                 
#底部显示发送（TX）、接收（RX）和合计的信息
#包括bar图、累计（cum）、峰值（peak）以及1/10/40统计
TX:    cum: 27.5MB   peak: 141kb  rates: 2.67kb  4.87kb  18.3kb
RX:         2.18MB         129kb         1.66kb  2.19kb  13.7kb
TOTAL:      29.7MB         174kb         4.33kb  7.06kb  32.1kb</pre>
<p><span style="background-color: #c0c0c0;">示例：</span></p>
<pre class="crayon-plain-tag">iftop -nNBPi eth0</pre>
</td>
</tr>
<tr>
<td class="blog_h2">dmesg</td>
<td>打印内核诊断信息，或者操控内核ring buffer</td>
</tr>
<tr>
<td class="blog_h2">uptime</td>
<td>显示已经系统运行的时间</td>
</tr>
<tr>
<td class="blog_h2">sysbench</td>
<td>
<p>一个跨平台、多线程、模块化的性能测试工具。可以测试：文件I/O性能、内存分配和传输速率、POSIX线程性能、数据库服务器性能等方面的内容
<p><span style="background-color: #c0c0c0;">命令格式：</span></p>
<pre class="crayon-plain-tag">sysbench [common-options] --test=name [test-options] command</pre>
<p><span style="background-color: #c0c0c0;">通用选项：</span></p>
<p>--num-threads 工作线程总数，默认1<br />--max-requests 最大请求次数，默认10000，0表示无限<br />--max-time 测试最大执行的秒数<br />--thread-stack-size 线程的栈大小，默认32K<br />--init-rnd 是否在测试启动前，从定时器初始化随机数生成器<br />--test 指定测试模式<br />--debug 打印调试信息<br />--validate 如果可能，验证测试结果<br />--percentile 保留测试数据的百分比，默认95%，意味着耗时最长的5%测试数据被丢弃<br />--batch 批量模式，周期性的产生测试结果<br />--batch-delay 两次执行之间延迟的秒数</p>
<p><span style="background-color: #c0c0c0;">测试模式：</span></p>
<p>cpu 通过寻找质数，来测试CPU性能<br />  --cpu-max-primes 寻找质数的最大数量<br />threads 用于测试内核在大量线程竞争一组互斥量时的调度性能<br />  --thread-locks 互斥量的数量，默认8<br />  --thread-yield  每次请求执行lock/yield/unlock循环的数量，默认1000<br />fileio 根据多种I/O工作负载，测试I/O性能。分为prepare、run两个阶段。prepare阶段创建一系列待测试文件<br />  --file-test-mode 测试模式：seqwr顺序写、seqrewr顺序重写、seqrd顺序读、rndrd随机读、rndwr随机写、rndrw随机读写<br />  --file-io-mode  I/O模式：sync同步、async异步、fastmmap快速内存映射、slowmmap内存映射<br />  --file-num 创建的文件数量，默认128<br />  --file-block-size 读写时的块大小，默认16K<br />  --file-total-size 总计文件大小，默认2G<br />  --file-async-backlog 每个线程可以有多少异步操作排队<br />  --file-fsync-freq 在多少次请求后，执行fsync()<br />  --file-fsync-all 是否在每次操作后执行fsync()，默认no<br />  --file-fsync-end 是否在测试结束后执行fsync()，默认yes<br />  --file-fsync-mode fsync模式：fsync、fdatasync<br />  --file-merged-requests 最多合并多少I/O请求，默认不合并</p>
<p><span style="background-color: #c0c0c0;">举例：</span></p>
<pre class="crayon-plain-tag"># CPU性能测试
sysbench --test=cpu --cpu-max-prime=1000000 --num-threads=8 run
# I/O性能测试
sysbench --num-threads=16 --test=fileio --file-total-size=3G --file-test-mode=rndrw prepare
sysbench --num-threads=16 --test=fileio --file-total-size=3G --file-test-mode=rndrw run
sysbench --num-threads=16 --test=fileio --file-total-size=3G --file-test-mode=rndrw cleanup
# MySQL数据插入
sysbench --mysql-host=127.0.0.1 --mysql-user=root --mysql-password=pswd --tables=1 \
    --table_size=100000000000 oltp_read_write prepare</pre>
</td>
</tr>
<tr>
<td class="blog_h2">fio</td>
<td>
<p>fio是测试IOPS的工具，用来对硬件进行压力测试和验证
<p><span style="background-color: #c0c0c0;">安装：</span></p>
<pre class="crayon-plain-tag">wget https://codeload.github.com/axboe/fio/zip/master
unzip master
rm -rf master
cd fio-master/
./configure
make &amp;&amp; make install</pre>
<p><span style="background-color: #c0c0c0;">格式：</span><pre class="crayon-plain-tag">fio [options] [jobfile]...</pre></p>
<p><span style="background-color: #c0c0c0;">示例：</span></p>
<pre class="crayon-plain-tag">filename=/dev/sdb1   # 测试文件名称，通常选择需要测试的盘的data目录
direct=1             # 测试过程绕过机器自带的buffer。使测试结果更真实
rw=randwrite         # 测试随机写的I/O
rw=randrw            # 测试随机写和读的I/O
bs=16k               # 单次io的块文件大小为16k
bsrange=512-2048     # 同上，提定数据块的大小范围
size=5G              # 本次的测试文件大小为5g，以每次4k的io进行测试
numjobs=30           # 本次的测试线程为30个
runtime=1000         # 测试时间1000秒，如果指定则将5g文件分4k每次写完即结束
ioengine=psync       # io引擎使用psync方式
rwmixwrite=30        # 在混合读写的模式下，写占30%
group_reporting      # 关于显示结果的，汇总每个进程的信息
lockmem=1G           # 只使用1g内存进行测试
zero_buffers         # 用0初始化系统buffer
nrfiles=8            # 每个进程生成文件的数量

# 顺序读
fio -filename=/dev/rbd1 -direct=1 -iodepth 1 -thread -rw=read -ioengine=psync -bs=16k -size=512M -numjobs=30 -runtime=60 -group_reporting -name=test
# 顺序写
fio -filename=/dev/rbd1 -direct=1 -iodepth 1 -thread -rw=write -ioengine=psync -bs=16k -size=512M -numjobs=30 -runtime=60 -group_reporting -name=test
#随机读
fio -filename=/dev/rbd1 -direct=1 -iodepth 1 -thread -rw=randread -ioengine=psync -bs=16k -size=512M -numjobs=30 -runtime=60 -group_reporting -name=test
# 随机写
fio -filename=/dev/rbd1 -direct=1 -iodepth 1 -thread -rw=randwrite -ioengine=psync -bs=16k -size=512M -numjobs=30 -runtime=60 -group_reporting -name=test
# 混合随机读写
fio -filename=/dev/rbd1 -direct=1 -iodepth 1 -thread -rw=randrw -rwmixread=70 -ioengine=psync -bs=16k -size=512M -numjobs=30 -runtime=60 -group_reporting -name=test -ioscheduler=noop</pre>
</td>
</tr>
<tr>
<td class="blog_h2">iperf3</td>
<td>
<p>网络吞吐量测试工具
<p><span style="background-color: #c0c0c0;">格式：</span></p>
<pre class="crayon-plain-tag"># 服务器
iperf3 -s [ options ]
# 客户端
iperf3 -c server [ options ]</pre>
<p><span style="background-color: #c0c0c0;">示例：</span></p>
<pre class="crayon-plain-tag"># 启动一个服务器
iperf3 -s
# 连接到服务器进行网速测试
iperf3 -c 10.0.1.1</pre>
</td>
</tr>
<tr>
<td>sysdig<a id="sysdig"></a></td>
<td>参考<a href="/sysdig">使用Sysdig进行系统性能分析</a></td>
</tr>
</tbody>
</table>
<div id="dev-commands" class="blog_h1"><span class="graybg">开发相关命令</span></div>
<table class="full-width fixed-word-wrap">
<thead>
<tr>
<td style="width: 100px; text-align: center;"> 命令</td>
<td style="text-align: center;">说明 </td>
</tr>
</thead>
<tbody>
<tr>
<td class="blog_h2">pkg-config</td>
<td>
<p>参考<a href="/linux-programming-faq#pkgcfg">Linux编程知识集锦</a>
</td>
</tr>
<tr>
<td class="blog_h2">ldconfig</td>
<td>
<p>参考<a href="/linux-programming-faq#ldconfig">Linux编程知识集锦</a></p>
</td>
</tr>
<tr>
<td class="blog_h2">ldd</td>
<td>
<p>参考<a href="/linux-programming-faq#ldd">Linux编程知识集锦</a></p>
</td>
</tr>
<tr>
<td class="blog_h2">objdump</td>
<td>
<p>参考<a href="/linux-programming-faq#objdump">Linux编程知识集锦</a></p>
</td>
</tr>
<tr>
<td class="blog_h2">gcc</td>
<td>
<p>参考<a href="/linux-programming-faq#gcc">Linux编程知识集锦</a></p>
</td>
</tr>
<tr>
<td class="blog_h2">gdb</td>
<td>
<p>参考<a href="/linux-programming-faq#gdb">Linux编程知识集锦</a></p>
</td>
</tr>
<tr>
<td class="blog_h2">gdbserver</td>
<td>
<p>参考<a href="/linux-programming-faq#gdbserver">Linux编程知识集锦</a></p>
</td>
</tr>
<tr>
<td class="blog_h2">adb</td>
<td>参见<a href="/android-faq#adb">Android知识集锦</a></td>
</tr>
<tr>
<td class="blog_h2">keytool</td>
<td>参见<a href="/android-faq#keytool">Android知识集锦</a></td>
</tr>
<tr>
<td class="blog_h2">jarsigner</td>
<td>参见<a href="/android-faq#jarsigner">Android知识集锦</a></td>
</tr>
<tr>
<td class="blog_h2">apktool</td>
<td>参见<a href="/android-faq#apktool">Android知识集锦</a></td>
</tr>
<tr>
<td class="blog_h2">dex2jar</td>
<td>参见<a href="/android-faq#dex2jar">Android知识集锦</a></td>
</tr>
<tr>
<td class="blog_h2">cmake</td>
<td>参见<a href="/cmake-study-note#cmake">CMake学习笔记</a></td>
</tr>
<tr>
<td>readelf</td>
<td>
<p>参考<a href="/linux-programming-faq#readelf">Linux编程知识集锦</a></p>
</td>
</tr>
</tbody>
</table>
<div class="blog_h1"><span class="graybg">多媒体命令</span></div>
<table class="full-width fixed-word-wrap">
<thead>
<tr>
<td style="width: 100px; text-align: center;">命令</td>
<td style="text-align: center;">说明</td>
</tr>
</thead>
<tbody>
<tr>
<td class="blog_h2"><a id="ffmpeg"></a>ffmpeg</td>
<td>
<p>ffmpeg是一个高性能的音视频编码器，它能够进行文件格式转换，也能够从源捕获音视频。ffmpeg能够任意的转换采样率、实时改变视频尺寸</p>
<p>ffmpeg读取任意数量的输入文件（可以是普通文件、管道、网络流、输入设备），写出到任意数量的输出文件中。每个文件可以是不同类型的视频、音频、字幕、附件、数据，但是受限于容器格式，不一定所有文件都支持。输入文件和输出文件的对应关系，可以自动映射，也可以利用-map选项手工映射。你应该先指定所有输入文件，然后开始指定输出文件</p>
<p>某些选项需要引用输入文件，你可以使用从0开始的索引引用之</p>
<p><strong>基本流程</strong></p>
<p>转码的处理过程如下：</p>
<p style="padding-left: 30px;">输入文件 ⇨ (demuxer) ⇨ 解码后的数据包 ⇨ (decoder ) ⇨ 解码后的帧 <br />                                            ⇨ (encoder) ⇨ 编码后的数据包 ⇨ (muxer) ⇨ 输出文件</p>
<p>ffmpeg调用libavformat库（其中包含demuxers）来读取输入文件，并获得其中的编码数据包。如果有多个输入文件，ffmpeg会尝试跟踪任意输入流中最低的时间戳，以确保这些文件同步</p>
<p>编码数据包随后被送给decoder（除非为目标流选择流streamcopy），decoder产生非压缩的帧（原始video / PCM 音频）。这些非压缩帧可能被过滤器处理</p>
<p>过滤器处理过后，帧被传递给encoder，然后送给muxer，最终写到目标文件中</p>
<p><strong>过滤器</strong></p>
<p>在重新编码解码帧之前，ffmpeg可以对原始音频、视频进行处理，这通过调用libavfilter库完成。若干个过滤器链条组成一个filter graph。过滤器图被分为简单（simple）、复杂（complex）两类</p>
<p>简单过滤器图仅仅有一个输入、一个输出，且它们的类型相同。简单过滤器图通过-filter选项，在每个流上设置（-vf、-af分别对应视频、音频过滤）。简单过滤器图示例：输入 ⇨ 反交错  ⇨ 缩放  ⇨ 输出</p>
<p>某些过滤器会改变帧属性，但是不改变其内容。例如fps过滤器，它改变帧的数量，但是不会操作帧内容。又例如setpts过滤器，仅仅设置时间戳</p>
<p>复杂过滤器图可以有N个输入、N个输出。这种过滤器图通过-filter_complex（-lavfi）选项配置，此选项是全局的。复杂过滤器图的例子如overlay，它可以把两个视频重叠输出</p>
<p><strong>流拷贝</strong></p>
<p>设置 -codec copy，则仅仅从demux输入文件，然后mux到输出文件中。流拷贝非常快，但是由于诸多因素可能不正常工作</p>
<p><strong>流选择</strong></p>
<p>默认的ffmpeg仅仅包含每个类型（视频、音频、字幕）中的单个输入流，并把它们输出到每个输出文件中。如果有多个同类型的输入流，它会选择其中最好的：</p>
<ol>
<li>对于视频：选择最高分辨率</li>
<li>对于音频：选择通道数最多的</li>
<li>对于字幕：选择第一个</li>
</ol>
<p>要禁用上面这种默认特性，选用-vn/-an/-sn/-dn选项，或者通过-map进行细粒度控制</p>
<p><strong>命令格式</strong></p>
<pre class="crayon-plain-tag">ffmpeg [options] [[infile options] -i infile]... {[outfile] outfile}...

# 示例
# 获取本地摄像头视频流，以MPEG1编码后通过HTTP发送
ffmpeg -s 640x480 -f video4linux2 -i /dev/video0 -f mpegts -codec:v mpeg1video -b 800k -r 30 http://127.0.0.1:8800/12345
# 把MP4转换为vp8编码格式，加快编码速度
ffmpeg -i Lightheaded.mp4 -c:v vp8 -c:a libopus -speed 4 lightheaded.webm
# 缩放视频帧，iw、ih分别表示输入宽度、高度
ffmpeg -i Lightheaded.webm -vf scale=iw/2:ih/2 Lightheaded1.webm

# 裁剪视频中352x288大小的区域，此区域的左上角坐标为256x64，跳过开头的一分钟
ffmpeg -i lightheaded.webm -c:v vp8 -vf "crop=352:288:256:64" -ss 60 lightheaded1.webm
# 实时预览上述裁剪的效果
ffplay -i lightheaded.webm -vf "crop=352:288:256:64" -ss 60

# 同时指定多个过滤器
-vf "scale=iw/2:ih/2, crop=352:288:64:64"

# 基于H.264编码
ffmpeg -f video4linux2 -i /dev/video0 -framerate 15 -video_size 640x480
                        # 使用x264库作为编码器              # 使用Baseline Profile
       -pix_fmt yuv420p -c:v libx264 -b:v 600k -bufsize 600k -vprofile baseline 
       # 零延迟优化
       -tune zerolatency -f rawvideo -   # 输出原始视频（没有容器封装）到标准输出</pre>
<p><strong>辅助类选项</strong></p>
<p>-buildconf 显示此软件的构建选项<br />-formats 显示支持的文件格式，例如mp3 mp4<br />-muxers 显示支持的混流器<br />-demuxers 显示支持的分流器<br />-devices  显示支持的设备类型，例如video4linux2（本质上是一系列驱动和API标准）<br />-codecs 显示支持的编码算法<br />-decoders 显示可用的解码器<br />-encoders 显示可用的编码器<br />-bsfs 显示可用的比特流过滤器<br />-protocols 显示支持的输入输出协议，例如http rtsp rtmp<br />-filters 显示支持的过滤器<br />-pix_fmts 显示支持的像素格式<br />-layouts 显示支持的音频通道布局<br />-sample_fmts 显示支持的音频采样<br />-colors 显示可用的颜色名称及其HEX代码<br />-sources  显示可用输入设备列表<br />-hwaccels 显示可用的硬件加速方式</p>
<p><strong>全局选项</strong></p>
<p>-loglevel loglevel 设置日志级别，等价于 -v。合法值quiet,panic,fatal,error,warning,info,verbose,debug,trace<br />-report 生成一个报告<br />-hide_banner 禁止打印ffmpeg的banner<br />-max_alloc bytes 单个分配的块的最大尺寸<br />-y  如果输出文件存在，覆盖之<br />-n 绝不覆盖已经存在的输出文件，如果目标文件存在则退出<br />-ignore_unknown 忽略未知媒体类型<br />-filter_threads 非复杂性过滤线程数量<br />-filter_complex_threads 复杂性过滤线程数量<br />-stats 在编码时打印进度/统计信息<br />-max_error_rate 最大错误率，0-1之间<br />-bits_per_raw_sample number 每个原始采样的对应的比特数<br />-vol volume 改变音量，255是正常音量<br />-speed N 加快编码速度，速度越快质量越差<br />-progress url  发送进度信息到指定的URL<br />-stdin 允许基于标准输入的交互，-nostdin明确的禁用之</p>
<p><strong><span class="graybg">文件级选项</span></strong></p>
<p>-f fmt 适用IO。强制文件格式，例如mpegts<br />-i url 适用I。输入文件的URI<br />-c[:stream_specifier] codec  适用IO，可针对单个流。指定使用的编码算法，等价于 -codec <br />-pre preset 预设名称<br />-stream_loop 适用I。输入循环次数，-1表示无限循环<br />-map_metadata outfile[,metadata]:infile[,metadata] 根据源文件为目标文件设置元数据<br />-t duration 适用IO。录制或者转码指定时长的音频/视频<br />-to time_stop 适用O。停止录制或者转码的时间点（position）<br />-fs limit_size 适用O。按字节设置文件最大尺寸<br />-ss time_off 适用IO。设置开始时间偏移。指定秒数或者<pre class="crayon-plain-tag">hh:mm:ss[.xxx]</pre><br />-sseof time_off 适用IO。设置相对于EOF的开始时间偏移。0为EOF时间点，数字越小越靠前<br />-itsoffset offset  适用I。设置输入文件的时间偏移<br />-seek_timestamp 使用-ss时允许基于时间戳进行seek<br />-timestamp time 适用O。在容器中设置录制时间戳，now表示当前时间<br />-metadata string=string 添加元数据<br />-target type 适用O。目标类型，例如vcd、svcd、dvd、dv、dv50<br />-frames framecount 适用O，可针对单个流。设置输出帧的最大数量，超过数量后不再输出<br />-filter filter_graph 适用O，可针对单个流。设置流的filtergraph<br />-filter_script 适用O，可针对单个流。从文件读取filtergraph脚本<br />-pre[:stream_specifier] preset_name 适用O，可针对单个流。为匹配的流指定预设。这样可以快捷的调整处理速度。可选值ultrafast,superfast, veryfast, faster, fast, medium, slow, slower, veryslow, placebo<br />-tune 根据输入类型来优化输出。可选值film, animation, grain, stillimage, psnr, ssim, fastdecode, zerolatency<br />-attach filename  适用O。附加文件到输出，少数容器例如MKV支持，可以附加字幕<br />-discard  适用I。可以在混流器中丢弃某些流或者某些帧</p>
<p><strong>视频选项</strong></p>
<p>-vframes number 适用O。输出视频帧数量，等价于-frames:v<br />-r rate 适用IO，可针对单个流。设置帧率，可以指定HZ值、fraction、所写<br />-s [:stream_specifier] size 适用IO，可针对单个流。设置帧大小，WxH或者缩写，例如640x480<br />-aspect [:stream_specifier] 适用O，可针对单个流。aspect 设置纵横比，例如16:9 1.3333<br />-bits_per_raw_sample number  每个原始采样的对应的比特数<br />-vn 禁用视频录制，即丢弃输入的视频部分<br />-vcodec codec 适用O。强制使用编码算法，等价于-codec:v。取值copy则不进行重新编码<br />-vf filter_graph 适用O。设置视频过滤器<br />-b bitrate 视频比特率，等价于 -b:v<br />-dn 禁用数据<br />-pix_fmt[:stream_specifier] format (input/output,per-stream) 设置像素格式，如果指定的格式不被支持，ffmpeg会打印警告并选取编码器的最佳像素格式<br />+pix_fmt 类似上面，但是如果像素格式不支持，会退出<br />-force_key_frames[:stream_specifier] time[,time...] 适用O，可针对单个流。在指定的时间戳强制输出关键帧<br /> -force_key_frames[:stream_specifier] expr:expr 适用O，可针对单个流。在指定的时间戳强制输出关键帧<br />-hwaccel[:stream_specifier] hwaccel 适用I，可针对单个流。选择硬件加速机制。取值：none不进行硬件加速；auto自动选择硬件加速方法；vda使用Apple的VDA硬件加速；vdpau使用Unix下的VDPAU硬件加速；dxva2使用DirectX硬件加速；使用Intel的QuickSync硬件加速<br />-hwaccel_device[:stream_specifier] hwaccel_device 适用I，可针对单个流。选择硬件加速设备。</p>
<p><strong>音频选项</strong></p>
<p>-aframes number 适用O。输出音频帧数量<br />-aq quality 适用O。设置音频质量（依赖于codec）<br />-ar rate 适用IO，可针对单个流。设置采样频率，单位Hz<br />-ac channels 设置音频通道数<br />-an 禁用音频，即丢弃输入的音频部分<br />-acodec codec 强制使用编码算法。取值copy则不进行重新编码<br />-vol 改变音量，255是正常音量<br />-af filter_graph 设置音频过滤器<br />-ab bitrate 音频比特率，等价于-b:a</p>
<p><strong>字幕选项</strong><br />-s size 设置帧大小，WxH或者缩写<br />-sn 禁用字幕<br />-scodec codec 强制使用编码算法<br />-stag fourcc/tag 强制字幕tag/fourcc<br />-fix_sub_duration 修复字幕持续时间<br />-canvas_size size 设置画布大小，WxH或者缩写<br />-spre preset  设置字幕预设</p>
</td>
</tr>
</tbody>
</table>
<div class="blog_h1"><span class="graybg">发行版特殊命令</span></div>
<table style="width: 100%;" border="1" cellspacing="0" cellpadding="5">
<thead>
<tr>
<td style="width: 100px; text-align: center;"><span style="font-family: Ubuntu, Georgia, 'Times New Roman', 'Bitstream Charter', Times, serif;"><span style="font-weight: normal; line-height: 19px;">命令 </span></span></td>
<td style="text-align: center;"><span style="font-family: Ubuntu, Georgia, 'Times New Roman', 'Bitstream Charter', Times, serif;"><span style="font-weight: normal; line-height: 19px;"> 说明</span></span></td>
</tr>
</thead>
<tbody>
<tr>
<td class="blog_h2"><span style="font-family: Ubuntu, Georgia, 'Times New Roman', 'Bitstream Charter', Times, serif;"><span style="line-height: 19px;">rpm</span></span></td>
<td><span style="font-family: Ubuntu, Georgia, 'Times New Roman', 'Bitstream Charter', Times, serif;"><span style="font-family: Ubuntu, Georgia, 'Times New Roman', 'Bitstream Charter', Times, serif;">Redhat及其衍生版本下的包管理器，详见：<a href="/centos-faq#rpm">CentOS知识集锦</a></span></span></td>
</tr>
<tr>
<td class="blog_h2"><span style="font-family: Ubuntu, Georgia, 'Times New Roman', 'Bitstream Charter', Times, serif;"><span style="line-height: 19px;">yum </span></span></td>
<td><span style="font-family: Ubuntu, Georgia, 'Times New Roman', 'Bitstream Charter', Times, serif;"><span style="font-family: Ubuntu, Georgia, 'Times New Roman', 'Bitstream Charter', Times, serif;">基于rpm的便捷的软件包管理工具，详见：<a href="/centos-faq#yum">CentOS知识集锦</a></span></span></td>
</tr>
<tr>
<td class="blog_h2"><span style="font-family: Ubuntu, Georgia, 'Times New Roman', 'Bitstream Charter', Times, serif;"><span style="line-height: 19px;">apt-get</span></span></td>
<td><span style="font-family: Ubuntu, Georgia, 'Times New Roman', 'Bitstream Charter', Times, serif;"><span style="font-family: Ubuntu, Georgia, 'Times New Roman', 'Bitstream Charter', Times, serif;">APT包处理工具，详见：<a href="/ubuntu-faq#apt-get">Ubuntu知识集锦</a></span></span></td>
</tr>
<tr>
<td>update-alternatives</td>
<td>
<p>属于dpkg的实用工具，能够维护基于符号链接确定的“默认命令”</p>
<p>在同一个Debian系统中安装多个相同或相似的功能是允许的，例如可以安装多个文本编辑器。但是对于程序来说，它却不知道选择哪个编辑器</p>
<p>Debian的备选系统（Alternatives system）用于解决此问题，系统中一个一般性的名字被多个提供可替换功能的文件共享，备选系统和管理员共同决定某个时刻到底哪个文件生效。例如ed和nvi同时安装到系统中，则备选系统默认会将一般性名字/usr/bin/editor指向nvi，管理员可以覆盖此默认值</p>
<p>一般性名字并非直接指向选中备选的符号链接，它直接指向的是备选目录中的文件，后者指向实际的备选文件</p>
<p>有时候保持一组备选的同步选中很有用，假设你安装了多个版本的vi，则man页/usr/share/man/man1/vi应该指向/usr/bin/vi所指向的vi版本。update-alternatives可以使用master/slave链接来处理这个问题。如果master变更，则关联的slave会相应的变更（改变备选）。<span style="background-color: #c0c0c0;">master + 加上它关联的slaves构成链接组（link group）</span></p>
<p>每个链接组必然处于两种状态之一：</p>
<ol>
<li>自动：当包安装或移除时，备选系统自动决定是否更新链接</li>
<li>手工：链接必须由管理员通过该命令手工变更</li>
</ol>
<p>每个备选都具有优先级（priority），在自动模式下，链接组成员将指向最高优先级的备选</p>
<p><strong><span style="background-color: #c0c0c0;">命令格式</span></strong></p>
<pre class="crayon-plain-tag"># 安装一组备选到系统中
# link master link的一般性名称
# name 位于备选目录中的符号链接的名称
# path master link引入的备选的所在位置
# priority 优先级
# --slave slave link列表，可以指定多次
--install link name path priority [--slave link name path]...
# 示例：
# 将gcc的备选设置为gcc-5，g++自动跟随着变更
update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-5 1 \
                    --slave /usr/bin/g++ g++ /usr/bin/g++-5


# 将path设置为name的一个备选，name为备选目录中的名称
--set name path

# 移除一个备选，以及它关联的slave links，name为备选目录中的名称
--remove name path

# 移除所有备选
--remove-all name

# 针对所有备选调用 --config
--all

# 将name的备选的链接组设置为自动模式。这导致最高优先级的备选对应的
# master + slaves链接被启用
--auto name

# 显示链接组的信息
--display name
# 类似，输出易于机器解析
--query name

# 列出所有链接组及其状态
--get-selections
# 示例：
sudo update-alternatives --get-selections
# c89                            auto     /usr/bin/c89-gcc
# c99                            auto     /usr/bin/c99-gcc
# cc                             auto     /usr/bin/gcc
# go                             auto     /usr/bin/gccgo-go

# 显示链接组的所有目标
--list name
# 示例：
# update-alternatives --list gcc
# /usr/bin/gcc-4.8
# /usr/bin/gcc-4.9
# /usr/bin/gcc-5


# 显示链接组的所有备选，允许用户交互式的选中备选
--config name</pre>
</td>
</tr>
</tbody>
</table>
<div class="blog_h1"><span class="graybg">JVM相关命令</span></div>
<table class="full-width fixed-word-wrap">
<thead>
<tr>
<td style="width: 100px; text-align: center;"><span style="font-weight: normal; line-height: 19px;"><span style="font-family: Ubuntu, 微软雅黑;">命令</span></span></td>
<td style="text-align: center;"><span style="font-weight: normal; line-height: 19px;"><span style="font-family: Ubuntu, 微软雅黑;">说明</span></span></td>
</tr>
</thead>
<tbody>
<tr>
<td><a href="/jvm-options-and-performance-tuning#jps"><span style="color: #333333; font-family: Ubuntu, 微软雅黑;"><span style="color: #333333; font-family: Ubuntu, 微软雅黑;">jps </span></span></a></td>
<td><span style="line-height: 19px;"><span style="font-family: Ubuntu, 微软雅黑;">显示指定系统内所有的HotSpot虚拟机进程</span></span></td>
</tr>
<tr>
<td><a href="/jvm-options-and-performance-tuning#jstat"><span style="color: #333333; font-family: Ubuntu, 微软雅黑;"><span style="color: #333333; font-family: Ubuntu, 微软雅黑;">jstat</span></span></a></td>
<td><span style="line-height: 19px;"><span style="font-family: Ubuntu, 微软雅黑;">用干收集HotSpot虚拟机各方面的运行数据</span></span></td>
</tr>
<tr>
<td><a href="/jvm-options-and-performance-tuning#jinfo"><span style="color: #333333; font-family: Ubuntu, 微软雅黑;"><span style="color: #333333; font-family: Ubuntu, 微软雅黑;">jinfo</span></span></a></td>
<td><span style="line-height: 19px;"><span style="font-family: Ubuntu, 微软雅黑;">实时地査看和调整虚拟机的各项参数</span></span></td>
</tr>
<tr>
<td><a href="/jvm-options-and-performance-tuning#jmap"><span style="color: #333333; font-family: Ubuntu, 微软雅黑;"><span style="color: #333333; font-family: Ubuntu, 微软雅黑;">jmap</span></span></a></td>
<td><span style="line-height: 19px;"><span style="font-family: Ubuntu, 微软雅黑;">生成虚拟机的内存转储快照</span></span></td>
</tr>
<tr>
<td><a href="/jvm-options-and-performance-tuning#jhat"><span style="color: #333333; font-family: Ubuntu, 微软雅黑;"><span style="color: #333333; font-family: Ubuntu, 微软雅黑;">jhat</span></span></a></td>
<td><span style="line-height: 19px;"><span style="font-family: Ubuntu, 微软雅黑;">分析 heapdump 文件</span></span></td>
</tr>
<tr>
<td><a href="/jvm-options-and-performance-tuning#jstack"><span style="color: #333333; font-family: Ubuntu, 微软雅黑;"><span style="color: #333333; font-family: Ubuntu, 微软雅黑;">jstack</span></span></a></td>
<td><span style="line-height: 19px;"><span style="font-family: Ubuntu, 微软雅黑;">显示虚拟机的线程快照</span></span></td>
</tr>
<tr>
<td><a href="/jvm-options-and-performance-tuning#jcmd"><span style="color: #333333; font-family: Ubuntu, 微软雅黑;"><span style="color: #333333; font-family: Ubuntu, 微软雅黑;">jcmd</span></span></a></td>
<td><span style="line-height: 19px;"><span style="font-family: Ubuntu, 微软雅黑;">1.7引入的通用命令行工具</span></span></td>
</tr>
</tbody>
</table>
<p>&nbsp;
</div><p>The post <a rel="nofollow" href="https://blog.gmem.cc/linux-command-faq">Linux命令知识集锦</a> appeared first on <a rel="nofollow" href="https://blog.gmem.cc">绿色记忆</a>.</p>
]]></content:encoded>
			<wfw:commentRss>https://blog.gmem.cc/linux-command-faq/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Bash学习笔记</title>
		<link>https://blog.gmem.cc/bash-study-note</link>
		<comments>https://blog.gmem.cc/bash-study-note#comments</comments>
		<pubDate>Sat, 15 Mar 2008 02:52:39 +0000</pubDate>
		<dc:creator><![CDATA[Alex]]></dc:creator>
				<category><![CDATA[Linux]]></category>
		<category><![CDATA[Bash]]></category>
		<category><![CDATA[Command]]></category>
		<category><![CDATA[学习笔记]]></category>
		<category><![CDATA[文本处理]]></category>

		<guid isPermaLink="false">http://blog.gmem.cc/?p=2298</guid>
		<description><![CDATA[<p>Bash简介 在Linux系统中，作为/bin/sh的标准Shell是GNU工具集中的bash（GNU Bourne-Again Shell），大多数Linux发行版中/bin/sh是指向/bin/bash的一个链接。 单实例运行 基于PID进行控制 Bash编程中，可以通过PID文件进行简单的单例控制——仅仅同时仅仅允许脚本的单个实例在运行： [crayon-69e4c2207e181088242549/] 使用flock命令 [crayon-69e4c2207e188713671125/] 色彩控制 我们可以对终端输出的字符颜色、背景色等参数进行设置，实现方式是转义序列。这个控制实际上与Bash语言无关，其它语言在输出时也可以使用。 转义序列以ESC字符开头，对应八进制的\033。控制代码格式为： [crayon-69e4c2207e18b891683163/] 注意：显示方式、前景色、背景色都是可选的，而且顺序可以颠倒。示例： [crayon-69e4c2207e18d703513377/] 在脚本中使用色彩控制的例子： [crayon-69e4c2207e18f883166476/] 编码列表 编码 动作 &#124; 颜色 <a class="read-more" href="https://blog.gmem.cc/bash-study-note">[...]</a></p>
<p>The post <a rel="nofollow" href="https://blog.gmem.cc/bash-study-note">Bash学习笔记</a> appeared first on <a rel="nofollow" href="https://blog.gmem.cc">绿色记忆</a>.</p>
]]></description>
				<content:encoded><![CDATA[<div class="wri_content_clear_both"><div class="blog_h1"><span class="graybg">Bash简介</span></div>
<p>在Linux系统中，作为/bin/sh的标准Shell是GNU工具集中的bash（GNU Bourne-Again Shell），大多数Linux发行版中/bin/sh是指向/bin/bash的一个链接。</p>
<div class="blog_h1"><span class="graybg">单实例运行</span></div>
<div class="blog_h2"><span class="graybg">基于PID进行控制</span></div>
<p>Bash编程中，可以通过PID文件进行简单的单例控制——仅仅同时仅仅允许脚本的单个实例在运行：</p>
<pre class="crayon-plain-tag">#!/usr/bin/env bash
PIDFILE=/var/run/gmem-sync.pid
if [ -f $PIDFILE ]
then
  # PID文件存在
  PID=$(cat $PIDFILE)
  ps -p $PID &gt; /dev/null 2&gt;&amp;1
  if [ $? -eq 0 ]
  then
    # PID文件指定的进程存在
    echo "Job is already running"
    exit 1
  else
    # PID文件指定的进程不存在
    echo $$ &gt; $PIDFILE
    if [ $? -ne 0 ]
    then
      echo "Could not create PID file"
      exit 1
    fi
  fi
else
  echo $$ &gt; $PIDFILE
  if [ $? -ne 0 ]
  then
    echo "Could not create PID file"
    exit 1
  fi
fi

# 这里编写主逻辑


# 完毕后删除PID文件
rm $PIDFILE</pre>
<div class="blog_h2"><span class="graybg">使用flock命令</span></div>
<pre class="crayon-plain-tag"># 以独占锁（-x）打开gmem-sync.pid文件，并执行-c指定的命令
# -n 如果无法获得独占锁，立即静默的退出，退出状态非0
flock -xn /var/run/gmem-sync.pid -c /usr/local/bin/gmem-sync.sh</pre>
<div class="blog_h1"><span class="graybg">色彩控制</span></div>
<p>我们可以对终端输出的字符颜色、背景色等参数进行设置，实现方式是转义序列。这个控制实际上与Bash语言无关，其它语言在输出时也可以使用。</p>
<p>转义序列以ESC字符开头，对应八进制的\033。控制代码格式为：</p>
<pre class="crayon-plain-tag">\033[显示方式;前景色;背景色;动作m;</pre>
<p>注意：显示方式、前景色、背景色都是可选的，而且顺序可以颠倒。示例：</p>
<pre class="crayon-plain-tag"># 恢复系统默认设置
\033[0m
# 设置蓝色背景、白色前景、光标闪烁
\033[44;37;5m</pre>
<p>在脚本中使用色彩控制的例子：</p>
<pre class="crayon-plain-tag">echo -e "\033[44mDumping Gmem database on hk.gmem.cc ...\033[0m"</pre>
<div class="blog_h2"><span class="graybg">编码列表</span></div>
<table class=" full-width fixed-word-wrap">
<thead>
<tr>
<td style="text-align: center;">编码</td>
<td style="text-align: center;">动作 | 颜色</td>
<td style="text-align: center;">编码</td>
<td style="text-align: center;">动作 | 颜色</td>
</tr>
</thead>
<tbody>
<tr>
<td>0</td>
<td>恢复默认设置</td>
<td>36</td>
<td>青色前景</td>
</tr>
<tr>
<td>1</td>
<td>启用粗体</td>
<td>37</td>
<td>白色前景</td>
</tr>
<tr>
<td>2</td>
<td>启用一半亮度</td>
<td>38</td>
<td>默认前景+下划线</td>
</tr>
<tr>
<td>4</td>
<td>启用下划线</td>
<td>39</td>
<td>默认前景+取消下划线</td>
</tr>
<tr>
<td>5</td>
<td>启用闪烁</td>
<td>40</td>
<td>黑色背景</td>
</tr>
<tr>
<td>7</td>
<td>前背景色交换</td>
<td>41</td>
<td>红色背景</td>
</tr>
<tr>
<td>22</td>
<td>禁用粗体</td>
<td>42</td>
<td>绿色背景</td>
</tr>
<tr>
<td>24</td>
<td>禁用下划线</td>
<td>43</td>
<td>棕色背景</td>
</tr>
<tr>
<td>27</td>
<td>禁用前背景色交换</td>
<td>44</td>
<td>蓝色背景</td>
</tr>
<tr>
<td>30</td>
<td>黑色前景</td>
<td>45</td>
<td>紫色背景</td>
</tr>
<tr>
<td>31</td>
<td>红色前景</td>
<td>46</td>
<td>青色背景</td>
</tr>
<tr>
<td>32</td>
<td>绿色前景</td>
<td>47</td>
<td>白色背景</td>
</tr>
<tr>
<td>33</td>
<td>棕色前景</td>
<td>49</td>
<td>黑色背景</td>
</tr>
<tr>
<td>34</td>
<td>蓝色前景</td>
<td> </td>
<td> </td>
</tr>
<tr>
<td>35</td>
<td>紫色前景</td>
<td> </td>
<td> </td>
</tr>
</tbody>
</table>
<div class="blog_h1"><span class="graybg">系统日志</span></div>
<p>可以利用<a href="http://refspecs.linuxbase.org/LSB_4.1.0/LSB-Core-generic/LSB-Core-generic/iniscrptfunc.html">初始化脚本函数（Init Script Functions）</a>来输出系统日志：</p>
<table class=" full-width fixed-word-wrap">
<thead>
<tr>
<td style="width: 20%; text-align: center;">函数</td>
<td style="text-align: center;">说明</td>
</tr>
</thead>
<tbody>
<tr>
<td>log_daemon_msg</td>
<td>输出一般性的daemon日志</td>
</tr>
<tr>
<td>log_end_msg</td>
<td>指定调用参数0：表示成功，1表示失败</td>
</tr>
<tr>
<td>log_success_msg</td>
<td>输出成功消息到未指定的日志文件（unspecified log file）中，消息格式不指定。消息应该相对较短，最好不超过60字符</td>
</tr>
<tr>
<td>log_failure_msg</td>
<td>输出失败消息到未指定的日志文件（unspecified log file）中，消息格式不指定。消息应该相对较短，最好不超过60字符</td>
</tr>
<tr>
<td>log_warning_msg</td>
<td>输出警告消息到未指定的日志文件（unspecified log file）中，消息格式不指定。消息应该相对较短，最好不超过60字符</td>
</tr>
</tbody>
</table>
<div class="blog_h1"><span class="graybg">特殊字符</span></div>
<table style="width: 100%;" border="1" cellspacing="0" cellpadding="5">
<thead>
<tr>
<td style="width: 80px; text-align: center;">字符 </td>
<td style="text-align: center;">说明 </td>
</tr>
</thead>
<tbody>
<tr>
<td>#</td>
<td>
<p>单行注释</p>
</td>
</tr>
<tr>
<td>;</td>
<td>
<p>命令分隔符，可以在单行放置多个命令：</p>
<pre class="crayon-plain-tag">echo hello; echo there
if [ -x "$filename" ]; then # 注意分号后面的空格</pre>
</td>
</tr>
<tr>
<td>;;</td>
<td>
<p>CASE子句终止符：
<pre class="crayon-plain-tag">case "$variable" in
    abc) echo "\$variable = abc" ;;
    xyz) echo "\$variable = xyz" ;;
esac</pre>
</td>
</tr>
<tr>
<td>;;&amp;、;&amp;</td>
<td>Bash4+的CASE子句终止符</td>
</tr>
<tr>
<td>.</td>
<td>点号命令，相当于source命令</td>
</tr>
<tr>
<td>.</td>
<td>作为文件名的组成部分：隐藏文件的前缀</td>
</tr>
<tr>
<td>.</td>
<td>正则式字符串匹配，匹配任何单字符</td>
</tr>
<tr>
<td>"</td>
<td>部分引用，保留字符串中的大部分字符（继续重新解释：$、\、`），用于括起字符串，如果其中有特殊字符</td>
</tr>
<tr>
<td>'</td>
<td>完全引用，保留字符串中的全部字符（无法表示'字符）</td>
</tr>
<tr>
<td>,</td>
<td>
<p>串联多个表达式，最后一个作为返回值：
<pre class="crayon-plain-tag">let "t2 = ((a = 9, 15 / 3))" #设置t2=15/3，a=9</pre>
</td>
</tr>
<tr>
<td>, ,,</td>
<td>参数替换时的小写转换，双字符表示所有字符都转换，单字符表示只转换第一个字符（逗号）</td>
</tr>
<tr>
<td>\</td>
<td>
<p>转义，后面的字符按字面解析（Shell不做特殊解释）。
<p>\n 意味着新的一行<br />\r 回车<br />\t Tab键<br />\v 垂直Tab,查前边的Ctl-K<br />\b backspace,查前边的Ctl-H<br />\a 报警响铃<br />\0xx 转换成8进制ASCII 解码</p>
</td>
</tr>
<tr>
<td>\</td>
<td>
<p>后面跟命令，例如\cp，可以临时禁用alias</p>
</td>
</tr>
<tr>
<td>/</td>
<td>文件路径分隔符</td>
</tr>
<tr>
<td>`</td>
<td>命令替换，将命令的输出赋值为变量，在子shell中执行</td>
</tr>
<tr>
<td>:</td>
<td>
<p>空命令，什么都不做，exit status=0(true)</p>
<pre class="crayon-plain-tag">if condition
then : #什么都不做
else 
    take-some-action
fi
: &gt;&gt; target_file #如果不存在，则创建文件</pre>
</td>
</tr>
<tr>
<td>!</td>
<td>反转测试或者exit status的值</td>
</tr>
<tr>
<td>*</td>
<td>文件名通配符</td>
</tr>
<tr>
<td>*</td>
<td>正则式中，表示任意数量的字符</td>
</tr>
<tr>
<td>*</td>
<td>乘号</td>
</tr>
<tr>
<td>**</td>
<td>
<p>幂
</td>
</tr>
<tr>
<td>**</td>
<td>扩展文件匹配</td>
</tr>
<tr>
<td>?</td>
<td>参数替换中，用于测试变量是否被设置</td>
</tr>
<tr>
<td>?</td>
<td>通配符，匹配单个字符</td>
</tr>
<tr>
<td>$</td>
<td>变量替换：表示变量的内容，例如 var1=5 echo $var1</td>
</tr>
<tr>
<td>$</td>
<td>在正则式中表示行的结尾</td>
</tr>
<tr>
<td>${}</td>
<td>参数替换</td>
</tr>
<tr>
<td>$' ... '</td>
<td>引用字符串扩展</td>
</tr>
<tr>
<td>$*  $@</td>
<td>位置参数</td>
</tr>
<tr>
<td>$?</td>
<td>退出状态码，包含一个命令、函数、脚本的返回值</td>
</tr>
<tr>
<td>$$</td>
<td>持有进程的标识符</td>
</tr>
<tr>
<td>()</td>
<td>命令组。在子shell中执行，父shell无法见到其中的变量</td>
</tr>
<tr>
<td>()</td>
<td>数组初始化：Array=(element1 element2 element3)</td>
</tr>
<tr>
<td>{xx,yy,zz}</td>
<td>
<p>花括号扩展：注意花括号中不能出现空格，除非\转义，或者引号包含之</p>
<pre class="crayon-plain-tag">echo \"{These,words,are,quoted}\"
#打印："These" "words" "are" "quoted"
cat {file1,file2,file3} &gt; combined_file
#将三个文件的内容连接合并到combined_file
cp file22.{txt,backup}
#复制file22.txt为file22.backup</pre>
</td>
</tr>
<tr>
<td>{a..z}</td>
<td>
<p>扩展的花括号扩展：
<pre class="crayon-plain-tag">echo {a..z} 
#打印 a b c d e f g h i j k l m n o p q r s t u v w x y z
echo {0..3} 
#打印 0 1 2 3
base64_charset=( {A..Z} {a..z} {0..9} + / = )
#初始化一个数组</pre>
</td>
</tr>
<tr>
<td>{}</td>
<td>
<p>代码块，亦称内联组（inline group），创建一个匿名函数，但是其内部变量对外部可见。不会发起子Shell
<pre class="crayon-plain-tag">#!/bin/bash
File=/etc/fstab
{
    read line1
    read line2
} &lt; $File
echo "第一行:"
echo "$line1"
echo
echo "第二行:"
echo "$line2"
{
    echo "$line1"
} &gt; $File
exit 0</pre>
</td>
</tr>
<tr>
<td>[]</td>
<td>测试其中的表达式</td>
</tr>
<tr>
<td>[[ ]]</td>
<td>测试其中的表达式，比[]更灵活</td>
</tr>
<tr>
<td>[ ]</td>
<td>数组元素：Array[1]=slot_1 echo ${Array[1]}</td>
</tr>
<tr>
<td>[ ]</td>
<td>在正则式中表示一个范围内的字符</td>
</tr>
<tr>
<td>$[ ... ]</td>
<td>
<p>（废弃）整数扩展，估算其中的整数值：
<pre class="crayon-plain-tag">a=3
b=7
echo $[$a+$b] # 10
echo $[$a*$b] # 21</pre>
</td>
</tr>
<tr>
<td>(( ))</td>
<td>
<p>算术扩展，和let 命令很像，允许算术运算和赋值。特别的，在<span style="background-color: #c0c0c0;">某些场景下，允许使用C风格的语法</span>，举例：
<pre class="crayon-plain-tag">#将a赋值为8
a=(( 5 + 3 ));
#双圆括号也是一种在Bash 中允许使用C 风格的变量处理的机制，注意下面赋值的空格
(( a = 23 ))
(( a++ ))
(( a-- ))
(( t = a&lt;45?7:11 )) # C 风格的3元操作</pre>
</td>
</tr>
<tr>
<td>重定向符</td>
<td>
<p>command <span style="background-color: #c0c0c0;">&lt;</span> filename：命令的<span style="background-color: #c0c0c0;">标准输入</span>来自文件<br />command <span style="background-color: #c0c0c0;">&gt;</span> filename：重定向脚本的<span style="background-color: #c0c0c0;">标准输出</span>到文件，如果有内容，覆盖<br />command <span style="background-color: #c0c0c0;">&amp;&gt;</span> filename：重定向命令的<span style="background-color: #c0c0c0;">stdout、stderr</span>到文件<br />command <span style="background-color: #c0c0c0;">&gt;&amp;2</span>：重定向命令的<span style="background-color: #c0c0c0;">stdout到stderr<br /></span>command <span style="background-color: #c0c0c0;">&gt;</span> file1 <span style="background-color: #c0c0c0;">2&gt;</span>file2：重新<span style="background-color: #c0c0c0;">标准输出到file1，标准错误到file2<br /></span>command <span style="background-color: #c0c0c0;">&gt;</span> file <span style="background-color: #c0c0c0;">2&gt;&amp;1</span>：<span style="background-color: #c0c0c0;">先重定向stderr到stdout，然后统一重定向到file</span><br />scriptname <span style="background-color: #c0c0c0;">&gt;&gt;</span> filename：<span style="background-color: #c0c0c0;">附加脚本的标准输出</span>到文件<br />[i] <span style="background-color: #c0c0c0;">&lt;&gt;</span> filename 打开文件用于<span style="background-color: #c0c0c0;">读写，并分配文件描述符</span>，没文件则创建<br />&lt;&lt; here document中使用的重定向<br />&lt;&lt;&lt; here string中使用的重定向<br /><span style="background-color: #c0c0c0;">&gt;|</span> 强制重定向，<span style="background-color: #c0c0c0;">强制覆盖</span>文件内容
</td>
</tr>
<tr>
<td>进程替换</td>
<td>(command)&gt;<br />&lt;(command)</td>
</tr>
<tr>
<td>&lt;, &gt;</td>
<td>
<p>ASCII比较</p>
<pre class="crayon-plain-tag">veg1=carrots
veg2=tomatoes
if [[ "$veg1" &lt; "$veg2" ]]
then :
else :
fi</pre>
</td>
</tr>
<tr>
<td>\&lt;, \&gt;</td>
<td>正则式中表示单词边界</td>
</tr>
<tr>
<td>|</td>
<td>
<p>管道，把前面命令的stdout作为后一个命令或者shell的stdin
<pre class="crayon-plain-tag">#打印所有.lst文件，并排序和删除重复行
cat *.lst | sort | uniq</pre>
<p> 管道作为子进程运行，因此不能修改变量</p>
</td>
</tr>
<tr>
<td>||</td>
<td>逻辑或，在测试中，导致返回0（成功），只要任何一个表达式为true</td>
</tr>
<tr>
<td>&amp;</td>
<td>在后台运行一个任务</td>
</tr>
<tr>
<td>&amp;&amp;</td>
<td>逻辑与</td>
</tr>
<tr>
<td>-</td>
<td>简写的命令选项的前缀</td>
</tr>
<tr>
<td>--</td>
<td>命令选项前缀</td>
</tr>
<tr>
<td>-</td>
<td>上一个工作目录：cd -，相当于$OLDPWD</td>
</tr>
<tr>
<td>-</td>
<td>减号</td>
</tr>
<tr>
<td>-</td>
<td>很多命令中表示标准输入，例如cat、sed</td>
</tr>
<tr>
<td>=</td>
<td>赋值符</td>
</tr>
<tr>
<td>+</td>
<td>加号</td>
</tr>
<tr>
<td>+</td>
<td>命令选项，部分命令使用+表示启用某些特性，-表示禁用某些特性</td>
</tr>
<tr>
<td>%</td>
<td>模</td>
</tr>
<tr>
<td>~</td>
<td>家目录</td>
</tr>
<tr>
<td>~+</td>
<td>当前工作目录，相当于$PWD</td>
</tr>
<tr>
<td>~-</td>
<td>上一个工作目录：cd -，相当于$OLDPWD</td>
</tr>
<tr>
<td>=~</td>
<td>正则式匹配</td>
</tr>
<tr>
<td>^</td>
<td>正则式中表示行的开始</td>
</tr>
<tr>
<td>^ ^^</td>
<td>参数替换时的大写转换，双字符表示所有字符都转换，单字符表示只转换第一个字符</td>
</tr>
<tr>
<td>控制字符</td>
<td>Ctl-A 光标移到行首<br />Ctl-B 后退符<br />Ctl-C 终止前端任务<br />Ctl-D 从Shell注销<br />Ctl-E 移动光标到行尾<br />Ctl-F 移动光标向前一字符<br />Ctl-G 响铃<br />Ctl-H 擦除字符<br />Ctl-I 水平制表<br />Ctl-J 新一行<br />Ctl-K 垂直制表<br />Ctl-L 清屏<br />Ctl-M 回车<br />Ctl-N 从历史缓冲中删除一行<br />Ctl-O 新一行<br />Ctl-P 撤销历史缓冲中最后一条命令<br />Ctl-Q 恢复终端的stdin<br />Ctl-R 在历史缓冲中反向查找<br />Ctl-S 暂停，冻结终端的stdin<br />Ctl-U 删除光标到行首的所有字符,在某些设置下,删除全行<br />Ctl-V 当输入字符时,Ctl-V 允许插入控制字符。echo -e '\x0a' 等价于 echo <br />Ctl-W 删除当前光标到前边的最近一个空格之间的字符<br />Ctl-Z 终止前台工作</td>
</tr>
<tr>
<td>空白符</td>
<td>作为命令、变量之间的分隔符。在某些情况下，例如赋值，空白符是禁止的</td>
</tr>
</tbody>
</table>
<div class="blog_h1"><span class="graybg">变量与参数</span></div>
<div class="blog_h2"><span class="graybg">基础知识</span></div>
<div class="blog_h3"><span class="graybg">变量替换</span></div>
<p>变量的名称是作为其值的占位符，获取其值的操作称为变量替换——使用$前缀执行。在以下情况下，<span style="background-color: #c0c0c0;"><strong><span style="color: #ff0000;">不需要$前缀</span></strong>：变量声明、变量赋值、read、uset、export、((算术表达式))、或者作为代表信号的特殊情况下</span>。在<span style="background-color: #c0c0c0;">双引号中还是会发生变量替换</span>，这被叫做部分引用，或叫弱引用；<span style="background-color: #c0c0c0;">在单引号中就不会发生变量替换</span>，这叫做全引用，也叫强引用。</p>
<p><span style="background-color: #c0c0c0;">$是${}的简写</span>形式。</p>
<div class="blog_h3"><span class="graybg">变量赋值</span></div>
<p>未初始化的变量的值为null。使用这样的变量可能出现问题，但是进行算术运算是允许的，相当于0</p>
<pre class="crayon-plain-tag">a=879
echo "The value of \"a\" is $a."
let a=16+5 #使用let赋值
#在for循环中赋值
for a in 7 8 9 11
do
    echo -n "$a "
done
#在read 命令状态中赋值
echo -n "Enter \"a\" "
read a
echo "The value of \"a\" is now $a."
#把echo 命令的结果传给变量a
a=`ls -l`
echo $a #注意，ls命令输出的空白符，包括换行，均消失
echo "$a" #空白符保留
# 命令替换的另外一种形式
a=$(cat /ect/redhat-release)

# 命令替换嵌套，$()形式嵌套了``形式
pid=$(ps `jcmd | awk '{print $1}' ` | grep passport | awk '{print $1}' | head -1)</pre>
<div class="blog_h3"><span class="graybg"><strong>变量类型</strong></span></div>
<p>Bash不区分变量的类型，在本质上所有变量均是字符串。但是在特定上下文下，又作为数字看待。</p>
<div class="blog_h3"><span class="graybg"><b>特殊变量</b></span></div>
<p><span style="background-color: #c0c0c0;">局部变量</span>：只有在代码块或者函数中可见</p>
<p><span style="background-color: #c0c0c0;">环境变量</span>：Shell启动时，创建自己的环境，并影响所有子Shell</p>
<p><span style="background-color: #c0c0c0;">位置参数</span>：$0, $1, $2, $3...，其中$0代表脚本文件的名字1-9代表参数${10}代表第10个参数，等等。$*、$@表示所有位置参数的数组。使用shift可以左移参数</p>
<div class="blog_h2"><span class="graybg">参数解析</span></div>
<pre class="crayon-plain-tag">#!/bin/bash

# 解析传递给此脚本的参数
# -o 指定短参数，单字符，多个参数连续写在一起，结尾:
# -l 指定长参数，多个参数使用逗号分隔，结尾:
# 此命令修改$@，$N的含义可能发生改变，命令的非选项部分，最好放在前面
getopt -o lc: --long latest,chart:  -- "$@" &gt; /dev/null

LATEST=false
CHART=""

echo '$1'=$1
echo '$2'=$2
echo '$3'=$3
echo '$4'=$4
echo '$5'=$5

while true; do
  case "$1" in
    -l | --latest ) LATEST=true; shift ;;
    -c | --chart )    CHART=$2; shift; shift ;;
    -- ) shift; break ;;
    * ) break ;;
  esac
done

echo LATEST=$LATEST
echo CHART=$CHART</pre>
<p>调用上述脚本的示例：</p>
<pre class="crayon-plain-tag">./push.sh  --latest --chart ngress gmem digital
# $1=--latest
# $2=--chart
# $3=ngress
# $4=gmem
# $5=digital
# LATEST=true
# CHART=ngress

./push.sh  --latest  gmem digital
# $1=--latest
# $2=gmem 注意非参数的位置改变
# $3=digital
# $4=
# $5=
# LATEST=true
# CHART=</pre>
<div class="blog_h2"><span class="graybg">变量的间接引用</span></div>
<p>例如：eval var1=<span style="background-color: #c0c0c0;">\$$var2</span></p>
<div class="blog_h2"><span class="graybg">限定类型的变量</span></div>
<p>declare 或者typeset 内建命令(这两个命令是完全一样的)允许指定变量的具体类型</p>
<table style="width: 100%;" border="1" cellspacing="0" cellpadding="5">
<thead>
<tr>
<td style="text-align: center;"> 命令</td>
<td style="text-align: center;"> 说明</td>
</tr>
</thead>
<tbody>
<tr>
<td>declare -r var1[=value1]</td>
<td> 与readonly var1 是完全一样，强制指定只读</td>
</tr>
<tr>
<td>declare -i number</td>
<td> 把变量"number"后边的赋值视为一个整型</td>
</tr>
<tr>
<td>declae -a indices</td>
<td> 变量 indices 将被视为数组</td>
</tr>
<tr>
<td>declare -x var3</td>
<td> 把var3 export 出来</td>
</tr>
</tbody>
</table>
<div class="blog_h2"><span class="graybg">引号内的字符串</span></div>
<p>引号可以保护字符串的字面值，避免特殊字符被重新解释，或者被Shell扩展</p>
<pre class="crayon-plain-tag">grep '[Ff]irst' *.txt #基于正则式搜索*.txt文件的内容</pre>
<div class="blog_h1"><span class="graybg">参数替换</span></div>
<table style="width: 100%;" border="1" cellspacing="0" cellpadding="5">
<thead>
<tr>
<td style="width: 300px; text-align: center;"> 语法</td>
<td style="text-align: center;">说明 </td>
</tr>
</thead>
<tbody>
<tr>
<td class="blog_h2">${parameter}</td>
<td> 与$parameter 相同，可以避免混淆</td>
</tr>
<tr>
<td class="blog_h2">${parameter-default}</td>
<td rowspan="2"> 如果 parameter 没被set，那么就使用default。例如：echo ${username-`whoami`}</td>
</tr>
<tr>
<td class="blog_h2">${parameter:-default}</td>
</tr>
<tr>
<td class="blog_h2">${parameter=default}</td>
<td rowspan="2"> 如果 parameter 未设置，那么就设置为default</td>
</tr>
<tr>
<td class="blog_h2">${parameter:=default}</td>
</tr>
<tr>
<td class="blog_h2">
<p>${parameter+alt_value}</p>
</td>
<td rowspan="2"> 如果 parameter 被set 了，那就使用alt_value，否则就使用null 字符串</td>
</tr>
<tr>
<td class="blog_h2">${parameter:+alt_value}</td>
</tr>
<tr>
<td class="blog_h2">${parameter?err_msg}</td>
<td rowspan="2"> 如果 parameter 被set，那就是用set 的值，否则打印err_msg</td>
</tr>
<tr>
<td class="blog_h2">${parameter:?err_msg}</td>
</tr>
<tr>
<td class="blog_h2">${#var}</td>
<td> 字符串长度 </td>
</tr>
<tr>
<td class="blog_h2">${#array}</td>
<td>数组中第一个元素的长度</td>
</tr>
<tr>
<td class="blog_h2">${#array[*]}</td>
<td rowspan="2"> 数组元素的个数</td>
</tr>
<tr>
<td class="blog_h2">${$#array[@]}</td>
</tr>
<tr>
<td class="blog_h2">${array[@]}</td>
<td>将数组扩展为列表</td>
</tr>
<tr>
<td>${var#Pattern}</td>
<td>从$var 开头删除最近匹配$Pattern 的子串</td>
</tr>
<tr>
<td class="blog_h2">${var##Pattern}</td>
<td>从$var 开头删除最远匹配$Pattern 的子串</td>
</tr>
<tr>
<td class="blog_h2">${var%Pattern}</td>
<td> 从$var 结尾删除最近匹配$Pattern 的子串</td>
</tr>
<tr>
<td class="blog_h2">${var%%Pattern}</td>
<td>从$var 结尾删除最远匹配$Pattern 的子串</td>
</tr>
<tr>
<td class="blog_h2">${var:pos}</td>
<td> 变量 var 从位置pos 开始扩展</td>
</tr>
<tr>
<td class="blog_h2">${var:pos:len}</td>
<td> 从位置 pos 开始，并扩展len 长度个字符</td>
</tr>
<tr>
<td class="blog_h2">${var/Pattern/Repl}</td>
<td> 使用 Replacement 来替换var 中的第一个Pattern 的匹配</td>
</tr>
<tr>
<td class="blog_h2">${var//Pattern/Repl}</td>
<td> 全局替换。在var 中所有的匹配，都会用Replacement 来替换</td>
</tr>
<tr>
<td class="blog_h2">${var/#Pattern/Repl}</td>
<td> 如果 var 的前缀匹配到了Pattern，那么就用Replacement 来替换Pattern</td>
</tr>
<tr>
<td class="blog_h2">${var/%Pattern/Repl}</td>
<td> 如果 var 的后缀匹配到了Pattern，那么就用Replacement 来替换Pattern</td>
</tr>
<tr>
<td class="blog_h2">${!varprefix*}</td>
<td rowspan="2"> 使用变量的前缀来匹配前边所有声明过的变量</td>
</tr>
<tr>
<td class="blog_h2">${!varprefix@}</td>
</tr>
<tr>
<td class="blog_h2">${parameter^^}</td>
<td rowspan="2">转换为大写</td>
</tr>
<tr>
<td class="blog_h2">${parameter^}</td>
</tr>
<tr>
<td class="blog_h2">${parameter,,}</td>
<td rowspan="2">转换为小写</td>
</tr>
<tr>
<td class="blog_h2">${parameter,}</td>
</tr>
</tbody>
</table>
<div class="blog_h1"><span class="graybg">命令替换</span></div>
<p>处理一个或者多个命令的输出，并字面的（literally）将其赋予另外一个上下文（设置变量、作为另外一个命令的参数、甚至生成for循环的列表）。命令替换的典型的语法是反引用包围的命令。命令替换以subshell形式调用</p>
<pre class="crayon-plain-tag">script_name=`basename $0`
echo "The name of this script is $script_name."

textfile_listing=`ls *.txt`
#命令替换的可选语法：textfile_listing=$(ls *.txt)
echo $textfile_listing

#把文件内容赋值给变量
variable1=`&lt;file1`
variable2=`cat file2`
#命令替换可能导致单词分隔
COMMAND `echo a b` #COMMAND有两个参数a、b
COMMAND "`echo a b`" #一个参数 "a b"
COMMAND `echo` #没有参数
COMMAND "`echo`" #一个空参数</pre>
<div class="blog_h2"><span class="graybg">捕获输出</span></div>
<div class="blog_h3"><span class="graybg">标准输出</span></div>
<pre class="crayon-plain-tag">VAR=$(command)</pre>
<div class="blog_h3"><span class="graybg">标准错误</span></div>
<pre class="crayon-plain-tag">ERROR=$(cat file1.txt nofile.txt 2&gt;&amp;1 &gt; /dev/null)</pre>
<div class="blog_h3"><span class="graybg">同时捕获 </span></div>
<pre class="crayon-plain-tag">VAR=$(cat file1.txt nofile.txt 2&gt;&amp;1) </pre>
<div class="blog_h1"><span class="graybg">算术扩展</span></div>
<p>算数扩展提供了强大的整数算术操作机制。</p>
<pre class="crayon-plain-tag">z=`expr $z + 3`
z=$(($z+3))       #双括号，注意不要和命令替换混淆
z=$((z+3))        #双括号中，变量解引用可有可无
let z=z+3
let "z += 3"      #引号允许在变量赋值语句中使用空格 </pre>
<div class="blog_h1"><span class="graybg">字符串处理</span></div>
<div class="blog_h2"><span class="graybg">字符串长度</span></div>
<pre class="crayon-plain-tag">#下面3种方式均可得到字符串长度
stringZ=abcABC123ABCabc
echo ${#stringZ} # 15
echo `expr length $stringZ` # 15
echo `expr "$stringZ" : '.*'` # 15</pre>
<div class="blog_h2"><span class="graybg">子串匹配</span></div>
<pre class="crayon-plain-tag">expr match "$string" '$substring'    #$substring 是一个正则表达式
expr "$string" : '$substring'        #$substring 是一个正则表达式
#举例
echo `expr match "$stringZ" 'abc[A-Z]*.2'`</pre>
<div class="blog_h2"><span class="graybg">前缀/后缀匹配</span></div>
<pre class="crayon-plain-tag">#                注意：不要加引号
                 # 前缀匹配              # 后缀匹配
if [[ "$line" == flannel* || "$line" == *$K8S_VERSION ]]; then
  echo $line
fi </pre>
<div class="blog_h2"><span class="graybg">子串索引</span></div>
<pre class="crayon-plain-tag">expr index $string $substring    #匹配到子串的第一个字符的位置
#举例
stringZ=abcABC123ABCabc
echo `expr index "$stringZ" C12`   #6</pre>
<div class="blog_h2"><span class="graybg">提取子串</span></div>
<pre class="crayon-plain-tag">#在string中从位置$position 开始提取子串
#如果$string 为"*"或"@",那么将提取从位置$position 开始的位置参数
${string:position} 

#在string中从位置$position 开始提取$length 长度的子串
${string:position:length}

#举例
stringZ=abcABC123ABCabc
echo ${stringZ:0}     # abcABC123ABCabc
echo ${stringZ:1}     # bcABC123ABCabc
echo ${stringZ:7}     # 23ABCabc
echo ${stringZ:7:3}   # 23A
echo ${stringZ:(-4)}  # Cabc
echo ${*:2}           # Echo 出第2个和后边所有的位置参数
echo ${@:2}           # 与前边相同
echo ${*:2:3}         # 从第2个开始,Echo后边3个位置参数
if [ "${1:0:1}" = '-' ]; then echo " $1 is a option"; fi

#在string中从位置$position开始提取$length 长度的子串
expr substr $string $position $length 
#举例
stringZ=abcABC123ABCabc
echo `expr substr $stringZ 1 2` # ab
echo `expr substr $stringZ 4 3` # ABC

#从$string 的开始位置提取$substring,$substring 是一个正则表达式
expr match "$string" '\($substring\)'
expr "$string" : '\($substring\)'
#举例
stringZ=abcABC123ABCabc
echo `expr match "$stringZ" '\(.[b-c]*[A-Z]..[0-9]\)'` # abcABC1</pre>
<div class="blog_h2"><span class="graybg">删除子串</span></div>
<pre class="crayon-plain-tag">#从$string 的左边截掉第一个匹配的$substring
${string#substring}
#从$string 的左边截掉最后一个匹配的$substring
${string##substring}
#举例
stringZ=abcABC123ABCabc
echo ${stringZ#a*C} # 123ABCabc   截掉'a'和'C'之间最近的匹配
echo ${stringZ##a*C} # abc        截掉'a'和'C'之间最远的匹配

#从$string 的右边截掉第一个匹配的$substring
${string%substring}
#从$string 的右边截掉最后一个匹配的$substring
${string%%substring}
#举例
stringZ=abcABC123ABCabc
echo ${stringZ%b*c}  # abcABC123ABCa 从$stringZ 的后边开始截掉'b'和'c'之间的最近的匹配</pre>
<div class="blog_h2"><span class="graybg">替换子串</span></div>
<pre class="crayon-plain-tag">#使用$replacement 来替换第一个匹配的$substring
${string/substring/replacement}
#使用$replacement 来替换所有匹配的$substring
${string//substring/replacement}
#举例
stringZ=abcABC123ABCabc
echo ${stringZ/abc/xyz}  # xyzABC123ABCabc
echo ${stringZ//abc/xyz} # xyzABC123ABCxyz

#如果$substring 匹配$string 的开头部分,那么就用$replacement 来替换$substring
${string/#substring/replacement}
#如果$substring 匹配$string 的结尾部分,那么就用$replacement 来替换$substring
${string/%substring/replacement}
#举例
stringZ=abcABC123ABCabc
echo ${stringZ/#abc/XYZ} # XYZABC123ABCabc
echo ${stringZ/%abc/XYZ} # abcABC123ABCXYZ</pre>
<div class="blog_h1"><span class="graybg">退出与退出状态</span></div>
<p>exit 命令被用来结束脚本，返回一个值来传给父进程，如果没有exit，则最后执行的命令的exit状态被返回。</p>
<p>每个命令都会返回一个 exit 状态(有时候也叫return 状态)，成功返回0，如果返回一个非0 值，通常情况下都会被认为是一个错误码。</p>
<p>变量：<span style="background-color: #c0c0c0;">$?</span>用于读取退出码。</p>
<div class="blog_h1"><span class="graybg">内部变量</span></div>
<table style="width: 100%;" border="1" cellspacing="0" cellpadding="5">
<thead>
<tr>
<td style="width: 120px; text-align: center;"> 变量/函数名</td>
<td style="text-align: center;">说明 </td>
</tr>
</thead>
<tbody>
<tr>
<td class="blog_h2"> $BASH</td>
<td>Bash 的二进制执行文件的位置</td>
</tr>
<tr>
<td class="blog_h2"> $BASH_ENV</td>
<td>指向一个 Bash 启动文件，这个启动文件将在调用一个脚本时被读取</td>
</tr>
<tr>
<td class="blog_h2"> $BASH_SUBSHELL</td>
<td>提示subshell 的层次</td>
</tr>
<tr>
<td class="blog_h2"> $BASH_VERSINFO[n]</td>
<td>记录 Bash 安装信息的一个6 元素的数组</td>
</tr>
<tr>
<td class="blog_h2"> $BASH_VERSION</td>
<td>安装在系统上的 Bash 的版本号</td>
</tr>
<tr>
<td class="blog_h2"> $DIRSTACK</td>
<td>在目录栈中最上边的值（将受到pushd 和popd 的影响）</td>
</tr>
<tr>
<td class="blog_h2"> $EDITOR</td>
<td>脚本调用的默认编辑器</td>
</tr>
<tr>
<td class="blog_h2"> $EUID</td>
<td>"effective"用户ID</td>
</tr>
<tr>
<td class="blog_h2"> $FUNCNAME</td>
<td>当前函数的名字</td>
</tr>
<tr>
<td class="blog_h2"> $GLOBIGNORE</td>
<td>文件名的模式匹配列表</td>
</tr>
<tr>
<td class="blog_h2"> $GROUPS</td>
<td>当前用户属于的组</td>
</tr>
<tr>
<td class="blog_h2"> $HOME</td>
<td>用户的 home 目录</td>
</tr>
<tr>
<td class="blog_h2"> $HOSTNAME</td>
<td>主机名</td>
</tr>
<tr>
<td class="blog_h2"> $HOSTTYPE</td>
<td>主机类型，识别系统的硬件，例如i686</td>
</tr>
<tr>
<td class="blog_h2"> $IFS</td>
<td>内部域分隔符，这个变量用来决定 Bash 在解释字符串时如何识别域、单词边界。默认为空白（空格、TAB、换行）</td>
</tr>
<tr>
<td class="blog_h2"> $IGNOREEOF</td>
<td>忽略 EOF</td>
</tr>
<tr>
<td class="blog_h2"> $LINENO</td>
<td>记录它所在的 shell 脚本中它所在行的行</td>
</tr>
<tr>
<td class="blog_h2"> $MACHTYPE</td>
<td>提示系统硬件</td>
</tr>
<tr>
<td class="blog_h2"> $OLDPWD</td>
<td>老的工作目录</td>
</tr>
<tr>
<td class="blog_h2"> $OSTYPE</td>
<td>操作系统类型</td>
</tr>
<tr>
<td class="blog_h2"> $PATH</td>
<td>指向 Bash 外部命令所在的位置，一般为/usr/bin,/usr/X11R6/bin,/usr/local/bin等</td>
</tr>
<tr>
<td class="blog_h2"> $PIPESTATUS</td>
<td>数组变量将保存最后一个运行的前台管道的退出码</td>
</tr>
<tr>
<td class="blog_h2"> $PPID</td>
<td>父进程的进程</td>
</tr>
<tr>
<td class="blog_h2"> $PROMPT_COMMAND</td>
<td>保存一个在主提示符($PS1)显示之前需要执行的命令</td>
</tr>
<tr>
<td class="blog_h2"> $PS1</td>
<td>主提示符，具体见命令行上的显示</td>
</tr>
<tr>
<td class="blog_h2"> $PS2</td>
<td>第 2 提示符，当需要额外的输入的时候将会显示，默认为"&gt;"</td>
</tr>
<tr>
<td class="blog_h2"> $PS3</td>
<td>第 3 提示符，在select 循环中显示</td>
</tr>
<tr>
<td class="blog_h2"> $PS4</td>
<td>第 4 提示符，当使用-x 选项调用脚本时，这个提示符将出现在每行的输出前边，默认为"+"</td>
</tr>
<tr>
<td class="blog_h2"> $PWD</td>
<td>工作目录</td>
</tr>
<tr>
<td class="blog_h2"> $REPLY</td>
<td>read命令如果没有给变量，输入将保存在$REPLY 中</td>
</tr>
<tr>
<td class="blog_h2"> $SECONDS</td>
<td>脚本已经运行的时间(单位为秒)</td>
</tr>
<tr>
<td class="blog_h2"> $SHELLOPTS</td>
<td>保存 shell 允许的选项，这个变量是只读的</td>
</tr>
<tr>
<td class="blog_h2"> $SHLVL</td>
<td>Shell层次，就是shell 层叠的层次，如果是命令行那$SHLVL 就是1，递增</td>
</tr>
<tr>
<td class="blog_h2"> $TMOUT</td>
<td>如果$TMOUT 环境变量被设置为一个非零的时间值，那么在过了这个指定的时间之后，shell提示符将会超时，这会引起一个logout</td>
</tr>
<tr>
<td class="blog_h2"> $UID</td>
<td>用户 ID 号</td>
</tr>
<tr>
<td class="blog_h2"> $0, $1, $2...</td>
<td>
<p>位置参数，从命令行传递给脚本，或者是传递给函数</p>
<p>$0 为脚本文件的名字<br />$1 为第一个参数，类推</p>
</td>
</tr>
<tr>
<td class="blog_h2"> $#</td>
<td>命令行或者是位置参数的个数</td>
</tr>
<tr>
<td class="blog_h2"> $*</td>
<td>
<p>所有的位置参数，被作为一个单词。注意：<span style="background-color: #c0c0c0;">"$*"必须被""引用</span></p>
</td>
</tr>
<tr>
<td class="blog_h2"> $@</td>
<td>与$*同义，但是每个参数都是一个独立的""引用字串。注意：<span style="background-color: #c0c0c0;">"$@"必须被""引用</span></td>
</tr>
<tr>
<td class="blog_h2"> $!</td>
<td>在后台运行的最后的工作的 PID</td>
</tr>
<tr>
<td class="blog_h2"> $_</td>
<td>保存之前执行的命令的最后一个参数</td>
</tr>
<tr>
<td class="blog_h2"> $?</td>
<td>命令，函数或者脚本本身的退出状态</td>
</tr>
<tr>
<td class="blog_h2"> $$</td>
<td>脚本自身的进程 ID</td>
</tr>
<tr>
<td class="blog_h2"> $RANDOM</td>
<td> 产生一个随机整数</td>
</tr>
</tbody>
</table>
<div class="blog_h1"><span class="graybg">条件测试与分支</span></div>
<div class="blog_h2"><span class="graybg">简介</span></div>
<p>一个<pre class="crayon-plain-tag">if/then</pre>结构可以测试命令的返回值是否为零（0表示成），如果是的话，执行更多命令。</p>
<p>内建命令<pre class="crayon-plain-tag">[</pre>与<pre class="crayon-plain-tag">test</pre>命令等价。这个命令把它的参数作为比较表达式或是文件测试，并且根据比较的结果，返回一个退出码。</p>
<p>Bash 2.02以后，关键字<pre class="crayon-plain-tag">[[...]]</pre>用于扩展test命令。 例如<pre class="crayon-plain-tag">[[ $a -lt $b ]]</pre>是一个单独的元素，返回一个退出码。</p>
<p><pre class="crayon-plain-tag">((...))</pre>和<pre class="crayon-plain-tag">let...</pre>结果也能够返回一个退出码，当它们所测试的<span style="background-color: #c0c0c0;">算术表达式的结果为<span style="color: #ff0000;"><strong>非0</strong></span></span> 的时候，退出码将返回0。</p>
<p><pre class="crayon-plain-tag">[[]]</pre>结构比<pre class="crayon-plain-tag">[]</pre>更加灵活，前者支持<span style="background-color: #c0c0c0;">参数扩展和命令替换</span>。</p>
<div class="blog_h2"><span class="graybg">test/[命令</span></div>
<div class="blog_h3"><span class="graybg">语法</span></div>
<pre class="crayon-plain-tag">test EXPRESSION

test

[ EXPRESSION ]

[ ]

[ OPTION</pre>
<div class="blog_h3"><span class="graybg">表达式</span></div>
<p>EXPRESSION的语法如下：</p>
<pre class="crayon-plain-tag"># 空白表达式为假


# 如果表达式为真，通过测试（结果为真）
( EXPRESSION )

# 如果表达式为假，通过测试
! EXPRESSION

# 逻辑与
EXPRESSION1 -a EXPRESSION2

# 逻辑或
EXPRESSION1 -o EXPRESSION2

# 字符串长度不为零，通过测试
-n STRING

# 如果字符串长度为零，通过测试
-z STRING

# 字符串比较、文件测试、数字比较见下文</pre>
<div class="blog_h2"><span class="graybg">示例</span></div>
<pre class="crayon-plain-tag">[ "$1" = 'mysqld' -a -n "$CLUSTER_INIT" ]   # 如果第一个参数为mysqld，并且变量CLUSTER_INIT不为空

(( 0 &amp;&amp; 1 ))                                # 逻辑与，$?为1
let "num = (( 0 &amp;&amp; 1 ))"                    # num的值为0，故$?为1
(( 200 || 11 ))                             # 逻辑或，$? # 0
let "num = (( 200 || 11 ))"                 # num的值为1，故$?为0
(( 200 | 11 ))                              # 按位或，$?为0     
   
# 注意，本行不会打印var变量，因为算术扩展的退出状态不是一个错误码                                  
var=-2 &amp;&amp; (( var+=2 )) &amp;&amp; echo $var     

# 测试任何命令    
if grep -q Bash file                        
    then echo "At least one Bash in file"
fi
# []或者[[]]测试时，必须与内部表达式之间保留一个空格

# 如果在同一行上边写多个子句，必须使用; 来分隔（注意后面的空格）
if [ ! -x "$filename" ]; then :               #空命令:不执行任何动作
else if [0]; then :
elif [1]; then :                            #elif是else if的简写
fi

# 测试上一个命令的退出码
if [[ $? -eq 0 ]] ; then echo 'Successful'; fi
if [[ $? -eq 0 ]] ; then
    echo 'Succeeded'
    echo 'OK'
else
    echo 'Failed'
fi

# 测试第四个参数是否存在
if [ -z "$4" ] ; then
   echo "Argument 4 not exist"
fi

# 所有内容集中在单行编写的例子
if [[ $? -eq 0 ]]; then echo FOUND; fi
# 使用逻辑与/或
if [[ 1 -eq 1 &amp;&amp; 2 eq 2 ]]; then : fi
if [[ 1 -eq 1 ]] || [[ 2 -eq 1 ]]; then : fi</pre>
<div class="blog_h2"><span class="graybg">文件测试</span></div>
<table style="width: 100%;" border="1" cellspacing="0" cellpadding="5">
<thead>
<tr>
<td style="width: 80px; text-align: center;">测试符 </td>
<td style="text-align: center;"> 说明</td>
</tr>
</thead>
<tbody>
<tr>
<td>-e</td>
<td>文件存在</td>
</tr>
<tr>
<td>-f</td>
<td>file 是一个普通文件，如果file是目录、设备文件，或者file不存在，则测试不通过</td>
</tr>
<tr>
<td>-s</td>
<td>文件长度不为0</td>
</tr>
<tr>
<td>-d</td>
<td>文件是个目录</td>
</tr>
<tr>
<td>-b</td>
<td>文件是个块设备(软盘,cdrom 等等)</td>
</tr>
<tr>
<td>-c</td>
<td>文件是个字符设备(键盘,modem,声卡等等)</td>
</tr>
<tr>
<td>-p</td>
<td>文件是个管道</td>
</tr>
<tr>
<td>-h</td>
<td>文件是个符号链接</td>
</tr>
<tr>
<td>-L</td>
<td>文件是个符号链接</td>
</tr>
<tr>
<td>-S</td>
<td>文件是个socket</td>
</tr>
<tr>
<td>-t</td>
<td>关联到一个终端设备的文件描述符<br />这个选项一般都用来检测是否在一个给定脚本中的 stdin[-t0]或[-t1]是一个终端</td>
</tr>
<tr>
<td>-r</td>
<td>文件具有读权限(对于用户运行这个test)</td>
</tr>
<tr>
<td>-w</td>
<td>文件具有写权限(对于用户运行这个test)</td>
</tr>
<tr>
<td>-x</td>
<td>文件具有执行权限(对于用户运行这个test)</td>
</tr>
<tr>
<td>-g</td>
<td>目录是否具有 sgid 标志</td>
</tr>
<tr>
<td>-u</td>
<td>文件是否具有suid标志。如果运行一个具有 root 权限的文件,那么运行进程将取得root 权限,即使你是一个普通用户，如果没有 suid 标志的话,那么普通用户(没有root 权限)将无法运行这种程序</td>
</tr>
<tr>
<td>-k</td>
<td>
<p>检查sticky bit，设置在文件上，将保存在交换区；设置在目录上，将限制写权限：如果用户不是该目录的所有者，但是具有写权限，那么他只能删除目录下自己拥有的文件。</p>
<p>设置了此标志位的文件或目录（例如/tmp），权限尾部有t标记，例如：drwxrwxrwt</p>
</td>
</tr>
<tr>
<td>-O</td>
<td>是否当前用户是文件所有者</td>
</tr>
<tr>
<td>-G</td>
<td>是否文件的group-id 与当前用户相同</td>
</tr>
<tr>
<td>-N</td>
<td>从文件最后被阅读到现在，是否被修改</td>
</tr>
<tr>
<td>f1 -nt f2</td>
<td>是否文件 f1 比f2 新</td>
</tr>
<tr>
<td>f1 -ot f2</td>
<td>是否文件 f1 比f2 老</td>
</tr>
<tr>
<td>f1 -ef f2</td>
<td>是否f1和f2 都硬连接到同一个文件</td>
</tr>
<tr>
<td>!</td>
<td>可以反转上述测试的结果</td>
</tr>
</tbody>
</table>
<div class="blog_h2"><span class="graybg">其他比较操作符</span></div>
<table style="width: 100%;" border="1" cellspacing="0" cellpadding="5">
<thead>
<tr>
<td style="width: 80px; text-align: center;"> 操作符</td>
<td style="text-align: center;">说明 </td>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align: center;" colspan="2"><strong> 整数比较</strong></td>
</tr>
<tr>
<td> -eq</td>
<td>等于，如：if [ "$a" -eq "$b" ]</td>
</tr>
<tr>
<td> -ne</td>
<td>不等于，如：if [ "$a" -ne "$b" ]</td>
</tr>
<tr>
<td> -gt</td>
<td>大于，如：if [ "$a" -gt "$b" ]</td>
</tr>
<tr>
<td> -ge</td>
<td>大于等于，如：if [ "$a" -ge "$b" ]</td>
</tr>
<tr>
<td> -lt</td>
<td>小于，如：if [ "$a" -lt "$b" ]</td>
</tr>
<tr>
<td> -le</td>
<td>小于等于，如：if [ "$a" -le "$b" ]</td>
</tr>
<tr>
<td> &lt;</td>
<td>小于(需要双括号)，如：(("$a" &lt; "$b"))</td>
</tr>
<tr>
<td> &lt;=</td>
<td>小于等于(需要双括号)，如：(("$a" &lt;= "$b"))</td>
</tr>
<tr>
<td> &gt;</td>
<td>大于(需要双括号)，如：(("$a" &gt; "$b"))</td>
</tr>
<tr>
<td> &gt;=</td>
<td>大于等于(需要双括号)，如：(("$a" &gt;= "$b"))</td>
</tr>
<tr>
<td style="text-align: center;" colspan="2"> <strong> 字符串比较</strong></td>
</tr>
<tr>
<td> =</td>
<td>等于，如：if [ "$a" = "$b" ]</td>
</tr>
<tr>
<td> ==</td>
<td>
<p>等于，如：if [ "$a" == "$b" ]，与=等价，注意其行为在[] [[]]中的不同</p>
<p>[[ $a == z* ]] # 如果$a 以"z"开头(模式匹配)那么将为true<br />[[ $a == "z*" ]] # 如果$a 等于z*(字符匹配),那么结果为true<br />[ $a == z* ] # File globbing（一种关于文件的速记法，比如"*.c"、"~"） 和word splitting 将会发生<br />[ "$a" == "z*" ] # 如果$a 等于z*(字符匹配),那么结果为true</p>
</td>
</tr>
<tr>
<td> !=</td>
<td>不等于，如：if [ "$a" != "$b" ]</td>
</tr>
<tr>
<td> &lt;</td>
<td>
<p>小于，按ASCII 字母顺序比较，例如</p>
<p>if [[ "$a" &lt; "$b" ]]<br />if [ "$a" \&lt; "$b" ]  #在[]中，&lt;需要转义</p>
</td>
</tr>
<tr>
<td> &gt;</td>
<td>大于，按ASCII 字母顺序比较</td>
</tr>
<tr>
<td>-z</td>
<td>测试字符串为"null"，即长度为0</td>
</tr>
<tr>
<td>-n</td>
<td>测试字符串不为"null"</td>
</tr>
<tr>
<td style="text-align: center;" colspan="2"><strong>混合比较</strong></td>
</tr>
<tr>
<td>-a</td>
<td>逻辑与</td>
</tr>
<tr>
<td>-o</td>
<td>逻辑或</td>
</tr>
</tbody>
</table>
<div class="blog_h2"><span class="graybg">嵌套的测试</span></div>
<pre class="crayon-plain-tag">if [ condition1 ]
then
    if [ condition2 ]
    then
    do-something # 这里只有在condition1 和condition2 都可用的时候才行.
    fi
fi</pre>
<div class="blog_h2"><span class="graybg">CASE分支结构</span></div>
<pre class="crayon-plain-tag">case "$variable" in
"$condition1")         #测试行都以右小括号)结尾
    command...
;;                     #条件块都以两个分号结尾
"$condition1")
    command...
;;
esac
#举例
read Keypress
case "$Keypress" in
[[:lower:]] ) echo "Lowercase letter";;
[[:upper:]] ) echo "Uppercase letter";;
[0-9] )       echo "Digit";;
* )           echo "Punctuation, whitespace, or other";;
esac</pre>
<div class="blog_h1"><span class="graybg">循环结构</span></div>
<div class="blog_h2"><span class="graybg">for循环</span></div>
<div class="blog_h3"><span class="graybg">语法</span></div>
<pre class="crayon-plain-tag">#for循环
for arg in [list]
do
    command(s)...
done</pre>
<div class="blog_h3"><span class="graybg">分隔符</span></div>
<p>默认的分隔符是whitespace，也就是每当遇到分隔符，就会产生新的arg。要修改分隔符为换行，在循环前添加：</p>
<pre class="crayon-plain-tag">IFS=$'\n'</pre>
<div class="blog_h2"><span class="graybg">C风格for循环</span></div>
<pre class="crayon-plain-tag">LIMIT=10
for ((a=1, b=1; a &lt;= LIMIT ; a++, b++))
do
    echo -n "$a "
done

# 无限循环
for (( ; ; ))</pre>
<div class="blog_h2"><span class="graybg">while循环</span></div>
<pre class="crayon-plain-tag">while [condition]
do
    command...
done</pre>
<div class="blog_h2"><span class="graybg">C风格while循环 </span></div>
<pre class="crayon-plain-tag">((a = 1))
while (( a &lt;= LIMIT ))
do
    echo -n "$a "
    ((a += 1)) # let "a+=1"
done</pre>
<div class="blog_h2"><span class="graybg">until循环</span></div>
<pre class="crayon-plain-tag">until [condition-is-true]
do
    command...
done </pre>
<div class="blog_h2"><span class="graybg">循环举例</span></div>
<div class="blog_h3"><span class="graybg">无限循环</span></div>
<pre class="crayon-plain-tag"># 无限循环1
while :

# 无限循环2
while true</pre>
<div class="blog_h3"><span class="graybg">数字范围循环</span></div>
<pre class="crayon-plain-tag"># 遍历范围
var0=0
LIMIT=10
while [ "$var0" -lt "$LIMIT" ]
do
    echo -n "$var0 "
    var0=`expr $var0 + 1` 
    # var0=$(($var0+1))
    # var0=$((var0 + 1))
    # let "var0 += 1"
done</pre>
<div class="blog_h3"><span class="graybg">遍历命令输出</span></div>
<p>可以使用管道：</p>
<pre class="crayon-plain-tag">ip route | while read -r route; do
  dest=$(echo $route | awk '{print $1}')
  if [[ "$dest" != *"/"* ]]; then
    continue
  fi
done</pre>
<p>注意，某些命令结尾没有\n，这会导致遍历的时候最后一行被略过，需要这样：</p>
<pre class="crayon-plain-tag">{ yourcmd; echo; } | while read -r line; do echo $line; done

# 遍历文件的每一行，注意，echo确保文件不以换行符结尾的情况下，最后一行不丢失
{ cat images.txt; echo; } | while read -r line; do
  if [[ "$src" == "" ]]; then
    continue
  fi
done</pre>
<p>使用管道时，while运行在subshell中，缺点是无法修改变量，可以使用Here String规避：</p>
<pre class="crayon-plain-tag">declare -A tgt_service_versions
while read -r line; do
  comp=$(echo "$line" | yq r - '.service_name')
  version=$(echo "$line" | yq r - '.tmplgrp_version')
  tgt_service_versions[$comp]=$version
done &lt;&lt;&lt; "$(yq r global.yaml ".vars.services")"</pre>
<div class="blog_h3"><span class="graybg">遍历字符串列表</span></div>
<pre class="crayon-plain-tag"># 遍历字符串列表，注意，如果字符串加引号，作为整体看待
for planet in Mercury Venus Earth Mars Jupiter Saturn Uranus Neptune Pluto
do
    echo $planet # Each planet on a separate line.
done

# 遍历字符串列表，使用变量
FILES="/usr/sbin/accept
/usr/sbin/pwck
/usr/sbin/chroot
/usr/bin/fakefile
/sbin/badblocks
/sbin/ypbind"
for file in $FILES
do
    if [ ! -e "$file" ]
        break
        continue 1   # 控制循环的行为，数字用于跳出或继续N层循环
    fi
done</pre>
<div class="blog_h3"><span class="graybg">遍历文件列表 </span></div>
<pre class="crayon-plain-tag"># 遍历文件列表。如果列表中包含通配符*?，则会扩展文件名，即file globbing
#   *所有文件
#   [jx]* 所有j或者x开头的文件
for file in *; do ...
for cfg in config/*; do
    if
done</pre>
<div class="blog_h3"><span class="graybg">遍历参数数组 </span></div>
<pre class="crayon-plain-tag"># 遍历参数数组。如果忽略列表，则操作$@
for a
do
    echo -n "$a "
done </pre>
<div class="blog_h1"><span class="graybg">内建命令</span></div>
<p>一个内建命令通常与一个系统命令同名，但是Bash 在内部重新实现了这些命令</p>
<table style="width: 100%;" border="1" cellspacing="0" cellpadding="5">
<thead>
<tr>
<td style="text-align: center;"> 命令</td>
<td style="text-align: center;">说明 </td>
</tr>
</thead>
<tbody>
<tr>
<td class="blog_h2" style="width: 200px;">echo</td>
<td>
<p>打印(到stdout)一个表达式或变量，可以用来作为一系列命令的管道输入<br />-e 打印转义字符，如果不指定，斜杠转义按字面输出<br />-n 阻止新起一行<br />注意：echo默认会把换行符替换为空格，要改变此行为，需要在被打印变量外面加""</p>
</td>
</tr>
<tr>
<td class="blog_h2">printf</td>
<td>
<p>格式化输出，是echo 命令的增强。与C语言同名函数类似</p>
</td>
</tr>
<tr>
<td>declare / typeset</td>
<td>
<p><pre class="crayon-plain-tag">declare [-aAfFgilnrtux] [-p] [name[=value] ...]</pre></p>
<p>声明变量，可选的，提供属性</p>
<p>如果不指定任何name，则打印所有变量的值</p>
<p>-p 用于显示变量的值和属性，使用该选项，则其它额外的（除了-f/-F）选项被忽略</p>
<p>-a 声明变量为索引数组<br />-A 声明变量为关联数组<br />-i 变量被作为整数看待，变量被赋值时，自动进行算术扩展<br />-l 赋值的时候，自动转换为小写<br />-u 赋值的时候，自动转换为大写 <br />-r 声明为只读变量，无法被后续赋值或unset<br />-x 变量被export为环境变量</p>
<p>所有选项前面的 - 替换为+，则关闭对应选项</p>
</td>
</tr>
<tr>
<td>local</td>
<td>
<p><pre class="crayon-plain-tag">local [option] [name[=value] ...]</pre></p>
<p>在函数内部使用，声明局部变量，option和declare命令相同</p>
</td>
</tr>
<tr>
<td class="blog_h2">read</td>
<td>
<p>从 stdin 中读取一个变量的值<br />-a 取得数组变量<br />-s 不回显输入<br />-d 读取到该选项指定的字符，而不是默认的换行符<br />-n N 只接受N个字符的输入<br />-p 给出提示文字<br />-t  等待用户输入的时间<br />-r 禁止 \ 进行任何字符的转义</p>
<p>使用read 命令时，输入一个\然后回车，会阻止产生一个新行</p>
</td>
</tr>
<tr>
<td class="blog_h2">cd</td>
<td>-P 忽略符号连接<br />cd - 切换工作目录为$OLDPWD</td>
</tr>
<tr>
<td class="blog_h2">pwd</td>
<td>打印当前的工作目录</td>
</tr>
<tr>
<td class="blog_h2">pushd</td>
<td>pushd dir-name 把路径dir-name 压入目录栈，同时修改当前目录到dir-name</td>
</tr>
<tr>
<td class="blog_h2">popd</td>
<td>popd 将目录栈中最上边的目录弹出，同时修改当前目录到弹出来的那个目录</td>
</tr>
<tr>
<td class="blog_h2">dirs</td>
<td>列出所有目录栈的内容</td>
</tr>
<tr>
<td class="blog_h2">let</td>
<td>执行变量的算术操作，可以看作expr的简化版</td>
</tr>
<tr>
<td class="blog_h2">eval</td>
<td><pre class="crayon-plain-tag">eval arg1 ... [argN]</pre>  将表达式中的参数、或者表达式列表组合起来并估算</td>
</tr>
<tr>
<td class="blog_h2">set</td>
<td>
<p>修改内部脚本变量的值。或者以一个命令的结果(set `command`)来重新设置脚本的位置参数，例如：set `uname -a`; <br />echo $_</p>
<p>&nbsp;</p>
<p>也可以<span style="background-color: #c0c0c0;">用来设置Bash的行为选项</span>：<br /><span style="background-color: #c0c0c0;"><strong>-e</strong> </span>如果一个管道、子Shell命令（括号中包围）、列表（花括号包围）中的某个命令以非0退出，则立即退出Shell。以下情况除外：</p>
<ol>
<li>如果命令列表后面是while/until关键字</li>
<li>如果命令位于if/elif测试中</li>
<li>位于&amp;&amp;或||中，且不在尾部</li>
<li>位于管道（Pipeline）中，且不在尾部</li>
</ol>
<p>你可以在Shell退出前捕获ERR信号</p>
<p><span style="background-color: #c0c0c0;"><strong>-f</strong> </span>禁用路径名（Pathname）展开</p>
<p><strong><span style="background-color: #c0c0c0;">-m</span> </strong>监控模式，启用Job控制，后台进程运行在独立的进程组中</p>
<p><strong><span style="background-color: #c0c0c0;">-o pipefail</span></strong> 如果管道中一个命令失败，则整个管道的退出码为非0</p>
<p>-o errexit  如果某个命令或管道失败，立即退出脚本，等同于 -e</p>
<p><span style="background-color: #c0c0c0;"><strong>+e、+o ... 取消之前的 -e、-o的效果</strong></span></p>
</td>
</tr>
<tr>
<td class="blog_h2">unset</td>
<td>来删除一个shell 变量（设置为null）。对位置参数无效</td>
</tr>
<tr>
<td class="blog_h2">export</td>
<td>使得被export 的变量在运行的脚本（或shell）的所有的子进程中都可用。该命令重要的使用就是用在启动文件中设置环境变量</td>
</tr>
<tr>
<td class="blog_h2">readonly</td>
<td>与 declare -r 作用相同</td>
</tr>
<tr>
<td class="blog_h2">getopts</td>
<td>允许传递和连接多个选项到脚本中，并能分配多个参数到脚本中</td>
</tr>
<tr>
<td class="blog_h2">source / .</td>
<td>
<p>在命令行上执行的时候，将会执行一个脚本</p>
<p>在一个文件内一个source file-name将会加载 file-name 文件；source 一个文件将会在脚本中引入代码，并附加到脚<br />本中（类似于#include）</p>
</td>
</tr>
<tr>
<td class="blog_h2">exit</td>
<td>停止一个脚本的运行。不带参数的exit，等价于exit $?，即最后一条命令的退出码</td>
</tr>
<tr>
<td class="blog_h2">exec</td>
<td>
<p>使用一个特定的命令来取代当前进程。一般的当shell遇到一个命令时，会fork off子进程来运行，使用exec 内建命令将会替换掉当前 shell，命令执行完毕即导致shell进程立即退出</p>
<p>也可以用来重定向脚本的标准输出</p>
</td>
</tr>
<tr>
<td class="blog_h2">shopt</td>
<td>允许 shell 在空闲时修改shell 选项</td>
</tr>
<tr>
<td class="blog_h2">caller</td>
<td>在stdout 上打印出函数调用者的信息</td>
</tr>
<tr>
<td class="blog_h2">ture</td>
<td>一个返回成功（0）退出码的命令</td>
</tr>
<tr>
<td class="blog_h2">flase</td>
<td>一个返回失败（非0）退出码的命令</td>
</tr>
<tr>
<td class="blog_h2">type [command]</td>
<td>将给出command的完整路径</td>
</tr>
<tr>
<td class="blog_h2">bind</td>
<td>令用来显示或修改readline的键绑定</td>
</tr>
<tr>
<td class="blog_h2">shift</td>
<td>
<p>向左移动参数数组$@的元素，可以指定一个数字，表示移动的个数，如果不指定则移动一个</p>
<p>移动1后，$@长度减小1，$1变为￥0</p>
</td>
</tr>
<tr>
<td style="text-align: center;" colspan="2">
<p><strong>作业控制命令（Job Control Commands）</strong></p>
<p style="text-align: left;"><strong>作业标识符</strong></p>
<p style="text-align: left;">%N  作业号[N]<br />%S  以字符串S 开头的被(命令行)调用的作业<br />%?S 包含字符串S 的被(命令行)调用的作业<br />%%、%+ 当前作业(前台最后结束的作业,或后台最后启动的作业)<br />%-  当前作业退出后，该作业变成当前作业<br />$!   最后的后台进程</p>
</td>
</tr>
<tr>
<td class=" blog_h2" style="text-align: left;">jobs</td>
<td>
<p>在后台列出所有正在运行的作业，给出作业号。<span style="background-color: #c0c0c0;">kill %作业号</span>和<span style="background-color: #c0c0c0;">kill 进程号</span>等价：</p>
<pre class="crayon-plain-tag"># 方括号内的是作业号
# Running表示正在运行的作业， 它会打印到标准输出
[1]- Running ping www.baidu.com &amp;
# +表示当前作业，如果fg、bg不指定参数，则针对当前作业
# Stopped表示挂起的作业，但是进程并没有退出
[2]+  Stopped                 ping www.163.com
# -表示如果当前作业退出，则它会变成当前作业
[3]-  Stopped                 ping www.qq.com</pre>
</td>
</tr>
<tr>
<td class=" blog_h2" style="text-align: left;">disown</td>
<td>从 shell 的当前作业表中，删除作业</td>
</tr>
<tr>
<td class=" blog_h2" style="text-align: left;">fg</td>
<td>
<p>把一个后台作业放到前台来运行。不指定作业号，则对当前作业进行处理
</td>
</tr>
<tr>
<td class=" blog_h2" style="text-align: left;">bg</td>
<td>
<p>新启动一个挂起的作业，并且在后台运行它。不指定作业号，则对当前作业进行处理</p>
</td>
</tr>
<tr>
<td class=" blog_h2" style="text-align: left;">wait</td>
<td>停止脚本的运行，直到后台运行的所有作业（或者指定作业号或进程号）都结束为止</td>
</tr>
<tr>
<td class=" blog_h2" style="text-align: left;">suspend</td>
<td>类似Control-Z，但是它挂起的是当前shell</td>
</tr>
<tr>
<td class=" blog_h2" style="text-align: left;">logout</td>
<td>退出一个登陆的 shell，可以指定一个退出码</td>
</tr>
<tr>
<td class=" blog_h2" style="text-align: left;">times</td>
<td>给出执行命令所占的时间</td>
</tr>
<tr>
<td class=" blog_h2" style="text-align: left;">kill</td>
<td>通过发送一个适当的结束信号，来强制结束一个进程</td>
</tr>
<tr>
<td class=" blog_h2" style="text-align: left;">command</td>
<td>
<p>禁用别名和函数的查找，只查找内部命令以及搜索路径中找到的脚本或可执行程序</p>
<p>Bash查找优先级：1.别名 2.关键字 3.函数 4.内置命令 5.脚本或可执行程序($PATH)</p>
</td>
</tr>
<tr>
<td class=" blog_h2" style="text-align: left;">builtin</td>
<td>在"builtin"后边的命令将只调用内建命令</td>
</tr>
<tr>
<td class=" blog_h2" style="text-align: left;">enable</td>
<td>禁用内建（-n）命令或者恢复（-a）内建命令</td>
</tr>
<tr>
<td class=" blog_h2" style="text-align: left;">autoload</td>
<td>带有"autoload"声明的函数，在它第一次被调用的时候才会被加载</td>
</tr>
</tbody>
</table>
<div class="blog_h1"><span class="graybg">外部、系统与管理命令</span></div>
<p>参见：<a href="/linux-command-faq">Linux命令知识集锦</a></p>
<div class="blog_h1"><span class="graybg">高级特性</span></div>
<div class="blog_h2"><span class="graybg">Here Documents</span></div>
<div>所谓Here Documents，是一种特殊用途的代码块，使用某种形式的I/O重定向来为交互式程序或命令提供输入，其形式如下：</div>
<pre class="crayon-plain-tag">command --args &lt;&lt; EOF
...
#注意在这里会发生变量替换，因此需要必要的转义
\$PWD is $PWD
...
...
EOF

# 将Here Document写入到文件
cat &lt;&lt; EOF  &gt; /path/to/file
drill.exec: {
  cluster-id: "$CLUSTER_ID",
  zk.connect: "$ZK_CONNECT"
}
EOF</pre>
<div class="blog_h3"><span class="graybg">禁止变量替换</span></div>
<p>下面两种语法都可以：</p>
<pre class="crayon-plain-tag">cat - &lt;&lt;'EOF'
$KNOWN
EOF
# 输出 $KNOWN

cat - &lt;&lt;\EOF
$KNOWN
EOF</pre>
<div class="blog_h2"><span class="graybg">Here String</span></div>
<p>可以看作是Here Document的stripped-down形式。字符串被展开，并逐个喂给命令的stdin：</p>
<pre class="crayon-plain-tag">COMMAND &lt;&lt;&lt; $WORD</pre>
<p>示例：</p>
<pre class="crayon-plain-tag">if grep -q "txt" &lt;&lt;&lt; "$VAR"
then
   echo "$VAR contains the substring sequence \"txt\""
fi

String="This is a string of words."
# 将字符串中的每个字符写入为数组元素
read -r -a Words &lt;&lt;&lt; "$String" </pre>
<div class="blog_h2"><span class="graybg">I/O重定向</span></div>
<p>Linux中，有三个文件：stdin、stdout、stderr总是处于打开状态的。这些文件或者任何打开的文件，可以被重定向。所谓重定向，就是捕获来自文件、命令、程序、脚本甚至代码块的输出（output），并将其作为其它文件、命令、程序或者脚本的输入。</p>
<pre class="crayon-plain-tag">#重定向输出到文件，如果不存在，则创建，否则覆盖
ls -lR &gt; dir-tree.list
: &gt; filename     #将文件的内容清空，如果不存在则创建

#重定向输出到文件，如果不存在，则创建，否则附加到文件结尾
ls -lR &gt;&gt; dir-tree.list

1&gt;filename       #把标准输出重定向到文件
2&gt;filename       #把标准错误重定向到文件
&amp;&gt;filename       #把标准输出、错误同时重定向到文件

LOGFILE=script.log
echo "命令的输出被重定向到文件描述符" 1&gt;$LOGFILE
echo "命令的错误被重附加到文件描述符" 2&gt;&gt;$LOGFILE

2&gt;&amp;1             #把标准错误重定向到标准输出
i&gt;&amp;j             #重定向文件描述符i到文件描述符j
&gt;&amp;j              #重定向默认文件描述符（1，stdout）到j

0&lt; FILENAME      #从文件读取输入

[j]&lt;&gt;filename    #打开文件进行读写，并分配文件描述符j
exec 3&lt;&gt; File    #打开File，并分配3位文件描述符
read -n 4 &lt;&amp;3    #从文件描述符3读入4字符
echo -n . &gt;&amp;3    #输出一个小数点到文件描述符3
exec 3&gt;&amp;-        #关闭文件描述符3

n&lt;&amp;-             #关闭输入文件描述符n
0&lt;&amp;-, &lt;&amp;-        #关闭标准输入
n&gt;&amp;-             #关闭输出文件描述符n
1&gt;&amp;-, &gt;&amp;-        #关闭标准输出

while [ "$name" != Smith ]
do
    read name
    echo $name
    let "count += 1"
done &lt;"$Filename"#重定向代码块的输入</pre>
<div class="blog_h2"><span class="graybg">子Shell</span></div>
<p>Subshell指Shell发动的子进程。一般的，<span style="background-color: #c0c0c0;">外部命令会发动子Shell</span>，而内置命令则不会，此外，括号包含的命令列表发动Subshell：</p>
<pre class="crayon-plain-tag">( command1; command2; command3; ... )

#Subshell可用于构建专用运行环境
COMMAND1
COMMAND2
COMMAND3
(
    IFS=:
    PATH=/bin
    unset TERMINFO
    set -C
    shift 5
    COMMAND4
    COMMAND5
    exit 3 #这里只会退出Subshell
)</pre>
<p><span style="background-color: #c0c0c0;"> Subshell中的变量，在代码块以外无法访问</span>，相当于局部变量。</p>
<div class="blog_h2"><span class="graybg">受限Shell</span></div>
<p>在受限模式下运行的Shell，一些命令被禁用：</p>
<ol>
<li>使用cd改变当前目录</li>
<li>修改环境变量$PATH, $SHELL, $BASH_ENV,  $ENV</li>
<li>读取或者改变$SHELLOPTS</li>
<li>重定向输出</li>
<li>调用包含/符号的命令</li>
<li>调用exec命令来替换Shell的进程</li>
<li>解除受限模式</li>
<li>其它一些命令</li>
</ol>
<p>使用set -r、set --restricted开启脚本受限模式。</p>
<div class="blog_h2"><span class="graybg">进程替换</span></div>
<p>进程替换把一些进程的输出作为其它进程的输入来使用。命令格式如下（使用括号包围），注意没有空格：</p>
<p>&gt;(command_list)<br />&lt;(command_list)</p>
<div class="blog_h2"><span class="graybg">函数</span></div>
<p>函数语法：</p>
<pre class="crayon-plain-tag">function function_name {
    command...
}
#第二种语法支持C-Style
function_name () {
    if [ -z "$1" ] #$1表示第一个参数
    then
        echo "-Parameter #1 is zero length.-"
    else
        echo "-Param #1 is \"$1\".-"
    fi
}
#调用函数
function_name 
function_name $arg1 $arg2  #传参，只支持传值方式，可以使用间接引用来传引用
#支持函数嵌套
f1 ()
{
    f2 () # nested
    {
        echo "Function \"f2\", inside \"f1\"."
    }
}</pre>
<p> 函数的退出：函数返回一个值，称为exit status，这与命令退出码类似。可以使用return语句指定返回值，否则，最后一条命令的退出码作为返回值。</p>
<div class="blog_h2"><span class="graybg">别名</span></div>
<p>Bash别名可以简单的看作一个键盘快捷方式：</p>
<pre class="crayon-plain-tag">alias ll="ls -l"</pre>
<div class="blog_h2"><span class="graybg">列表构造</span></div>
<p>and list：如果前一个命令的退出码为0，则继续执行后面的命令</p>
<pre class="crayon-plain-tag">command-1 &amp;&amp; command-2 &amp;&amp; command-3 &amp;&amp; ... command-n</pre>
<p> or list：如果前一个命令退出码味非0，则继续执行后面的命令</p>
<pre class="crayon-plain-tag">command-1 || command-2 || command-3 || ... command-n</pre>
<div class="blog_h2"><span class="graybg">数组</span></div>
<p>较新版本的Bash支持一维数组，数组元素以<pre class="crayon-plain-tag">variable[xx]</pre>的方式进行访问，通过<pre class="crayon-plain-tag">${element[xx]}</pre>来获取元素的值。</p>
<pre class="crayon-plain-tag">area[11]=23
area[13]=37
area[51]=UFOs

echo ${area[11]}
area[5]=`expr ${area[11]} + ${area[13]}`

area2=( zero one two three four )
area3=([17]=seventeen [24]=twenty-four)
base64_charset=( {A..Z} {a..z} {0..9} + / = )</pre>
<div class="blog_h3"><span class="graybg">数组长度</span></div>
<p>没有下标的索引点，不会占用元素个数：</p>
<pre class="crayon-plain-tag">adobe=([0]='Flash' [2]='Flex' [4]='Photoshop')
echo ${#adobe[@]}
# 打印 3 </pre>
<div class="blog_h3"><span class="graybg">扩展为列表</span></div>
<p>可以使用表达式：<pre class="crayon-plain-tag">${array[@]}</pre>将数组转换为列表：</p>
<pre class="crayon-plain-tag"># 声明一个数组，它的元素来自DOCKER数组的所有成员 +
#                                    run字面之 +
#                                         docker_run_opts数组的所有成员 +
#                                                                KUBE_BUILD_IMAGE 变量
local -ra docker_cmd=("${DOCKER[@]}" run "${docker_run_opts[@]}" "${KUBE_BUILD_IMAGE}")</pre>
<div class="blog_h3"><span class="graybg">连接操作</span></div>
<p>通过扩展操作，可以连接两个数组：</p>
<pre class="crayon-plain-tag">adobe=('Flash' 'Flex' 'Photoshop' 'Dreamweaver' 'Premiere')
adobe2=('Fireworks' 'Illustrator')
adobe3=(${adobe[@]} ${adobe2[@]}) </pre>
<div class="blog_h3"><span class="graybg">切片操作</span></div>
<pre class="crayon-plain-tag">adobe=('Flash' 'Flex' 'Photoshop' 'Dreamweaver' 'Premiere')
echo ${adobe[@]:1:3}
# 打印 Flex Photoshop Dreamweaver
echo ${adobe[@]:3}
# 打印 Dreamweaver Premiere</pre>
<div class="blog_h3"><span class="graybg">文件读取为数组</span></div>
<pre class="crayon-plain-tag">names=(`cat 'names.txt'`)</pre>
<div class="blog_h3"><span class="graybg">遍历数组</span></div>
<pre class="crayon-plain-tag">adobe=('Flash' 'Flex' 'Photoshop' 'Dreamweaver' 'Premiere')

for item in ${adobe[@]};do
	echo $item
done

len=${#adobe[@]}
for ((i=0;i&lt;$len;i++));do
	echo ${adobe[$i]}
done </pre>
<div class="blog_h2"><span class="graybg">关联数组</span></div>
<p>关联数组也就是字典/映射，声明语法：</p>
<pre class="crayon-plain-tag">declare -A archMap=(
  [x86_64]=amd64
  [aarch64]=arm64
)</pre>
<div class="blog_h3"><span class="graybg">数组长度</span></div>
<pre class="crayon-plain-tag">${#filetypes[*]}
${#filetypes[@]}</pre>
<div class="blog_h3"><span class="graybg">写入元素</span></div>
<pre class="crayon-plain-tag">archMap[arm64]=aarch64 </pre>
<div class="blog_h3"><span class="graybg">获取元素</span></div>
<pre class="crayon-plain-tag">arch=x86_64
${archMap[$arch]}</pre>
<div class="blog_h3"><span class="graybg">获取键列表</span></div>
<pre class="crayon-plain-tag"># 使用*，并且整个表达式用双引号包围，则结果是一个字符串
${!filetypes[*]}
# 使用@，并且整个表达式用双引号包围，则结果是一个数组
${!filetypes[@]}</pre>
<div class="blog_h3"><span class="graybg">获取值列表 </span></div>
<pre class="crayon-plain-tag"># 使用*，并且整个表达式用双引号包围，则结果是一个字符串
"${filetypes[*]}"
# 使用@，并且整个表达式用双引号包围，则结果是一个数组
${filetypes[@]}</pre>
<div class="blog_h3"><span class="graybg">遍历数组</span></div>
<pre class="crayon-plain-tag">for key in "${!filetypes[@]}"; do 
  echo ${filetypes[$key]}
done</pre>
<div class="blog_h2"><span class="graybg">/dev和/proc</span></div>
<p>Unix、Linux的文件系统中，通常都有这两个特殊用途的子目录。</p>
<div class="blog_h3"><span class="graybg"><strong>/dev</strong></span></div>
<p>包含设备文件（device files），包括环回文件（loopback devices，例如/dev/loop0。所谓环回文件是一种虚拟机制，可以将一个普通文件作为块设备访问）。此目录下还包含若干常用的伪设备：/dev/null, /dev/zero,/dev/urandom, /dev/sda1, /dev/udp,/dev/tcp。</p>
<p>/dev/null：相当于一个黑洞，可以用于忽略输出：</p>
<pre class="crayon-plain-tag">#忽略命令的输出
cat $filename &gt;/dev/null
#忽略命令的错误
rm $badname 2&gt;/dev/null

#从中无法读取到任何东西，可以用于清空文件内容
cat /dev/null &gt; /var/log/messages</pre>
<p> /dev/zero：该设备制造二进制0，主要用于生成交换文件</p>
<p>当在/dev/tcp/$host/$port这样的伪设备上执行命令时，Bash会打开一个TCP连接：</p>
<pre class="crayon-plain-tag">#从time.nist.gov获取时间
cat /dev/tcp/www.net.cn/80
echo -e "GET / HTTP/1.0\n" &gt;&amp;5
cat &lt;&amp;5</pre>
<div class="blog_h3"><span class="graybg"><strong>/proc</strong></span></div>
<p>该目录中的文件是当前系统中正在运行的系统和内核进程的镜像，包含了运行时和统计信息。可以获取CPU、内存、电池等多种组件的信息。</p>
<div class="blog_h1"><span class="graybg"><a id="trap"></a>信号处理</span></div>
<p>关于Linux信号相关的知识，参考<a href="/linux-process-and-signals">Linux信号、进程和会话</a></p>
<p>注意：<span style="background-color: #c0c0c0;">如果存在正在运行的子进程，Bash默认会忽略发送给父进程的信号</span>。</p>
<div class="blog_h2"><span class="graybg">trap命令</span></div>
<p>当你在终端窗口按下Ctrl + C或者Break键后，正常情况下应用程序会立即停止。但是你可以在脚本中指定信号处理函数。其格式为：</p>
<pre class="crayon-plain-tag"># arg默认为 - 表示捕获到信号时，需要执行的命令
trap [-lp] [[arg] sigspec ...]</pre>
<p>示例用法：</p>
<pre class="crayon-plain-tag"># 列出信号名称和编号的对应关系
trap -l

# 接收到HUP INT PIPE QUIT TERM这几种信号时，执行exit 1命令
trap "exit 1" HUP INT PIPE QUIT TERM

# 也可以指定函数来处理信号
sighdl() {
}
trap sighdl SIGTERM

# 重置信号的默认处理逻辑
trap 1 2

# 忽略信号
trap '' 1</pre>
<div class="blog_h2"><span class="graybg">trap行为</span></div>
<p>当进程收到信号后，在<span style="background-color: #c0c0c0;">同一线程</span>中发生以下事件序列：</p>
<ol>
<li>当前进程正在进行的内置命令（不产生子进程）立即退出</li>
<li>程序转到trap指定的信号处理脚本执行</li>
<li>执行完毕后，到被中断的命令的下一行执行</li>
</ol>
<p>例如下面的脚本：</p>
<pre class="crayon-plain-tag">trap "echo TRAPED" HUP INT PIPE QUIT TERM
while true; do :; done</pre>
<p>当按下Ctrl + C后，信号处理脚本运行，但是然后会继续循环，程序无法停止。下面的代码则可以正常工作：</p>
<pre class="crayon-plain-tag">sighdl() {
    echo TRAPED
    TERM_FLAG=1
}
trap sighdl HUP INT PIPE QUIT TERM

while [ "$TERM_FLAG" != "1" ] ; do :; done </pre>
<div class="blog_h2"><span class="graybg">处理ERR信号</span></div>
<p>设置选项<pre class="crayon-plain-tag">set -o errexit</pre> / <pre class="crayon-plain-tag">set -e</pre>后，任何一个命令出错，都导致脚本退出，并且释放ERR信号。</p>
<p>要捕获这个信号，你需要选项<pre class="crayon-plain-tag">set -o errexit -o errtrace</pre> / <pre class="crayon-plain-tag">set -eE</pre>，并且：</p>
<pre class="crayon-plain-tag"># 出错时清理后台进程
trap 'kill $(jobs -p)' ERR</pre>
<div class="blog_h1"><span class="graybg">常见问题</span></div>
<div class="blog_h2"><span class="graybg">字符串处理</span></div>
<div class="blog_h3"><span class="graybg">分隔字符串</span></div>
<pre class="crayon-plain-tag"># 分割字符串 1,2,3,4,5,6,7,8,9,10
# IFS指定基于什么符号拆分，这里是逗号
IFS=',' read -ra ARRAY &lt;&lt;&lt; `seq -s ',' 10`
for i in "${ARRAY[@]}"; do
    # 遍历分割后的子串
    echo $i 
done</pre>
<div class="blog_h3"><span class="graybg">字符串匹配</span></div>
<p>可以使用Glob：<pre class="crayon-plain-tag">if [[ $line = *"Server startup in"* ]]; then ...</pre></p>
<div class="blog_h2"><span class="graybg">零散问题</span></div>
<div class="blog_h3"><span class="graybg">如何递归遍历目录</span></div>
<pre class="crayon-plain-tag">#!/bin/bash
shopt -s globstar
for file in ./*.go ./**/*.go ; do
	echo $file
done</pre>
<p><pre class="crayon-plain-tag">./*</pre>表示当前目录下的所有文件，<pre class="crayon-plain-tag">./**/*</pre>则表示任意级别子目录下的所有文件。 需要Bash 4.0+。</p>
<div class="blog_h3"><span class="graybg">在脚本内部重定向标准输出</span></div>
<pre class="crayon-plain-tag">exec 2&gt; /var/log/on-startup.log   # 将当前脚本的标准错误重定向到文件
exec 1&gt;&amp;2                         # 将当前脚本的标准输出重定向到标准错误
set -x</pre>
<div class="blog_h3"><span class="graybg">打印到标准错误</span></div>
<pre class="crayon-plain-tag">echo &gt;&amp;2 "ERROR: "</pre>
<div class="blog_h3"><span class="graybg">循环过早退出</span></div>
<p>如果你读取标准输入，并且循环处理：</p>
<pre class="crayon-plain-tag">while read p; do
  cmd $p
done &lt; input.file</pre>
<p><span style="background-color: #c0c0c0;">当循环体中的命令cmd也会读取标准输入时，上述循环会立即退出</span>。</p>
<p>解决办法：</p>
<pre class="crayon-plain-tag">for p in `cat input.file`
do
  cmd $p
done</pre>
<div class="blog_h3"><span class="graybg">sudo echo &gt;报错</span></div>
<p>报错信息：Permission denied</p>
<p>解决办法：<pre class="crayon-plain-tag">sudo sh -c "echo '' &gt; $LOG"</pre></p>
<div class="blog_h3"><span class="graybg">退出命令管道</span></div>
<p>如果在管道的某个命令中需要退出处理，你需要显式的关闭管道中的其它命令（Subshell），简单的例子：</p>
<pre class="crayon-plain-tag">tail -f /usr/local/$TOMCAT_PATH/logs/catalina.out | while read line
do
    if [[ $line = *"Server startup in"*  ]]; then
          # 找到管道前面的命令tail，并杀死
          TAIL_PID=`ps --ppid $PID  | grep tail | awk '{print $1}'`
          echo "Killing subprocess $TAIL_PID"
          kill -9 $TAIL_PID
          exit 0
    fi
done</pre>
<p>如果管道由很多命令组成，可以将它们放置到同一进程组中，然后向进程组发送信号，一起终结它们：</p>
<pre class="crayon-plain-tag"># 项目的命令启用Job控制，导致后台进程运行在独立的进程组
set -m

tail -Fn0 /tmp/report | while :
do 
    echo "pre"
    # 向后台进程组发送信号，使其中的所有进程终结
    sh -c 'PGID=$( ps -o pgid= $$ | tr -d \  ); kill -TERM -$PGID'
    echo "past"
done &amp;  # 在后台运行
wait    # 等待上述后台任务退出 </pre>
<div class="blog_h3"><span class="graybg">得到脚本所在的目录</span></div>
<pre class="crayon-plain-tag">pushd `dirname $0` &gt; /dev/null
SCRIPT_DIR=`pwd`
popd &gt; /dev/null</pre>
<div class="blog_h3"><span class="graybg">转义单引号</span></div>
<p>单引号字符串默认是禁止转义的，如果其中包含成对的单引号本身，会自动被忽略。</p>
<pre class="crayon-plain-tag">echo '''a'''    # a</pre>
<p> 如果其中包含的单引号不成对，属于语法错误。如果要在单引号字符串中使用单引号本身，可以：</p>
<pre class="crayon-plain-tag">echo  $'\'a\''</pre>
<p>即，在字符串前面加上特殊符号$，即可启用ANSI C风格的转义</p>
<div class="blog_h3"><span class="graybg">变量跨行问题</span></div>
<pre class="crayon-plain-tag">#跨行编写的多行字符串变量
mls="
line 1
line 2
line 3
"

#echo的默认行为是把换行符修改为空格输出
echo $mls
#输出：line 1 line 2 line 3

#目标变量外面加上引号，则可避免此默认行为
echo "$mls"
#输出：
#
#line 1
#line 2
#line 3
#
#可以看到，首尾有空白行，这分别是第一个"后的空白行，以及line3后面的空白行

#行尾加上反斜杠，可以把相邻的两行作为单行看待：
mls="\
line 1
line 2
line 3\
"
#再执行echo "$mls"，就不会有空白行了：
#line 1
#line 2
#line 3

mls="\
line 1
line 2\n
line 3\
"
#默认的，反斜杠转义是不被echo命令启用的，除非指定-e
#执行echo -e  "$mls"，会发现\n被转义为换行输出:
#line 1
#line 2

#line 3

#可以使用 $'\n' 把新行添加到变量尾部
mls="$mls"$'\n'"line 4"

#使用Here Document捕获多行文本到变量
read -d '' mls &lt;&lt; EOF
line 1git-study-note
line 2
line 3
EOF
#首尾不会出现空行
echo "$mls"</pre>
</div><p>The post <a rel="nofollow" href="https://blog.gmem.cc/bash-study-note">Bash学习笔记</a> appeared first on <a rel="nofollow" href="https://blog.gmem.cc">绿色记忆</a>.</p>
]]></content:encoded>
			<wfw:commentRss>https://blog.gmem.cc/bash-study-note/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Windows命令知识集锦</title>
		<link>https://blog.gmem.cc/windows-command-faq</link>
		<comments>https://blog.gmem.cc/windows-command-faq#comments</comments>
		<pubDate>Sun, 15 May 2005 05:23:59 +0000</pubDate>
		<dc:creator><![CDATA[Alex]]></dc:creator>
				<category><![CDATA[Windows]]></category>
		<category><![CDATA[Command]]></category>
		<category><![CDATA[FAQ]]></category>

		<guid isPermaLink="false">http://blog.gmem.cc/?p=2739</guid>
		<description><![CDATA[<p>特殊字符  字符 说明  &#60; 输入重定向 &#62;  输出重定向 () 命令分组 &#38; 命令串联 &#124; 管道 @ 禁止当前命令的回显 ^ 转义字符引导符 cmd.exe的使用  参数  说明 /C 执行指定的命令，之后退出命令shell <a class="read-more" href="https://blog.gmem.cc/windows-command-faq">[...]</a></p>
<p>The post <a rel="nofollow" href="https://blog.gmem.cc/windows-command-faq">Windows命令知识集锦</a> appeared first on <a rel="nofollow" href="https://blog.gmem.cc">绿色记忆</a>.</p>
]]></description>
				<content:encoded><![CDATA[<div class="wri_content_clear_both"><div class="blog_h2"><span class="graybg">特殊字符</span></div>
<table style="width: 100%;" border="1" cellspacing="0" cellpadding="5">
<thead>
<tr>
<td style="width: 150px; text-align: center;"> 字符</td>
<td style="text-align: center;">说明 </td>
</tr>
</thead>
<tbody>
<tr>
<td>&lt;</td>
<td>输入重定向</td>
</tr>
<tr>
<td>&gt; </td>
<td>输出重定向</td>
</tr>
<tr>
<td>()</td>
<td>命令分组</td>
</tr>
<tr>
<td>&amp;</td>
<td>命令串联</td>
</tr>
<tr>
<td>|</td>
<td>管道</td>
</tr>
<tr>
<td>@</td>
<td>禁止当前命令的回显</td>
</tr>
<tr>
<td>^</td>
<td>转义字符引导符</td>
</tr>
</tbody>
</table>
<div class="blog_h2"><span class="graybg">cmd.exe的使用</span></div>
<table style="width: 100%;" border="1" cellspacing="0" cellpadding="5">
<thead>
<tr>
<td style="width: 150px; text-align: center;"> 参数</td>
<td style="text-align: center;"> 说明</td>
</tr>
</thead>
<tbody>
<tr>
<td>/C</td>
<td>执行指定的命令，之后退出命令shell<br />
<pre class="crayon-plain-tag">cmd /c "ipconfig&gt; F:\ipconfig.txt"</pre>
</td>
</tr>
<tr>
<td>/K</td>
<td>执行指定的命令，之后仍保持交互模式</td>
</tr>
<tr>
<td>/A</td>
<td>到文件（或管道〉的命令输出设置为ANSI格式（默认设置）</td>
</tr>
<tr>
<td>/U</td>
<td>到文件（或管道）的命令输出设置为Unicode格式</td>
</tr>
<tr>
<td>/Q</td>
<td>开启静默模式，关闭命令回显</td>
</tr>
<tr>
<td>/T:fg</td>
<td>为控制台窗口设置前台与背录颜色，fg为前背景色代码</td>
</tr>
<tr>
<td>/E:ON</td>
<td>激活命令扩展（默认设置）</td>
</tr>
<tr>
<td>/E:OFF</td>
<td>禁用命令扩展</td>
</tr>
</tbody>
</table>
<div class="blog_h2"><span class="graybg">Cmd Shell内部命令列表</span></div>
<p>可以通过<span style="background-color: #c0c0c0;"> command /?</span>来显示命令帮助。按<span style="background-color: #c0c0c0;">F7</span>可以显示命令历史的弹出窗口，按<span style="background-color: #c0c0c0;">F8</span>可以搜索以当前输入为前缀的命令历史</p>
<table style="width: 100%;" border="1" cellspacing="0" cellpadding="5">
<thead>
<tr>
<td style="width: 150px; text-align: center;"> 命令</td>
<td style="text-align: center;"> 说明</td>
</tr>
</thead>
<tbody>
<tr>
<td>assoc</td>
<td>显示或修改当前的文件扩展关联</td>
</tr>
<tr>
<td>break</td>
<td>设置调试中断</td>
</tr>
<tr>
<td>call</td>
<td>
<p>在一个脚木内调用程序或其他脚本</p>
<p>格式：<br />CALL [drive:][path]filename [batch-parameters]<br />CALL :label arguments</p>
</td>
</tr>
<tr>
<td>cd (chdir)</td>
<td>显示当前目录名或改变当前目录位置</td>
</tr>
<tr>
<td>cls</td>
<td>淸理命令窗口并擦除所幕缓冲区</td>
</tr>
<tr>
<td>color</td>
<td>设置命令shell窗口的文本与背景色</td>
</tr>
<tr>
<td>copy</td>
<td>
<p>将文件从一个位置复制到另外的位置，或者将多个文件连接在起</p>
<p><strong><span style="background-color: #c0c0c0;">格式：</span></strong><br />COPY [/D] [/V] [/N] [/Y | /-Y] [/Z] [/L] [/A | /B ]  source [/A | /B] [+ source [/A | /B] [+ ...]] [destination [/A | /B]]</p>
<p><strong><span style="background-color: #c0c0c0;">选项：</span></strong><br />source 指定被拷贝的源文件<br />/A 指示一个ASCII文本文件<br />/B 指示一个二进制文件<br />/D 允许目标文件解密创建<br />destination 指定目标目录或者目标文件名<br />/V 验证新文件被正确存盘<br />/N 使用短文件名<br />/Y 忽略文件覆盖的提示<br />/-Y 启用覆盖提示<br />/Z 使用可重启模式拷贝网络文件<br />/L 如果源文件是符号连接，则不拷贝真实文件</p>
</td>
</tr>
<tr>
<td>date</td>
<td>显示或设置系统日期</td>
</tr>
<tr>
<td>del (erase)</td>
<td>
<p>删除指定的文件、多个文件或目录</p>
<p><span style="background-color: #c0c0c0;"><strong>格式：</strong></span><br />DEL [/P] [/F] [/S] [/Q] [/A[[:]attributes]] names<br />ERASE [/P] [/F] [/S] [/Q] [/A[[:]attributes]] names</p>
<p><strong><span style="background-color: #c0c0c0;">选项：</span></strong><br />names 指定一个文件或者目录的列表，可以使用通配符，如果指定目录则其中的文件都被删除Specifies a list of one or more files or directories.<br />/P 删除前进行提示<br />/F 强制删除只读文件<br />/S 删除所有子目录中的文件<br />/Q 安静模式，不提示是否删除全局通配符<br />/A 根据文件属性选择需要删除的文件：R只读S系统H隐藏A归档I非索引，-表示非</p>
</td>
</tr>
<tr>
<td>dir</td>
<td>
<p>显示当前目录或指定目录中的子目录与文件列表</p>
<p><strong>格式：</strong><br />DIR [drive:][path][filename] [/A[[:]attributes]] [/B] [/C] [/D] [/L] [/N] [/O[[:]sortorder]] [/P] [/Q] [/R] [/S] [/T[[:]timefield]] [/W] [/X] [/4]</p>
<p><strong>选项：</strong><br />[drive:][path][filename] 指定需要列出的目录或者文件<br />/A 显示具有指定属性的文件<br />/B 使用简单模式，只显示文件名<br />/C 在文件尺寸中显示千位分隔符，这是默认选项，/-C禁止<br />/D 类似于/W，但是文件按列顺序显示<br />/L 使用小写<br />/N 新的长列表格式<br />/O 按顺序列出文件：N按名称S按大小E根据扩展名D根据日期,-表示反序<br />/P 满屏后暂停<br />/Q 显示文件所有者<br />/S 显示指定目录和所有子目录中的数据<br />/T 控制哪个时间字段用于排序：C创建A最后访问W最后修改<br />/W 使用宽列表格式<br />/X 显示non-8dot3短名称<br />/4 显示4位年度</p>
</td>
</tr>
<tr>
<td>dpath</td>
<td>允许程序打开指定目录中的数据文件（就像在当前目录中一样〉</td>
</tr>
<tr>
<td>echo</td>
<td>显示命令行的文本字符串，设置命令回显状态</td>
</tr>
<tr>
<td>endlocal</td>
<td>变量局部化结束</td>
</tr>
<tr>
<td>exit</td>
<td>退出命令shell</td>
</tr>
<tr>
<td>for</td>
<td>对一组文件中的每一文件运行指定的命令 </td>
</tr>
<tr>
<td>ftype</td>
<td>显示当前的文件类型或修改文件类型（文件扩展关联中使用）</td>
</tr>
<tr>
<td>goto</td>
<td>将命令解释器直接跳转到批处理脚本中某个标记行</td>
</tr>
<tr>
<td>if</td>
<td>命令的条件执行</td>
</tr>
<tr>
<td>md (mkdir)</td>
<td>在当前目录或指目录下创建子目录，自动创建必要的父目录</td>
</tr>
<tr>
<td>mklink</td>
<td>为文件或目录创建符号链接或硬链接</td>
</tr>
<tr>
<td>move</td>
<td>
<p>将一个或多个文件从当前目录或指定源目录移动到指定的目标目录，也可以用于对目录进行重命名</p>
<p><strong><span style="background-color: #c0c0c0;">格式：</span></strong><br />移动一个或者多个文件：<br />MOVE [/Y | /-Y] [drive:][path]filename1[,...] destination<br />重命名目录:<br />MOVE [/Y | /-Y] [drive:][path]dirname1 dirname2</p>
<p><strong><span style="background-color: #c0c0c0;">选项：</span></strong><br />[drive:][path]filename1 指定需要一定的文件<br />destination 指定文件的新位置，如果只包含一个源文件，可以指定目标文件名来进行重命名<br />[drive:][path]dirname1 指定需要重命名的目录<br />dirname2 目录的新名称<br />/Y 忽略覆盖的提示</p>
</td>
</tr>
<tr>
<td>path</td>
<td>显示或设置操作系统用于搜索可执行文件与脚本的命令路径</td>
</tr>
<tr>
<td>pause</td>
<td>中断批处理文件的处理过程（挂起），等待键盘输入</td>
</tr>
<tr>
<td>popd</td>
<td>弹出由PUSHD保存的目录，使其成为当前目录</td>
</tr>
<tr>
<td>prompt</td>
<td>为命令提示符设置文本</td>
</tr>
<tr>
<td>pushd</td>
<td>保存当前目录位置，并可选的跳转到指定目录</td>
</tr>
<tr>
<td>rd (rmdir)</td>
<td>
<p>移除目录（也可以移除其子目录）</p>
<p><span style="background-color: #c0c0c0;"><strong>格式：</strong></span><br />RMDIR [/S] [/Q] [drive:]path<br />RD [/S] [/Q] [drive:]path<br /><strong><span style="background-color: #c0c0c0;">选项：</span></strong><br />/S 移除目录树，包括目录本身<br />/Q 不进行删除提示</p>
</td>
</tr>
<tr>
<td>rem</td>
<td>注释</td>
</tr>
<tr>
<td>ren (rename)</td>
<td>
<p>对一个或多个文件进行重命名，不能指定新的路径或者盘符</p>
<p><strong><span style="background-color: #c0c0c0;">格式：</span></strong><br />RENAME [drive:][path]filename1 filename2<br />REN [drive:][path]filename1 filename2</p>
</td>
</tr>
<tr>
<td>set</td>
<td>显示当前的环境变或者为当前命令shell设置临时变量</td>
</tr>
<tr>
<td>sctlocal</td>
<td>在批处理脚本中标记变量内部化的开始</td>
</tr>
<tr>
<td>shift</td>
<td>改变批处理脚本中可替换变量的位置</td>
</tr>
<tr>
<td>start</td>
<td>启动一个单独的窗口，以便运行指定的程序或命令</td>
</tr>
<tr>
<td>time</td>
<td>显示或设置系统时间</td>
</tr>
<tr>
<td>title </td>
<td>设置命令shell窗口的标题</td>
</tr>
<tr>
<td>type</td>
<td>显示文本文件的内容</td>
</tr>
<tr>
<td>verify</td>
<td>在将文件写入磁盘后，指令操作系统对其进行验证</td>
</tr>
<tr>
<td>vol</td>
<td>显示磁盘卷标与序列号</td>
</tr>
</tbody>
</table>
<div class="blog_h2">常用外部命令</div>
<table style="width: 100%;" border="1" cellspacing="0" cellpadding="5">
<thead>
<tr>
<td style="width: 150px; text-align: center;">命令</td>
<td style="text-align: center;">说明</td>
</tr>
</thead>
<tbody>
<tr>
<td>setx</td>
<td>
<p>设置并持久化环境变量</p>
<pre class="crayon-plain-tag">setx PATH "C:\Scripts;%PATH%"</pre>
</td>
</tr>
<tr>
<td>whoami</td>
<td>显示当前登录用户名</td>
</tr>
<tr>
<td>where</td>
<td>
<p>显示程序所在位置：
<pre class="crayon-plain-tag">where cmd.exe
#输出：C:\Windows\System32\cmd.exe

#在指定的目录下（包括子目录）寻找
where /r baseDir filename</pre>
</td>
</tr>
<tr>
<td> netstat</td>
<td>
<p>显示通信协议统计信息以及当前的TCP/IP网络连接
<p><strong><span style="background-color: #c0c0c0;">格式：</span></strong><br />NETSTAT [-a] [-b] [-e] [-f] [-n] [-o] [-p proto] [-r] [-s] [-t] [interval]</p>
<p><span style="background-color: #c0c0c0;"><strong>选项：</strong></span><br />-a 显示所有网络连接和监听端口<br />-b 显示参与创建连接或监听的可执行文件<br />-e 显示以太网统计信息，通常与-s联用<br />-f 显示外部地址的全限定域名（Fully Qualified Domain Names）<br />-n 以数字形式显示地址和端口<br />-o 显示连接的所属进程PID<br />-p proto 显示指定协议类型的连接，协议包括：TCP, UDP, TCPv6, UDPv6，如果使用-s，则可用协议为：IP, IPv6, ICMP, ICMPv6, TCP, TCPv6, UDP, UDPv6<br />-r 显示路由表<br />-s 按协议统计<br />interval 间隔指定秒数后刷新统计，按CTRL+C停止</p>
</td>
</tr>
<tr>
<td>route</td>
<td>
<p>操控路由表</p>
<p><span style="background-color: #c0c0c0;"><strong>格式：</strong></span></p>
<p>ROUTE [-f] [-p] [-4|-6] command [destination] [MASK netmask] [gateway] [METRIC metric] [IF interface]</p>
<p><span style="background-color: #c0c0c0;"><strong>选项：</strong></span><br />-f 清除所有网关条目的路由表，该选项与任何子命令联用，则在执行子命令执行前清除路由表<br />-p 当使用ADD子命令时，使路由信息持久化，重启后仍然生效<br />-4 强制使用IPv4<br />-6 强制使用 IPv6<br />destination 指定主机<br />MASK netmask 指定子网掩码，默认255.255.255.255<br />gateway 指定网关<br />interface 指定路由使用的网卡号<br />METRIC 指定metric，即destination的成本</p>
<p><span style="background-color: #c0c0c0;"><strong>子命令：</strong></span><br />PRINT 打印一条路由信息<br />ADD 添加一条路由信息<br />DELETE 删除一路由信息<br />CHANGE 修改一条路由信息</p>
<p>PRINT、DELETE子命令的destination、gateway可以是通配符（*），gateway可以忽略</p>
<p><span style="background-color: #c0c0c0;"><strong>示例：</strong></span></p>
<pre class="crayon-plain-tag">route PRINT
route PRINT -4
route PRINT -6
rem 仅打印157开头的主机的路由信息
route PRINT 157*
rem 如果不提供IF，会尝试寻找最适合指定网关的网卡
route ADD 157.0.0.0 MASK 255.0.0.0  157.55.80.1 METRIC 3 IF 2
route ADD 3ffe::/32 3ffe::1
route CHANGE 157.0.0.0 MASK 255.0.0.0 157.55.80.5 METRIC 2 IF 2
route DELETE 157.0.0.0
route DELETE 3ffe::/32</pre>
<p>&nbsp;</p>
</td>
</tr>
<tr>
<td> find</td>
<td>
<p>从文本、一个或者多个文件中搜索字符串，如果不指定目标文件路径，则从管道读取输入</p>
<p><span style="background-color: #c0c0c0;"><strong>格式：</strong></span><br />FIND [/V] [/C] [/N] [/I] [/OFF[LINE]] "string" [[drive:][path]filename[ ...]]</p>
<p><span style="background-color: #c0c0c0;"><strong>选项：</strong></span><br />/V 显示所有不包含指定字符串的行 Displays all lines NOT containing the specified string.<br />/C 仅仅显示匹配的行数 Displays only the count of lines containing the string.<br />/N 显示行号 Displays line numbers with the displayed lines.<br />/I 忽略大小写 Ignores the case of characters when searching for the string.<br />/OFF[LINE] 不跳过脱机文件<br />"string" 需要寻找的字符串<br />[drive:][path]filename 目标文件路径</p>
</td>
</tr>
<tr>
<td> runas</td>
<td>
<p>以指定身份运行程序</p>
<p><span style="background-color: #c0c0c0;"><strong>格式：</strong></span><br />RUNAS [ [/noprofile | /profile] [/env] [/savecred | /netonly] ] /user: program<br />RUNAS [ [/noprofile | /profile] [/env] [/savecred] ] /smartcard [/user:] program<br />RUNAS /trustlevel: program</p>
<p><span style="background-color: #c0c0c0;"><strong>选项：</strong></span><br />/noprofile 指示不需要加载用户配置文件<br />/profile 指示需要加载用户配置文件，默认<br />/env 使用当前环境变量而不是用户的<br />/netonly 指示身份验证信息是否仅用户远程访问<br />/savecred 使用之前保存的身份验证信息<br />/smartcard 指示身份信息从智能卡读取<br />/user 用户名，必须是USER@DOMAIN或者DOMAIN\USER格式<br />/showtrustlevels 显示可用的信任级别<br />/trustlevel 指定信任级别<br />program 需要运行的程序</p>
<p><span style="background-color: #c0c0c0;"><strong>举例：</strong></span></p>
<pre class="crayon-plain-tag">runas /noprofile /user:mymachine\administrator cmd
runas /profile /env /user:mydomain\admin "mmc %windir%\system32\dsa.msc"
runas /env /user:user@domain.microsoft.com "notepad \"my file.txt\""</pre>
</td>
</tr>
<tr>
<td>SC</td>
<td>
<p>管理NT服务
<p><span style="background-color: #c0c0c0;">命令格式：</span></p>
<p>SC servicename subCmd</p>
<p><span style="background-color: #c0c0c0;">子命令：</span></p>
<p>SC config 用于配置服务启动与登录账号<br />SC query 用于显示计算机上已配置的所有服务的列表<br />SC qc 用于显示某特定服务的配置<br />SC queryex 查询服务额外信息，例如PID<br />SC delete 删除一个服务（从注册表）<br />SC start 用于启动服务<br />SC stop 用于结束服务<br />SC pause 用于暂停服务<br />SC continue 用子恢复服务<br />SC failure 用于设置服务失效时执行的操作<br />SC qfailure 用于查看服务失效时执行的操作</p>
<p><span style="background-color: #c0c0c0;">举例：</span></p>
<pre class="crayon-plain-tag">rem 査看系统中己配置的所有服务
sc query type= service state= all
rem 査看远程机器中己配置的所有服务
sc ServerName query type= service state= all
rem 一定要注意等于号后面的空格
sc \\192.168.1.100 query type= service state= all

rem 启动某服务
sc start ServiceName
rem 暂停某服务
sc pause ServiceName
rem 恢复暂停的服务
sc continue ServiceName
rem 终止某服务
sc stop ServiceName

rem 配置服务启动方式
sc config ServiceName start= Auto|Demand|Disabled|Delayed-Auto

rem 使用本地系统用户SYSTEM登陆
sc config ServiceName obj= LocalSystem</pre>
</td>
</tr>
<tr>
<td>shutdown</td>
<td>
<p>关机命令
<pre class="crayon-plain-tag">rem 关闭本地系统
shutdown /s /t ShutdownDelay /l /f
rem 重启本地系统
shutdown /r /t ShutdownDelay /l /f
rem 取消本地计算机的延迟关机
shutdown /a</pre>
</td>
</tr>
<tr>
<td>tasklist</td>
<td>
<p>显示进程列表
<pre class="crayon-plain-tag">rem 查看进程使用的模块（DLL）
tasklist /M
rem 显示系统进程与服务的对应关系
tasklist /Svc
rem 显示远程机器上的进程列表
tasklist /s 192.168.1.15 /u admin\pswd

rem 使用Eq/Ne/Gt/Lt/Ge/Le操作符可以对tasklist结果进行过滤
rem 过滤查询条件包括：
rem CPUTime        以hh:mm:ss格式呈现的任意有效值
rem Services       任意有效的字符串
rem ImageName      任意有效的字符串
rem MemUsage       以KB为计数单位的任意有效值
rem Modules        DLL名称
rem PID            任意有效的正整数
rem Session        任意有效的会话编号
rem SessionName    任意有效的字符串
rem Status         运行、无响应、未知
rem Username       任意有效的用户名，只包括用户名，或者以域\用户的格式
rem WindowTitle    任意有效的宁符串

rem 在silverstone上搜索占用CPU时间超过30分钟的进程:
tasklist /s silverstone /fi "Mcputime gt 00:30:00"
rem 在silverstone上搜索占用内存超过20000KB的进程:
tasklist /s silverstone /u admin\pswd /fi "memusage gt 20000"
rem 连续使用/fi可以添加多个过滤器</pre>
</td>
</tr>
<tr>
<td>taskkill</td>
<td>
<p>终止进程
<pre class="crayon-plain-tag">rem 终止进程ID为208的进程：
taskkill /pid 208
rem 终止镜像名为java.exe的所有进程：
taskkill /im java.exe
rem 终止silverstone上进程ID为208、1346、2048的进程: 
taskkill /s silverstone /pid 208 /pid 1346 /pid 2048 
rem 强制终止PID为1346的进程： 
taskkill  /f /pid 1346
rem 终止进程树，以PID为1248的进程开始，包括所有子进程: 
taskKill /t /pid 1248
rem 终止失去响应的cmd.exe进程
taskkill /im cmd.exe /fi "status eq not responding"</pre>
</td>
</tr>
<tr>
<td>Schtasks</td>
<td>
<p>管理计划任务
<p><span style="background-color: #c0c0c0;">子命令：</span><br />Schtasks /Create 用于创建计划任务。<br />Schtasks /Change 用于改变现有任务的属性。<br />Schtasks /Query 用于在本地计算机或其他指定的计算机上显示计划任务<br />Schtasks/Run 用于立即启动计划任务<br />Schtasks /End 用于终止运行中的任务<br />Schtasks /Delete 用于删除不再需要的任务</p>
<pre class="crayon-plain-tag">rem 创建计划任务
rem 命令格式（注意空格要双引号处理）：
rem schtasks /create /tn taskName /tr cmd /sc ScheduleType [/mo Modifier]
rem /st startTime(HH:MM) /sd startDate(系统默认日期格式)
rem /et endTime /ed endDate    /Z 完成后删除任务
rem   调度类型   说明
rem   MINUTE    以指定间隔（分钟为单位）执行，默认1分钟，Modifier：/mo 1-1439
rem   HOURLY    以指定间隔（小时为单位）执行，默认1小时，Modifier：/mo 1-23
rem   DAILY     以指定间隔（天为单位）执行，默认每天，Modifier：/mo 1-365
rem   WEEKLY    以指定间隔（周为单位）执行，默认每周一，Modifier：/mo 1-365    
rem   MONTHLY   以指定间隔（月为单位）执行，默认每月第一天，Modifier：/mo 1-12 
rem   ONCE      在指定的时间与日期执行一次
rem   ONEVENT   在指定事件发生时执行 /mo XPathString 事件查询字符串
rem   ONSTART   系统启动时运行
rem   ONLOGON   用户登录时运行
rem   ONIDLE    系统空闲时运行，/i 1-999系统空闲的分钟数
 
rem 创建一个任务，该任务立即运行一次，之后不再运行:
schtasks /create /tn "SysChecks" /tr c:\sch.bat /sc once
rem 创建一个任务，该任务在本地计算机上每隔15分钟运行：
schtasks /create /tn "SysChecks" /tr c:\sch.bat /sc minute /mo 15
 
rem 创建一个任务，该任务在本地计算机上每隔2天运行:
schtasks /create /tn "SysChecks" /tr c:\sch.bat /sc daily /mo 2
rem 创建一个任务，该任务在每隔两个星期的星期一（默认的运行日期）运行:
schtasks /create /tn "SysChecks" /tr c:\sch.bat /sc weekly /mo 2
rem 创建一个任务，该任务在每个星期的周一与周五运行：
schtasks /create /tn "SysChecks" /tr c:\sch.bat /sc weekly /d mon, fri
rem 创達一个任务，该任务在每个月的第1天运行：
schtasks /create /tn "SysChecks" /tr c:\sch.bat /sc monthly
rem 创建一个任务.该任务在每隔一个月的第5天运行：
schtasks /create /tn "SysChecks" /tr c:\sch.bat /sc monthly /mo 2 /d 5
rem 创建一个任务，该任务在每个月的最后一天运行：
schtasks /create /tn "SysChecks" /tr c:\sysch.bat /sc monthly /mo lastday
rem 删除计划任务
schtasks /delete /tn "SysChecks"</pre>
</td>
</tr>
</tbody>
</table>
<div class="blog_h2"><span class="graybg">常用MSC</span></div>
<table style="width: 100%;" border="1" cellspacing="0" cellpadding="5">
<thead>
<tr>
<td style="width: 150px; text-align: center;"> MSC</td>
<td style="text-align: center;"> 说明</td>
</tr>
</thead>
<tbody>
<tr>
<td> devmgmt.msc</td>
<td> 设备管理器</td>
</tr>
<tr>
<td> diskmgmt.msc</td>
<td> 磁盘管理</td>
</tr>
<tr>
<td> services.msc</td>
<td> 本地服务配置</td>
</tr>
<tr>
<td> perfmon.msc</td>
<td> 性能监控</td>
</tr>
<tr>
<td> rsop.msc</td>
<td> 组策略结果集</td>
</tr>
<tr>
<td> lusrmgr.msc</td>
<td> 本地用户和组管理</td>
</tr>
<tr>
<td> fsmgmt.msc</td>
<td> 共享文件夹管理</td>
</tr>
<tr>
<td> gpedit.msc</td>
<td> 组策略编辑器</td>
</tr>
</tbody>
</table>
<div class="blog_h2"><span class="graybg">注册表管理命令</span></div>
<p>注意，命令中ROOTKEY使用简写： HKLM | HKCU | HKCR | HKU | HKCC 
<p>数据类型列表：REG_SZ | REG_MULTI_SZ | REG_EXPAND_SZ |  REG_DWORD | REG_QWORD | REG_BINARY | REG_NONE</p>
<table style="width: 100%;" border="1" cellspacing="0" cellpadding="5">
<thead>
<tr>
<td style="width: 150px; text-align: center;">命令 </td>
<td style="text-align: center;">说明 </td>
</tr>
</thead>
<tbody>
<tr>
<td>REG QUERY</td>
<td>可以引用想要操作的键名或键值的全路径来读取注册表值</p>
<p><span style="background-color: #c0c0c0;">格式：</span><br />REG QUERY KeyName [/v [ValueName] | /ve] [/s] [/f Data [/k] [/d] [/c] [/e]] [/t Type] [/z] [/se Separator]<br /><span style="background-color: #c0c0c0;">选项：</span><br />KeyName 以[\\Machine\]FullKey的形式出现，Machine为远程机器的名字，仅仅HKLM、HKU可以在远程机器上使用。FullKey以ROOTKEY\SubKey的形式出现<br />/v 查询指定的键值，如果不指定，则键下的所有值被查询<br />/ve 查询默认值<br />/s 递归的查询子键的值<br />/se 多行文本（REG_MULTI_SZ）的分隔字符<br />/f 指定需要检索的PATTERN，可以使用*，如果有空格需要引号<br />/k 仅在键的名字中检索<br />/d 仅在数据中检索<br />/c 指定大小写敏感<br />/e 仅返回精确匹配的项目<br />/t 指定匹配的注册表数据类型<br />/z 显示冗长信息</p>
<p><span style="background-color: #c0c0c0;">举例：</span></p>
<pre class="crayon-plain-tag">rem 显示注册表版本
REG QUERY HKLM\Software\Microsoft\ResKit /v Version
rem 显示远程机器上Setup的所有子键
EG QUERY \\silverstone\HKLM\Software\Microsoft\ResKit\Nt\Setup /s
rem 显示所有子键和值，多行文本使用#作为分隔符
REG QUERY HKLM\Software\Microsoft\ResKit\Nt\Setup /se #
rem 显示精确匹配SYSTEM的键、值、数据
REG QUERY HKLM /f SYSTEM /t REG_SZ /c /e</pre>
</td>
</tr>
<tr>
<td>REG ADD</td>
<td>添加或者覆盖键值
<p><span style="background-color: #c0c0c0;">格式：</span><br />REG ADD KeyName [/v ValueName | /ve] [/t Type] [/s Separator] [/d Data] [/f]</p>
<p><span style="background-color: #c0c0c0;">选项：</span><br />KeyName 键的名称，格式同REG ADD<br />/v 在键下需要添加的值的名称<br />/ve 设置键的默认值<br />/t 值数据类型<br />/s 多行文本分隔符<br />/d 需要赋给值的数据<br />/f 强制覆盖已有的键值</p>
<p><span style="background-color: #c0c0c0;">举例：</span></p>
<pre class="crayon-plain-tag">rem 在silverstone机器上添加Gmem键
REG ADD \\silverstone\HKLM\Software\Gmem
rem 添加一个值，名称为Data，类型为REG_BINARY，值为十六进制fe340ead，强制覆盖已有值
REG ADD HKLM\Software\Gmem /v Data /t REG_BINARY /d fe340ead /f</pre>
</td>
</tr>
<tr>
<td>REG DELETE</td>
<td>
<p>删除指定的键值
<p><span style="background-color: #c0c0c0;">格式：</span><br />REG DELETE KeyName [/v ValueName | /ve | /va] [/f]</p>
<p><span style="background-color: #c0c0c0;">选项：</span><br />KeyName 键的名称，格式同REG ADD<br />ValueName 值的名称，如果不指定，则键被清空<br />/ve 删除默认值<br />/va 删除此键下的所有值<br />/f 强制删除不提示</p>
</td>
</tr>
<tr>
<td>REG COPY</td>
<td>
<p>复制键</p>
<p><span style="background-color: #c0c0c0;">格式：</span><br />REG COPY KeyName1 KeyName2 [/s] [/f]</p>
<p><span style="background-color: #c0c0c0;">选项：</span><br />KeyName 键的名称，格式同REG ADD<br />/s 复制所有子键和值<br />/f 强制复制不提示</p>
</td>
</tr>
<tr>
<td>REG SAVE</td>
<td>
<p>保存键到文件</p>
<p><span style="background-color: #c0c0c0;">格式：</span><br />REG SAVE KeyName FileName [/y]</p>
<p><span style="background-color: #c0c0c0;">选项：</span><br />KeyName 键的名称，格式同REG ADD<br />FileName 保存的文件名<br />/y 强制覆盖已经存在的文件</p>
</td>
</tr>
<tr>
<td>REG RESTORE</td>
<td>
<p>从文件中还原键</p>
<p><span style="background-color: #c0c0c0;">格式：</span><br />REG RESTORE KeyName FileName</p>
</td>
</tr>
<tr>
<td>REG LOAD</td>
<td>加载键</td>
</tr>
<tr>
<td>REG UNLOAD</td>
<td>卸载键</td>
</tr>
<tr>
<td>REG COMPARE</td>
<td>比较两个键</td>
</tr>
<tr>
<td>REG EXPORT</td>
<td>导出.reg文件</td>
</tr>
<tr>
<td>REG IMPORT</td>
<td>导入.reg文件</td>
</tr>
</tbody>
</table>
<div class="blog_h2"><span class="graybg">常用第三方工具</span></div>
<div class="blog_h3"><span class="graybg">PSTools</span></div>
<p>PsTools是Sysinternals公司推出的一个功能强大的远程管理工具包：</p>
<table style="width: 100%;" border="1" cellspacing="0" cellpadding="5">
<thead>
<tr>
<td style="width: 150px; text-align: center;">命令 </td>
<td style="text-align: center;"> 说明</td>
</tr>
</thead>
<tbody>
<tr>
<td>PsExec</td>
<td>在远程系统上执行指定的程序，如果目标程序是交互式的控制台应用，保持其交互性</p>
<p>格式：<br />psexec [\\computer[,computer2[,...] | @file]][-u user [-p psswd][-n s][-r servicename][-h][-l][-s|-e][-x][-i [session]][-c [-f|-v]][-w directory][-d][- ][-a n,n,...] cmd [arguments]</p>
<p><span style="background-color: #c0c0c0;">选项：</span><br />-a 指定运行程序的处理器序号，逗号分隔<br />-c 复制指定的程序到远程系统用于执行，如果无此选项，远程系统的PATH中必须存在要执行的程序<br />-d 不等待远程进程结束，立即返回<br />-e 不加载用户的配置<br />-f 即使远程系统已经存在要执行的程序，依然拷贝<br />-i 让运行的程序与指定Session的远程桌面交互<br />-h 提升用户级别并执行<br />-l 以限制身份运行<br />-n 连接远程系统的超时<br />-p 指定用户的密码<br />-r 指定需要创建或者交互的远程服务<br />-s 使用SYSTEM用户运行远程程序<br />-u 指定登陆用户<br />-v 只有程序版本更新，才拷贝到远程机器<br />-w 设置远程程序的工作目录<br />-x 显示UI，仅本地系统<br />-priority 设置运行优先级：-low, -belownormal, -abovenormal, -high, -realtime<br />computer 指定需要运行程序的远程机器，如果使用\\*，则域中所有机器都执行<br />@file 在文件中列出的机器中执行<br />cmd 需要执行的命令<br />arguments 参数<br />-accepteula 禁止显示License信息</p>
</td>
</tr>
<tr>
<td>PsFile</td>
<td>列出或者关闭打开的远程文件</p>
<p><span style="background-color: #c0c0c0;">格式：</span><br />PsFile [\\RemoteComputer [-u Username [-p Password]]] [[Id | path] [-c]]</p>
<p><span style="background-color: #c0c0c0;">选项：</span><br />-u 登陆用户名<br />-p 登陆密码<br />Id 需要显示或者关闭的文件ID，如果不指定，将关闭或者列出所有文件<br />Path 用于匹配的全部或者部分文件路径<br />-c 根据ID挂壁文件</p>
</td>
</tr>
<tr>
<td>PsGetSid</td>
<td>在系统标识符（SID）和系统名称之间进行转换</td>
</tr>
<tr>
<td>PsInfo</td>
<td>显示系统信息</td>
</tr>
<tr>
<td>PsPing</td>
<td>类似ping</td>
</tr>
<tr>
<td>PsKill</td>
<td>终结远程机器上的进程</td>
</tr>
<tr>
<td>PsList</td>
<td>显示远程机器上的进程</td>
</tr>
<tr>
<td>PsLoggedOn</td>
<td>显示远程机器上登陆的用户</td>
</tr>
<tr>
<td>PsLogList</td>
<td>dump远程或者本地机器上的系统日志</td>
</tr>
<tr>
<td>PsPasswd</td>
<td>修改本地或者远程机器用户密码</td>
</tr>
<tr>
<td>PsService</td>
<td>列出、控制本地或者远程机器的服务</td>
</tr>
<tr>
<td>PsShutdown</td>
<td>注销、关机、重启远程或本地机器</td>
</tr>
<tr>
<td>PsSuspend</td>
<td>暂停本地或者远程机器的进程</td>
</tr>
</tbody>
</table>
<div class="blog_h3"><span class="graybg">其它</span></div>
<table class="fixed-word-wrap" style="width: 100%;" border="1" cellspacing="0" cellpadding="5">
<thead>
<tr>
<td style="width: 150px; text-align: center;"> 命令</td>
<td style="text-align: center;">说明 </td>
</tr>
</thead>
<tbody>
<tr>
<td>winrar</td>
<td>以命令行方式使用WinRAR软件<br />
<pre class="crayon-plain-tag">rem 压缩，把hello.txt压缩为hello.rar
rem -mN是可选参数N取值0-5越大压缩比越高
rem -df 可选参数，压缩后删除原文件
winrar a -m5 hello.rar hello.txt
rem 解压，不保留压缩文件中的目录结构
winrar e hello.rar
rem 解压，保留压缩文件中的目录结构
winrar x hello.rar</pre>
</td>
</tr>
</tbody>
</table>
</div><p>The post <a rel="nofollow" href="https://blog.gmem.cc/windows-command-faq">Windows命令知识集锦</a> appeared first on <a rel="nofollow" href="https://blog.gmem.cc">绿色记忆</a>.</p>
]]></content:encoded>
			<wfw:commentRss>https://blog.gmem.cc/windows-command-faq/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>MS-DOS批处理学习笔记</title>
		<link>https://blog.gmem.cc/bat</link>
		<comments>https://blog.gmem.cc/bat#comments</comments>
		<pubDate>Fri, 02 Jul 2004 06:46:12 +0000</pubDate>
		<dc:creator><![CDATA[Alex]]></dc:creator>
				<category><![CDATA[Windows]]></category>
		<category><![CDATA[BAT]]></category>
		<category><![CDATA[Command]]></category>
		<category><![CDATA[DOS]]></category>
		<category><![CDATA[学习笔记]]></category>

		<guid isPermaLink="false">http://blog.gmem.cc/?p=1937</guid>
		<description><![CDATA[<p>基础知识 关于目录 任何一个目录下均有[crayon-69e4c2207fee3927173074-i/]、[crayon-69e4c2207fee7291914635-i/]这两个虚拟目录，其中[crayon-69e4c2207fee9146032884-i/]指向当前目录，[crayon-69e4c2207feeb091500361-i/]指向上级目录： [crayon-69e4c2207feed633901530/] 基本命令与概念 符号  说明 @前缀 取消当前命令的回显 ECHO OFF 禁用命令回显 SET 显示、设置或删除环境变量 [crayon-69e4c2207fef0039107255/] ECHO. 显示空行 PUSHD 压栈并切换到指定工作目录，例如PUSHD C:\TEMP POPD 弹出并回到上一个工作目录 <a class="read-more" href="https://blog.gmem.cc/bat">[...]</a></p>
<p>The post <a rel="nofollow" href="https://blog.gmem.cc/bat">MS-DOS批处理学习笔记</a> appeared first on <a rel="nofollow" href="https://blog.gmem.cc">绿色记忆</a>.</p>
]]></description>
				<content:encoded><![CDATA[<div class="wri_content_clear_both"><div class="blog_h1"><span class="graybg">基础知识</span></div>
<div class="blog_h2"><span class="graybg">关于目录</span></div>
<p>任何一个目录下均有<pre class="crayon-plain-tag">.</pre>、<pre class="crayon-plain-tag">..</pre>这两个虚拟目录，其中<pre class="crayon-plain-tag">.</pre>指向当前目录，<pre class="crayon-plain-tag">..</pre>指向上级目录：</p>
<pre class="crayon-plain-tag">pushd D:\Programs\chrome

rem 下面两条还是进入当前目录
cd D:\Programs\chrome\.
cd Programs\chrome\.\.\.

rem 进入上级目录
cd D:\Programs\chrome\..
rem 进入上级目录的上级目录
cd D:\Programs\chrome\..\..</pre>
<div class="blog_h2"><span class="graybg">基本命令与概念</span></div>
<table style="width: 100%;" border="1" cellspacing="0" cellpadding="5">
<thead>
<tr>
<td style="width: 100px; text-align: center;">符号</td>
<td style="text-align: center;"> 说明</td>
</tr>
</thead>
<tbody>
<tr>
<td>@前缀</td>
<td>取消当前命令的回显</td>
</tr>
<tr>
<td>ECHO OFF</td>
<td>禁用命令回显</td>
</tr>
<tr>
<td>SET</td>
<td>显示、设置或删除环境变量<br />
<pre class="crayon-plain-tag">rem expression被扩展为算术表达式
SET /A variable=expression
rem 从标准输入读入一行，promptString为读入前显示的文本
SET /P variable=[promptString]</pre>
</td>
</tr>
<tr>
<td>ECHO.</td>
<td>显示空行</td>
</tr>
<tr>
<td>PUSHD</td>
<td>压栈并切换到指定工作目录，例如PUSHD C:\TEMP</td>
</tr>
<tr>
<td>POPD</td>
<td>弹出并回到上一个工作目录</td>
</tr>
<tr>
<td>组合命令</td>
<td>&amp;：串联多个命令，依次执行<br /> &amp;&amp;：只有前面命令成功了，后面命令才执行<br /> ||：只有前面命令失败了，后面命令才执行</td>
</tr>
<tr>
<td>" "</td>
<td>字符串界定符——允许在字符串中包含空格</td>
</tr>
<tr>
<td>^</td>
<td>
<p>转义字符，例如^G表示响铃</p>
<p>在行尾，表示下一行的内容与这一行作为<span style="background-color: #c0c0c0;">单行</span>看待</p>
</td>
</tr>
<tr>
<td>*</td>
<td>通配0-N个字符</td>
</tr>
<tr>
<td>%</td>
<td>批处理变量引导符。%VAR%引用环境变量，%n引用调用参数，%*表示所有调用参数</td>
</tr>
<tr>
<td>!VAR!</td>
<td>变量延迟扩展符</td>
</tr>
<tr>
<td>?</td>
<td>通配单个字符</td>
</tr>
<tr>
<td>COLOR</td>
<td>设置背景前景色，使用一位数表示颜色。例如COLOR 47表示红色背景白色文字</p>
<p>0 = 黑色 1 = 蓝色 3 = 湖蓝色 B = 淡浅绿色 4 = 红色 C = 淡红色 5 = 紫色<br /> 6 = 黄色E = 淡黄色 7 = 白色 8 = 灰色 9 = 淡蓝色 2 = 绿色 A = 淡绿色  D = 淡紫色</p>
</td>
</tr>
<tr>
<td>TITLE</td>
<td>设置窗口标题</td>
</tr>
<tr>
<td>FIND</td>
<td>
<p>在文本中搜索字符串，命令格式： </p>
<pre class="crayon-plain-tag">FIND [/V] [/C] [/N] [/I] [/OFF[LINE]] "string" [[drive:][path]filename[ ...]]</pre>
<p>/V 显示所有未包含指定字符串的行<br /> /C 仅显示包含字符串的行数<br /> /N 显示行号<br /> /I 搜索字符串时忽略大小写<br /> /OFF[LINE] 不要跳过具有脱机属性集的文件"string" 指定要搜索的文字串<br /> [drive:][path]filename 指定要搜索的文件</p>
</td>
</tr>
<tr>
<td>ATTRIB</td>
<td>显示或更改文件属性，命令格式：<br />
<pre class="crayon-plain-tag">ATTRIB [+R|-R] [+A|-A] [+S|-S] [+H|-H] [[drive:] [path] filename] [/S [/D]]</pre></p>
<p>+ 设置属性， - 清除属性<br />R 只读文件属性， A 存档文件属性， S 系统文件属性， H 隐藏文件属性<br />/S 处理当前文件夹及其子文件夹中的匹配文件， /D 也处理文件夹</p>
</td>
</tr>
<tr>
<td>NUL</td>
<td>空设备<br /><pre class="crayon-plain-tag">1&gt;nul</pre>  表示禁止输出一般信息（重定向标准输出到空设备）<br /><pre class="crayon-plain-tag">2&gt;nul</pre> 表示禁止输出错误信息（重定向标准错误到空设备）</td>
</tr>
<tr>
<td>Ctrl+C</td>
<td>按键中断批处理执行</td>
</tr>
<tr>
<td>Ctrl+S</td>
<td>暂停或者恢复显示</td>
</tr>
<tr>
<td>~</td>
<td>扩展符号，对于变量%1，可以这样使用%~x1：取变量的扩展名。支持的扩展列表：</p>
<p>%~1 扩展 %1 并删除任何引号 ("")<br /> %~f1 将 %1 扩展到全限定的路径名<br /> %~d1 将 %1 扩展到驱动器盘符<br /> %~p1 将 %1 扩展到路径<br /> %~n1 将 %1 扩展到文件名<br /> %~x1 将 %1 扩展到文件扩展名<br /> %~s1 扩展的路径仅包含短名称<br /> %~a1 将 %1 扩展到文件属性<br /> %~t1 将 %1 扩展到文件日期/时间<br /> %~z1 将 %1 扩展到文件大小<br /> %~$PATH:1 搜索 PATH 环境变量中列出的目录，并将 %1 扩展到第一个找到的目录的完全限定名称。如果没有定义环境变量名称，或没有找到文件，则此符号扩展成空字符串</p>
<div>获取bat所在目录的例子：</div>
<pre class="crayon-plain-tag">set BAT_PATH0=%~dp0
set BAT_PATH=%BAT_PATH0:~0,-1%
for %%f in (%BAT_PATH%) do set BAT_FOLDER=%%~nxf
echo %BAT_FOLDER%</pre>
</td>
</tr>
<tr>
<td>|</td>
<td>管道符：将一个命令的输出作为另外一个命令的输入</td>
</tr>
<tr>
<td>&gt; TARGET</td>
<td>重定向输出<br />
<pre class="crayon-plain-tag">rem 将第一个命令的输出作为第二个命令的输入
command1&gt;commana2  
rem 将输出发送到指定的文件，必要的时候需要创建该文件或重写
command&gt;[path]filename
rem 将输出附加到指定的文件（如果该文件存在），或者创建该文件并向其写入
command&gt;&gt;[path]filename
rem 从指定的文件中获取命令的输入，之后将命令的输出发送到指定的文件
command&lt;[path] filename &gt;[path]filename
rem 从指定的文件中获取命令的输入，之后将命令的输出附加到指定的文件
command&lt;[path]filename&gt;&gt;[path]fllename
rem 创建指定的文件，之后将错误输出发送到该文件。如果该文件存在，则其内容会被重写
command 2&gt; [path]filename
rem 将错误输出信总发送到标准输出
command 2&gt;&amp;1
rem 将标准错误丢弃，不显示
command 2&gt; nul
rem 从指定的文件路径中提取命令的输入信息
command&lt;[path]filename</pre>
</td>
</tr>
<tr>
<td>&gt;&gt; TARGET</td>
<td>重定向输出，附加模式</td>
</tr>
<tr>
<td>&lt; SOURCE</td>
<td>重定向输入</td>
</tr>
<tr>
<td>REM</td>
<td>注释，内容可以回显。::这样的注释则不会回显</td>
</tr>
<tr>
<td>PAUSE</td>
<td>暂停执行，按任意键继续ECHO 定制的提示语 &amp; pause &gt; nul</td>
</tr>
<tr>
<td>SHIFT</td>
<td>参数移位，即第二个参数变为第一个，第一个移除，命令格式 SHIFT n ，其中 0&lt;=n&lt;=8</td>
</tr>
<tr>
<td>CALL</td>
<td>在一个批处理程序中调用另外一个，执行完毕后返回CALL :label arguments，调用当前批处理文件内的命令段——:label开头，以命令goto :eof结尾的部分</td>
</tr>
<tr>
<td>START</td>
<td>在新的命令行窗口中执行程序，命令格式：start ["title"] [/dPath] [/i] [/min] [/max] [{/separate | /shared}] [{/low | /normal | /htgh | /realtime | /abovenormal | belownormal}] [/wait] [/b] [FileName] [parameters]
<p>title:指定在“命令提示符”窗口标题栏中显示的标题<br /> /dPath:指定启动目录<br /> /i:将Cmd.exe启动环境传送到新的“命令提示符”窗口<br /> /min:启动新的最小化“命令提示符”窗口<br /> /max:启动新的最大化“命令提示符”窗口<br /> /separate:在单独的内存空间启动16位程序<br /> /shared:在共享的内存空间启动16位程序<br /> /low:以空闲优先级启动应用程序<br /> /normal:以一般优先级启动应用程序<br /> /high:以高优先级启动应用程序<br /> /realtime:以实时优先级启动应用程序<br /> /abovenormal：以超出常规优先级的方式启动应用程序<br /> /bdownormal:以低出常规优先级的方式启动应用程序<br /> /wait:启动应用程序，并等待其结束<br /> /b:启动应用程序时不必打开新的“命令提示符”窗口<br /> FileName:指定要启动的命令或程序<br /> parameters:指定要传送给命令或程序的参數</p>
</td>
</tr>
</tbody>
</table>
<div class="blog_h2"><span class="graybg">动态环境变量</span></div>
<table style="width: 100%;" border="1" cellspacing="0" cellpadding="5">
<thead>
<tr>
<td style="width: 100px; text-align: center;">变量</td>
<td style="text-align: center;"> 说明</td>
</tr>
</thead>
<tbody>
<tr>
<td>%CD%</td>
<td>扩展到当前目录字符串</td>
</tr>
<tr>
<td>%DATE%</td>
<td>用跟 DATE 命令同样的格式扩展到当前日期</td>
</tr>
<tr>
<td>%TIME%</td>
<td>用跟 TIME 命令同样的格式扩展到当前时间</td>
</tr>
<tr>
<td>%RANDOM%</td>
<td>扩展到 0 和 32767 之间的任意十进制数字</td>
</tr>
<tr>
<td>%ERRORLEVEL%</td>
<td>扩展到当前 ERRORLEVEL 数值</td>
</tr>
<tr>
<td>%CMDEXTVERSION%</td>
<td>扩展到当前命令处理器扩展名版本号</td>
</tr>
<tr>
<td>%CMDCMDLINE%</td>
<td>扩展到调用命令处理器的原始命令行</td>
</tr>
</tbody>
</table>
<div class="blog_h2"><span class="graybg">批处理参数</span></div>
<table style="width: 100%;" border="1" cellspacing="0" cellpadding="5">
<thead>
<tr>
<td style="text-align: center;">参数</td>
<td style="text-align: center;">说明</td>
</tr>
</thead>
<tbody>
<tr>
<td>%0</td>
<td>批处理文件的名字</td>
</tr>
<tr>
<td>%1 - %9</td>
<td>第1-9个参数</td>
</tr>
<tr>
<td>%~nx0</td>
<td>批处理文件的名字，例如some-batch.bat</td>
</tr>
<tr>
<td>%~dp0</td>
<td>批处理文件所在目录，例如C:\scripts</td>
</tr>
<tr>
<td>%~dpnx0</td>
<td>批处理文件全限定名</td>
</tr>
</tbody>
</table>
<div class="blog_h1"><span class="graybg">批处理编程</span></div>
<div class="blog_h2"><span class="graybg">变量管理</span></div>
<div class="blog_h3"><span class="graybg">setlocal</span></div>
<p>setlocal命令可在批处理程序运行时设置自身的临时变量环境（仅对当前批处理程序有效），直到出现endlocal</p>
<pre class="crayon-plain-tag">#同时启用变量延迟扩展
setlocal enabledelayedexpansion</pre>
<div class="blog_h3"><span class="graybg">set</span></div>
<p>set命令用于创建、设置或者删除环境变量，命令格式：<pre class="crayon-plain-tag">set [[/a [expression]] [/p [variable=]] string]</pre></p>
<p>参数说明：</p>
<ol>
<li><pre class="crayon-plain-tag">/a</pre>：将string设置成可求值的数学表达式，expression:合法的表达式，表达式支持的运算符按优先级降序如下：<br />
<table style="width: 50%;" border="1" cellspacing="0" cellpadding="5">
<thead>
<tr>
<td style="text-align: center;">运算符</td>
<td style="text-align: center;">说明</td>
</tr>
</thead>
<tbody>
<tr>
<td>()</td>
<td>分组</td>
</tr>
<tr>
<td>! ~ -</td>
<td>一元运算符</td>
</tr>
<tr>
<td>* / % + -</td>
<td>算术运算符</td>
</tr>
<tr>
<td>&lt;&lt; &gt;&gt;</td>
<td>移位</td>
</tr>
<tr>
<td>&amp; ^ |</td>
<td>按位与非或</td>
</tr>
<tr>
<td>
<p>=   *=   /=   %=   +=   -=<br />&amp;=   ^=   |=   &lt;&lt;=   &gt;&gt;=</p>
</td>
<td>赋值</td>
</tr>
<tr>
<td>,</td>
<td>表达式分隔符</td>
</tr>
</tbody>
</table>
</li>
<li><pre class="crayon-plain-tag">/p</pre>：将variable的值设置成输入行，variable:指定需要设置或修改的变量</li>
<li><pre class="crayon-plain-tag">string</pre>：指定要与指定变量关联的字符串</li>
</ol>
<p>举例：</p>
<pre class="crayon-plain-tag">REM 设置VAR1为Hello
SET VAR1=Hello
REM 提示用户输入
SET /P variable=请输入值
REM 设置变量为表达式的值，下面为VAR1递增
SET /a VAR1=VAR1+1
REM 设置VAR1为"Hello"
SET  VAR1="Hello"
REM 如果变量值包含命令关键字，可以使用双引号包围：
SET "VAR1=&amp;amp;"
REM 删除变量
SET VAR1=</pre>
<div class="blog_h2"><span class="graybg">条件测试</span></div>
<p>注意对环境变量进行条件测试的时候，不能带<span style="background-color: #c0c0c0;"><strong>%%</strong></span>。</p>
<pre class="crayon-plain-tag">REM 文件存在性测试（注意，不能用来测试环境变量）
IF [NOT] EXIST FILENAME.EXT Command
if not exist SERVICE_NAME &amp;nbsp;set "SERVICE_NAME=%SERVICE_NAME_DEFAULT%"
REM 如果有多行命令需要执行，可以用()包围：
set /p VENDER_NAME=
IF NOT Gmem=VENDER_NAME (
    echo.
)
REM 变量是否为空测试
IF DEFINED VAR_NAME (...)
REM 字符串为空测试，这个用于stdin读入变量无效
IF [%1] == [] ECHO "Empty argument."
REM 字符串相等性测试，加上双引号避免歧义
IF "%VAR_NAME%" == "1" ECHO .
REM 注意，如果VAR_NAME来自标准输入，或者可能为空，要加上双引号，否则可能出现
REM was unexpected at this time（此时不应有）错误
REM 如果字符串可能有空格，可以使用双引号，例如 "AUTOEXE .BAT"，"%1"（第一个参数）
IF [NOT] %1 == AUTOEXEC.BAT ECHO Parameter is AUTOEXEC.BAT
REM 上一条命令返回值测试
REM 其中值为整数，只要大于等于该值，判断为真。0表示没有错误
IF [NOT] ERRORLEVEL 值 Command
REM 比较字符串大小：op可以是：EQU、NEQ、LSS、LSQ、GTR、GEQ之一，/i表示忽略大小写
if [/i] stringl op string2 command [else expression]
REM 如果变量被定义，则执行
if defined variable command [else expression]

REM IF-ELSE结构
IF EXIST filename ( 
    del filename
) ELSE ( 
    echo filename missing
)</pre>
<div class="blog_h2"><span class="graybg">分支转移GOTO</span></div>
<pre class="crayon-plain-tag">GOTO LABEL

:LABEL
ECHO done</pre>
<div class="blog_h2"><span class="graybg">for命令循环</span></div>
<div class="blog_h3"><span class="graybg">参数说明</span></div>
<ol>
<li>%variable|%%variable：代表可替换的参教：<br /> 使用<strong>%variable通过命令提示符</strong>执行for 命令，使用<strong>%%variable在批处理文件</strong>执行for命令</li>
<li>set:指定要用命令处理的<strong>一个或多个文件、目录、数值范围或文本字符串</strong></li>
<li> command:指定要对包括在指定(set)中的每个文件、目录、数值范围或文本字符 串所执行的命令</li>
<li>CommandLineOptions:命令使用的命令行选项</li>
</ol>
<div class="blog_h3"><span class="graybg">for命令的不同形式</span></div>
<table style="width: 100%;" border="1" cellspacing="0" cellpadding="5">
<thead>
<tr>
<td style="width: 300px; text-align: center;"> 用途</td>
<td style="text-align: center;">语法格式 </td>
</tr>
</thead>
<tbody>
<tr>
<td>文件集合 </td>
<td>for %%variable in (fileSet) do statement</td>
</tr>
<tr>
<td>目录集合</td>
<td>for /D %%variable in (directorySet) do statement</td>
</tr>
<tr>
<td>子目录中的文件</td>
<td>for /R [path] %%variable  in (fileSet) do statement</td>
</tr>
<tr>
<td>遍历一系列的值</td>
<td>for /L %%variable in (stepRange) do statement</td>
</tr>
<tr>
<td>分析文本文件、字符串以及命令输出</td>
<td>for /F ["options"]  %%variable in (source) do statement</td>
</tr>
</tbody>
</table>
<div class="blog_h3"><span class="graybg">示例：各种用法</span></div>
<pre class="crayon-plain-tag">@echo off
set /a sum=0
REM 遍历当前目录中的文本文件并打印其内容，多行命令需要用()包围
for %%x in (*. txt) do (
    echo Printing content of file %%x
    type %%x
    echo.
set /a sum=sum+1
REM 从0开始，步进2，到10结束
for /L %%B in (0 2, 10) do echo %%B

REM 下面的语句首先会运行date /t命令，其输出为类似：“2001/01/01 周一”这样的形式
REM /F 表示以字符串方式处理命令输出、字符串或者文件内容
REM tokens用于定义for命令的变量个数，1-3表示第1、2、3个字符串并解析为变量
REM delims表示用于拆分字符串的分隔符，包括/、-
REM set表示把拆分的字符串依次赋值给%%A %%B %%C三个变量（后面的变量名在前面的ASCII码加1）
REM delims可以指定多个字符用于分隔
for /F "tokens=l-3 delims=/-" %%A in ('date /T') do set date=%%A%%B%%C

rem 提取NT Service的PID的例子，注意sc queryex命令输出多行
rem 下面的for命令以行为单位进行处理，并提取第一列、第三列
rem skip可以用于跳过指定数量的行
for /F "tokens=1,3 skip=3" %%a in ('sc queryex Tomcat7') do (
    echo %%a %%b
)
rem usebackq允许在源指定符中使用引号；eol指定行尾结束字符，之后的内容被忽视
for /f "tokens=3-5 usebackq eol=#" %%C in ("user data.txt") do  echo %%C
rem 命令输出如下：
rem SERVICE_NAME:
rem TYPE 110
rem STATE 4
rem (STOPPABLE, ACCEPTS_SHUTDOWN)
rem WIN32_EXIT_CODE 0
rem SERVICE_EXIT_CODE 0
rem CHECKPOINT 0x0
rem WAIT_HINT 0x0
rem PID 5812
rem FLAGS

REM tokens更复杂的例子
REM tokens=x 表示只提取第x列。
REM tokens=x,y 表示只提取第x列和第y列。
REM tokens=m-n 表示提取第m列至第n列。
REM tokens=x* 表示提取第x列和后面所有字符串都作为第x+1列。
REM tokens=x,* 等同tokens=x*
REM tokens=x,y,m-n 表示提取第x，y列以及第m至第n列。</pre>
<div class="blog_h3"><span class="graybg">示例：获取PID</span></div>
<pre class="crayon-plain-tag">@echo off
REM 这样才能将循环变量%%a赋值给环境变量
setlocal enabledelayedexpansion

title fuckbat

REM 遍历命令结果的2、10列
for /f "delims=, tokens=2,10" %%a in ('tasklist /NH /V /FI "IMAGENAME eq cmd.exe" /FO CSV') do (
REM  将循环变量赋值
    set task_title=title%%b
    set pid=%%a
REM 脱去外部的双引号，用!!的界定符访问变量pid， pid:"= 表示将pid中的"替换为空
    set pid=!pid:"=!
    
REM 如果将标题中的fuckbat替换为空后得到的值与之前不等，说明标题中有fuckbat，说明当前迭代的时当前进程
    if not "!task_title!"=="!task_title:fuckbat=!" (
        echo !pid! &gt; pid.txt
    )
)
endlocal</pre>
<p>&nbsp;</p>
<div class="blog_h2"><span class="graybg">字符串处理</span></div>
<div class="blog_h3"><span class="graybg">字符串替换</span></div>
<p>语法格式：<strong>%a:搜索字符串=替换字符串%</strong>，举例：</p>
<p>&nbsp;</p>
<pre class="crayon-plain-tag">set domain=www.gmem. cc
REM 替换空格为空串，结果：www.gmem.cc
set var=%domain: =%</pre>
<div class="blog_h3"><span class="graybg">字符串截取</span></div>
<p>语法格式：<strong>%a:~[m[,n]]%</strong><br /> a为变量名，m为偏移量（缺省为0），n为截取长度（缺省为全部）</p>
<p>&nbsp;</p>
<div class="blog_h2"><span class="graybg">变量延迟</span></div>
<p>考虑下面的例子：</p>
<pre class="crayon-plain-tag">@echo off 
set a=1 
set a=2 &amp; echo %a%
REM 输出为1

REM 启用变量延迟
setlocal enabledelayedexpansion 
set a=1 
set a=2 &amp; echo !a!
REM 输出为2</pre>
<p>上半部分输出不是2的原因：</p>
<ol>
<li>批处理读取命令时是按行读取的（另外例如for命令等，其后用一对<strong>圆括号闭合的所有语句也当作一行</strong>）</li>
<li>为了能够感知环境变量的动态变化，批处理设计了变量延迟——在读取了一条完整的语句之后，不立即对该行的变量赋值，而会在某个单条语句执行之前再进行赋值</li>
</ol>
<div class="blog_h3"><span class="graybg">使用变量延迟扩展来处理环境变量中的特殊字符</span></div>
<pre class="crayon-plain-tag">@echo off
Setlocal EnableDelayedExpansion
set "VAR=&lt;"
rem 输出：&lt;
echo !VAR!
set "VAR1=value"
echo %VAR1%</pre>
<div class="blog_h1"><span class="graybg">常见问题</span></div>
<div class="blog_h2"><span class="graybg">零散问题</span></div>
<div class="blog_h3"><span class="graybg">如何调用Jar包</span></div>
<pre class="crayon-plain-tag">java -jar .jar</pre>
<div class="blog_h3"><span class="graybg">如何在隐藏窗口中调用BAT脚本？</span></div>
<p>创建VB脚本并调用：</p>
<pre class="crayon-plain-tag">createobject("wscript.shell").run "batch.bat arg1 arg2..." , 0</pre>
</div><p>The post <a rel="nofollow" href="https://blog.gmem.cc/bat">MS-DOS批处理学习笔记</a> appeared first on <a rel="nofollow" href="https://blog.gmem.cc">绿色记忆</a>.</p>
]]></content:encoded>
			<wfw:commentRss>https://blog.gmem.cc/bat/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
