<?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; Windows</title>
	<atom:link href="https://blog.gmem.cc/category/work/os/windows/feed" rel="self" type="application/rss+xml" />
	<link>https://blog.gmem.cc</link>
	<description></description>
	<lastBuildDate>Thu, 16 Apr 2026 07:10:45 +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>操作系统知识集锦</title>
		<link>https://blog.gmem.cc/os-faq</link>
		<comments>https://blog.gmem.cc/os-faq#comments</comments>
		<pubDate>Tue, 11 May 2010 13:49:11 +0000</pubDate>
		<dc:creator><![CDATA[Alex]]></dc:creator>
				<category><![CDATA[Linux]]></category>
		<category><![CDATA[OS]]></category>
		<category><![CDATA[Windows]]></category>

		<guid isPermaLink="false">http://blog.gmem.cc/?p=5988</guid>
		<description><![CDATA[<p>硬件平台基础知识 总线 在计算机领域，总线（来源于拉丁语omnibus）是用于在计算机内部组件之间进行数据传输的通信子系统。总线上传递的数据类型包括数据信息、地址信息、控制信息。 在个人计算机上，总线一般分为5类： 数据总线（Data Bus）：在CPU与RAM或其它设备之间来回传送需要处理或是需要储存的数据。数据总线的宽度决定了CPU与外界数据交换的最大速率。数据总线有一系列的传输线组成，每条传输线同一时刻只能传输1bit的数据，如果数据总线位宽为64位，就意味着有64根传输线 地址总线（Address Bus）：CPU通过地址总线来指定存储器的地址，地址总线决定了CPU能访问的最大内存空间大小 控制总线（Control Bus）：将处理器控制单元（Control Unit）的信号传送到周边设备，一般常见的为USB总线 扩展总线（Expansion Bus）：可连接扩展槽，以增添设备 局部总线（Local Bus）：直接的连接CPU与部分扩展总线的插槽，避免扩展总线引入的性能瓶颈，提高数据吞吐量  在Intel的处理器产品线中，总线还可以按如下方式分类： 系统总线：一般特指PCI/PCIe总线，带宽高，支持热插拔。内部总线、外部总线都挂接在系统总线上 外部总线：诸如USB、SATA、IDE、1394、以太网等暴露在外的，都属于外部总线 内部总线：外部总线上的一些零散小芯片使用 前端总线：CPU与北桥、内存的连接总线，北桥是PCI/PCIe的发源地 频率 CPU时钟频率速度（主频）=系统总线速率（外频）×倍频系数，某些主板可以通过跳线设置倍频系数、系统总线频率。 <a class="read-more" href="https://blog.gmem.cc/os-faq">[...]</a></p>
<p>The post <a rel="nofollow" href="https://blog.gmem.cc/os-faq">操作系统知识集锦</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>在计算机领域，总线（来源于拉丁语omnibus）是用于在计算机<span style="background-color: #c0c0c0;">内部组件之间进行数据传输的通信子系统</span>。总线上传递的数据类型包括数据信息、地址信息、控制信息。</p>
<p>在个人计算机上，总线一般分为5类：</p>
<ol>
<li>数据总线（Data Bus）：在CPU与RAM或其它设备之间来回传送需要处理或是需要储存的数据。数据总线的宽度决定了CPU与外界数据交换的最大速率。数据总线有一系列的传输线组成，每条传输线同一时刻只能传输1bit的数据，如果数据总线位宽为64位，就意味着有64根传输线</li>
<li>地址总线（Address Bus）：CPU通过地址总线来指定存储器的地址，地址总线决定了CPU能访问的最大内存空间大小</li>
<li>控制总线（Control Bus）：将处理器控制单元（Control Unit）的信号传送到周边设备，一般常见的为USB总线</li>
<li>扩展总线（Expansion Bus）：可连接扩展槽，以增添设备</li>
<li>局部总线（Local Bus）：直接的连接CPU与部分扩展总线的插槽，避免扩展总线引入的性能瓶颈，提高数据吞吐量</li>
</ol>
<p> 在Intel的处理器产品线中，总线还可以按如下方式分类：</p>
<ol>
<li>系统总线：一般特指PCI/PCIe总线，带宽高，支持热插拔。内<span style="color: #222222;">部总线、外部总线都挂接在系统总线上</span></li>
<li>外部总线：诸如USB、SATA、IDE、1394、以太网等暴露在外的，都属于外部总线</li>
<li>内部总线：外部总线上的一些零散小芯片使用</li>
<li>前端总线：CPU与北桥、内存的连接总线，北桥是PCI/PCIe的发源地</li>
</ol>
<div class="blog_h2"><span class="graybg">频率</span></div>
<p><span style="background-color: #c0c0c0;">CPU时钟频率速度（主频）=系统总线速率（外频）×倍频系数</span>，某些主板可以通过跳线设置倍频系数、系统总线频率。</p>
<p>在早期，并没有倍频这一概念，CPU主频与外频是一致的。然而CPU的速率越来越快，开始出现倍频——让CPU主频与总线频率之间呈现倍数关系，这样CPU可以高速运作，而外设以低频运作。</p>
<p>在早期，系统总线、前端总线的工作频率也是一致的，目前前端总线往往是系统总线的数倍速度。</p>
<div class="blog_h2"><span class="graybg">SMP</span></div>
<p>CPU设计初期是往高频率方向发展的，然而最终遭遇到物理极限的限制。这时为了继续提高处理能力，只能向多核心、多CPU的方向发展了。</p>
<p>CPU有多个，而内存是大家共享的，这时SMP架构出现了。所谓对称多处理（Symmetric multiprocessing，SMP）是指每个处理器核心的地位都是平等的（所谓对称），对所有计算机资源（特别是内存）具有相同的使用权限。</p>
<p>SMP的优点是并行度高，然而系统总线的带宽有限，因此处理器的数目不能无限添加，系统性能和处理器数量也不是线性关系。</p>
<p>Linux对SMP的早期支持依赖于一个全局大锁，直到2.6才有效的发挥SMP的能力。</p>
<div class="blog_h2"><span class="graybg">NUMA</span></div>
<p>SMP的最大问题在于总线带宽有限，当很多CPU都通过北桥来读写内存，北桥带宽的瓶颈很快就出现了。</p>
<p>为了解决此问题，硬件工程师开始把北桥中的<span style="background-color: #c0c0c0;">内存控制器拆分</span>，让CPU与特定内存插槽、内存控制器关联在一起。当CPU访问自己本地内存（Local Access）时，速度很快，而需要访问其它CPU的内存（Remote Access）时速度就慢了。这就是所谓非统一内存访问（Non-Uniform Memory Access，NUMA）的由来。</p>
<p>NUMA一定程度上保证了单台主机的扩容能力，然而操作系统面临的问题则是，如何尽可能的避免Remote Access。Linux的默认策略是：</p>
<ol>
<li>优先尝试在请求线程当前所处的CPU的本地内存中进行分配</li>
<li>如果本地内存不足，尝试淘汰（Reclaim）其中无用的页</li>
</ol>
<div class="blog_h2"><span class="graybg">PCI</span></div>
<p>外设组件互连标准（Peripheral Component Interconnect），是一种连接电脑主板和外部设备的总线标准。基于PCI标准连接到主板的外设，要么嵌入到主板的集成电路中，要么通过主板上的PCI插槽连接。</p>
<p>目前PCI总线已经被更先进的技术，例如PCI Express（PCIe）逐步取代。</p>
<p>PCI子系统包含四级模块：</p>
<ol>
<li>Bus，一个PCI子系统最多256个Bus，常用的是Bus 0和Bus 1</li>
<li>Device，即连接到Bus上的设备，如声卡，网卡等，每个Bus最多32个</li>
<li>Function，每个Device有至少有一个Function 0，最多8个</li>
<li>Register，每个Function有256字节的的Registers</li>
</ol>
<div class="blog_h2"><span class="graybg">SCSI</span></div>
<p>SCSI是一种用于计算机和智能设备之间（硬盘、软驱、光驱、打印机、扫描仪等）系统级接口的独立处理器标准。与IDE最大的不同是，IDE的工作需要CPU全程参与，而SCSI卡自带处理器，因而CPU占用极低。</p>
<div class="blog_h2"><span class="graybg">iSCSI</span></div>
<p>集因特网小型计算机系统接口（Internet Small Computer System Interface），又称为IP-SAN，是一种基于Internet和SCSI-3协议下的存储技术，与传统的SCSI相比，其优势为：</p>
<ol>
<li>将原先仅用于单机的SCSI协议通过TCP/IP网络传输</li>
<li>连接的服务器数量没有限制，而SCSI-3有15的限制</li>
</ol>
<p>iSCSI让计算机可以透过<span style="background-color: #c0c0c0;">高速的局域网来把SAN模拟成为本地的储存</span>装置。它让两个主机通过 IP 网络相互协商然后交换 SCSI 命令，用局域网仿真了高性能本地存储总线。与某些SAN协议不同，iSCSI 不需要专用的电缆，被认为是光纤通道（Fiber Channel）的一个低成本替代方法。</p>
<div class="blog_h2"><span class="graybg">指令集架构（Instruction Set Architecture，ISA）</span></div>
<p>亦称指令集，是计算机体系结构（Computer Architecture）中与编程相关的部分，其包括了：<span style="background-color: #c0c0c0;">基本（native）数据类型、指令、寄存器、寻址模式、内存架构、中断、异常处理、外部I/O</span>几个方面的内容。指令集包括了一系列面向机器语言的操作码（Opcodes），这些操作码由特定的CPU实现。</p>
<p>复杂指令集计算机（CISC）、精简指令集计算机（RISC）是根据指令集的复杂度来区分的，前者包含很多不常使用的指令，并且导致指令长度不固定。大部分RISC具有固定的指令长度，通常与机器字一样长。</p>
<p>每条指令由一个Opcode、0个或者多个算子组成，这些算子可能是<span style="background-color: #c0c0c0;">寄存器编号、内存位置或者字面值</span>。</p>
<p>从功能上，指令可以分为以下几种类型：</p>
<ol>
<li><span style="background-color: #c0c0c0;">数据读写</span>操作指令：设置寄存器的值、读取寄存器的值、取出数据并计算、保存计算结果、从硬件读写数据</li>
<li><span style="background-color: #c0c0c0;">算术与逻辑运算</span>指令：对两个寄存器中的值进行加减乘除、执行位操作、执行逻辑与、逻辑非、逻辑或、比较两个寄存器中数据的大小</li>
<li><span style="background-color: #c0c0c0;">控制流</span>指令：分支——跳跃到某个地址继续执行、条件分支、间接分支——跳跃前，将下一条指令的位置存储起来，作为子程序的返回地址</li>
</ol>
<p> 注意术语“微架构”与指令集架构没有直接关系，前者代表了一种处理器硬件的设计方式，不同微架构的处理器可以实现同一套指令集。</p>
<div class="blog_h2"><span class="graybg">x86指令集架构家族</span></div>
<p>x86包含了一系列指令集架构，它们都是<span style="background-color: #c0c0c0;">可变指令长度的CISC</span>，最早由英特尔在1978年面市的“Intel 8086”CPU上开发出来。三年后IBM PC开始使用8086，x86逐渐成为个人计算机的标准平台。</p>
<p>x86这个名称的由来是Intel早期CPU的名称：Intel 8086、80186、80286、80386、80486，后续的处理器由于商标的问题，改用“Pentium”之类的名称。现在Intel把x86-32称为IA-32，尽管x86系列包含16位处理器。与IA-32对应的是IA-64，这是早在1990年代就提出的，在安腾系列处理器中使用的独立64位架构，与IA-32完全不兼容。</p>
<p>除了Intel以外，还有若干厂商实现了x86指令集的CPU，其中包括AMD的Athlon系列处理器。有趣的是，2003年，AMD发布了针对x86架构的64位扩充，命名为AMD64，Intel则被迫推出了与AMD64兼容的CPU，并命名为Intel 64。不同操作系统厂商对AMD64使用不同的称呼：Apple称之为x86-64或者x86_64；Sun和微软称之为x64；BSD和Linux称之为amd64，并把32位版本成为i386。</p>
<div class="blog_h2"><span class="graybg">字</span></div>
<p>在计算机领域，“字（Word）”是用于表示其自然的数据单位的术语，对应了CPU一次性处理事务的固定比特位宽度。字在多个方面有体现，例如大部分通用寄存器的尺寸是一个字长；CPU与内存之间数据传输的单位也是字长；内存地址也通常用字长来表示。</p>
<p>为了保证向后兼容，实际的体系结构下<span style="background-color: #c0c0c0;">经常把字固定为某个长度</span>，以Intel为例，由于后续的处理器都是对8086的扩充，所以IA-32、AMD64架构下，字一直保持16位的大小，对VC的数据类型WORD、DWORD执行sizeof可以明确的看到这一点。</p>
<div class="blog_h2"><span class="graybg">64位元</span></div>
<p>64位、32位是人们经常提到的名词，但是所谓64位到底指的是什么？如果一颗处理器是64位的，通常是指：</p>
<ol>
<li>该CPU的各种指针寄存器是64位的，因此理论上支持16EB的存储器</li>
<li>该CPU的通用寄存器是64位的，因此支持64位二进制整数的直接算术与逻辑运算</li>
<li>该CPU具有64位宽的地址、数据总线</li>
</ol>
<p>现实的情况比较复杂，由于硬件设计、操作系统限制，64位机支持的存储器大小远远小于16EB，地址总线的宽度也往往没有64位。</p>
<div class="blog_h2"><span class="graybg">AMD64（x86_64）</span></div>
<p>可以认为是x86指令集的64位版本。AMD64理论上支持2^64比特（16EB）的寻址空间，并引入了若干64位通用寄存器和其它的特性增强。由于AMD64保留了全部16位、32位x86指令，因此它完全向后兼容（Backwards Compatible ）16位、32位的x86代码。首片支持AMD64的CPU是2003年发布的AMD Opteron。</p>
<p>AMD64具有以下特性：</p>
<div class="blog_h3"><span class="graybg">64位整数支持</span></div>
<p>所有的通用寄存器被从32位扩充到64位，因此所有的64位<span style="background-color: #c0c0c0;">算术、逻辑、寄存器-内存操作可以直接在64位整数上操作</span>；<span style="background-color: #c0c0c0;">压栈/弹出操作默认8字节步长</span>；<span style="background-color: #c0c0c0;">指针默认8字节宽</span>。</p>
<div class="blog_h3"><span class="graybg">引入额外的寄存器</span></div>
<p>除了扩展通用寄存器的长度外，其数量也被加倍，从8扩展到16，因此，可以<span style="background-color: #c0c0c0;">在寄存器上存放更多的局部变量</span>，而避免存放在栈上。</p>
<p>128位SSE寄存器的数量也从8增加到16。</p>
<div class="blog_h3"><span class="graybg">更大的虚拟地址空间</span></div>
<p>AMD64定义了64位的虚拟地址格式，理论上最大支持16EB的地址空间，目前只使用了其中的低48位，因此支持256TB的虚拟地址空间。</p>
<div class="blog_h3"><span class="graybg">更大的物理地址空间集锦</span></div>
<p>AMD64的初始版本允许40位的物理地址，因此最大支持1TB的物理内存。当前版本的实现则使用48位物理地址，可以支持256TB的物理内存。由于页表条目结构的限制，未来最多可以扩展到52位物理地址。</p>
<p>当AMD64在遗留模式（实模式、保护模式）下运行时，PAE由36位扩展到52位，因此物理地址的限制与长模式一致。相比之下，32位的x86处理器在物理地址扩展（PAE）模式下最多支持64GB的物理内存，不使用PAE则最多4GB内存。</p>
<div class="blog_h3"><span class="graybg">IP相对数据访问</span></div>
<p>在AMD64架构下，允许根据当前指令指针（RIP）来访问相对位置的数据，可以实现位置无关代码（Position Independent Code），这在共享库、动态加载代码中更加高效。</p>
<div class="blog_h3"><span class="graybg">禁止执行比特位</span></div>
<p>NX位是页表的最高位，允许操作系统指定哪些虚拟地址空间的页可以包含executable代码，哪些不能。尝试执行NX页的代码，会导致内存访问违例（Memory Access Violation）。</p>
<div class="blog_h2"><span class="graybg">x86运作模式</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>实模式</td>
<td>
<p>即“真实地址模式”，是8086即以后的x86兼容CPU的一种运作模式。其特征是逻辑地址直接指向物理地址。实模式包含20位的分段的地址空间（仅仅1MB地址空间），必须将段地址左移4位，然后加上地址偏移量才能得到最终的20位地址。</p>
<p>实模式支持通过<span style="background-color: #c0c0c0;">软件直接访问硬件</span>、没有硬件级别的<span style="background-color: #c0c0c0;">内存保护、多任务</span>的概念。</p>
<p>80286以及以后的CPU在启动后首先处于实模式，80186只有一种运作模式，类似于实模式。</p>
<p>&nbsp;</p>
<p>操作系统要求：16位实模式操作系统或者16/32/64位启动加载器（Boot Loader）<br />指向代码类型：16位实模式代码<br />默认地址尺寸：16位<br />默认操作数尺寸：16位<br />支持的典型操作数尺寸：8/16/32<br />寄存器堆尺寸：8寄存器<br />通用寄存器典型宽度：16/32</p>
</td>
</tr>
<tr>
<td>保护模式</td>
<td>
<p>所谓保护模式，即“受保护的虚拟地址模式”，x86兼容机器不会直接进入保护模式，必须在操作系统设置好若干描述符表（GDT等）后，并且设置了控制寄存器（CR0）的PE位（Protection Enable）后才能生效。保护模式具有以下特性：</p>
<ol>
<li>特权级别（Privilege levels，aka rings），用数字0-3表示 ，0的级别最高，大部分操作系统代码和驱动程序工作在0级别，应用程序则工作在3级别。特权级别用于限制数据访问、限制执行特定的指令</li>
<li>支持虚拟内存（ virtual memory）</li>
<li>支持安全的多任务（multi-tasking）设计。80286引入了任务状态段（TSS），配合特权级别机制可以实现安全的多任务</li>
<li>80386引入到保护模式的新特性：32bit物理和虚拟地址空间、分页（paging）、32位的段偏移量、不需要重启的返回实模式、虚拟8086模式</li>
</ol>
<p>保护模式（16位）最初由80286引入，将可寻址的物理内存扩充到16MB，可寻址的虚拟内存最大到1GB。</p>
<p>16位保护模式相关参数：</p>
<p>操作系统要求：16位保护模式操作系统或者16/32/64位启动加载器<br />指向代码类型：16位保护模式代码<br />默认地址尺寸：16位<br />默认操作数尺寸：16位<br />支持的典型操作数尺寸：8/16/32<br />寄存器堆尺寸：8寄存器<br />通用寄存器典型宽度：16/32</p>
<p>&nbsp;</p>
<p>32位保护模式相关参数：</p>
<p>操作系统要求：32位保护模式操作系统或者32/64位启动加载器<br />指向代码类型：32位保护模式代码<br />默认地址尺寸：32位<br />默认操作数尺寸：16位<br />支持的典型操作数尺寸：8/16/32<br />寄存器堆尺寸：8寄存器<br />通用寄存器典型宽度：32</p>
</td>
</tr>
<tr>
<td>虚拟8086模式</td>
<td>
<p>用于支持先前基于8086的程序不经修改的运行在80386下，支持与其它任务并发运行</p>
<p>&nbsp;</p>
<p>操作系统要求：16/32位保护模式操作系统<br />指向代码类型：16位实模式代码<br />默认地址尺寸：16位<br />默认操作数尺寸：16位<br />支持的典型操作数尺寸：8/16/32<br />寄存器堆尺寸：8寄存器<br />通用寄存器典型宽度：16/32</p>
</td>
</tr>
<tr>
<td>长模式</td>
<td>
<p>在x86_84架构处理器中，长模式（Long mode）允许64位操作系统或者应用程序使用64位指令和寄存器，而32位、16位程序则以一种兼容子模式来运行。</p>
<p>不在长模式下（兼容模式）运行时，x86_64处理器与x86_32处理器的行为完全相同</p>
<p>&nbsp;</p>
<p>16位兼容模式相关参数：</p>
<p>操作系统要求：64位保护模式操作系统<br />指向代码类型：16位保护模式代码<br />默认地址尺寸：16位<br />默认操作数尺寸：16位<br />支持的典型操作数尺寸：8/16/32<br />寄存器堆尺寸：8寄存器<br />通用寄存器典型宽度：32</p>
<p>32位兼容模式相关参数：</p>
<p>操作系统要求：64位保护模式操作系统或者64位启动加载器<br />指向代码类型：32位保护模式代码<br />默认地址尺寸：32位<br />默认操作数尺寸：32位<br />支持的典型操作数尺寸：8/16/32<br />寄存器堆尺寸：8寄存器<br />通用寄存器典型宽度：32</p>
<p>长模式相关参数：</p>
<p>操作系统要求：64位保护模式操作系统或者64位启动加载器<br />指向代码类型：64位代码<br />默认地址尺寸：64位<br />默认操作数尺寸：32位<br />支持的典型操作数尺寸：8/16/32/64<br />寄存器堆尺寸：16寄存器<br />通用寄存器典型宽度：64</p>
</td>
</tr>
</tbody>
</table>
<div class="blog_h2"><span class="graybg">虚拟内存（Virtual memory）</span></div>
<p>这里所说的虚拟内存与Windows面向用户的“虚拟内存是两回事”，后者实际上是分页技术（Paging）。</p>
<p>操作系统将大小一致的、代表<span style="background-color: #c0c0c0;">连续虚拟地址空间</span>的数据块称为“<span style="background-color: #c0c0c0;">页（Page）</span>”；相应的，物理地址空间上与页大小一致的连续空间则被称为“<span style="background-color: #c0c0c0;">页帧（Page Frame）</span>”。32位x86处理器的内存管理单元（MMU，CPU中的特殊硬件）支持从4KB到4MB大小的页。</p>
<p>虚拟内存是同时使用硬件、软件实现的一种内存管理技术。它将应用程序使用的内存地址（即虚拟地址，Virtual Addresses）映射到计算机内存（即主存，Main Storage）的物理地址（Physical Addresses）。在应用程序看来，内存是一个连续的地址空间，实际上则可能是<span style="background-color: #c0c0c0;">分散在物理内存上的多个片段</span>。</p>
<p><span style="background-color: #c0c0c0;">虚拟地址与物理地址的映射（即页与页帧之间的映射）是由MMU完成</span>的。操作系统可以利用MMU，把多个虚拟地址映射到同一物理地址，从而在分页技术的支持下，允许应用程序引用大于实际物理内存的虚拟地址。</p>
<p>大部分操作系统使用<span style="background-color: #c0c0c0;">“页表（Page Table）”</span>来存储虚拟地址与物理地址的映射关系，页面通常是一个简单的数组，pageTable[v] = p，代表虚拟页v与物理页p具有关联关系。为了<span style="background-color: #c0c0c0;">节省空间，通常会使用多级页表</span>（M<span style="color: #505050;">ultilevel Page Table </span>）,例如Linux在进行32位寻址时，使用二级页表。</p>
<div class="blog_h2"><span class="graybg">分页（Paging）</span></div>
<p>分页是一种内存管理技术，允许从在主存、辅存之间存取、交换页，共应用程序使用。</p>
<p>当应用程序程序尝试<span style="background-color: #c0c0c0;">访问的页当前没有映射到物理内存</span>的情况，称为<span style="background-color: #c0c0c0;">页面错误（Page fault）</span>，操作系统采取一种对程序透明的方式来处理页面错误：</p>
<ol>
<li>确定页在辅存中的位置</li>
<li>获取一个空白的页帧（Page Frame）来作为数据的容器</li>
<li>加载辅存中的页到页帧</li>
<li>更新页表（Page Table），引用新的页帧</li>
<li>返回控制器给应用程序，重试导致页面错误的指令</li>
</ol>
<p>如果处理页面错误时，发现没有足够的内存以获取一个空白页帧，则操作系统会使用一个<span style="background-color: #c0c0c0;">页面替换算法</span>，将某个现存的页帧从内存中清除，并将其持久化到辅存（如果其内容被修改过）。大部分操作系统使用LRU算法或者基于工作集的算法来进行页面替换。</p>
<p><span style="background-color: #c0c0c0;">工作集</span>这一概念，用于确定进程在<span style="background-color: #c0c0c0;">一定时间区间内需要的内存的量</span>。</p>
<p>在Unix-like的操作系统中，使用术语“<span style="background-color: #c0c0c0;">交换（Swap）</span>”来描述页面替换这一动作。</p>
<div class="blog_h2"><span class="graybg">x86寄存器</span></div>
<table style="width: 100%;" border="1" cellspacing="0" cellpadding="5">
<thead>
<tr>
<td style="width: 70px; text-align: center;"> 寄存器</td>
<td style="width: 70px;">起源</td>
<td style="width: 50px; text-align: center;">位数</td>
<td style="text-align: center;">说明 </td>
</tr>
</thead>
<tbody>
<tr>
<td>AX</td>
<td rowspan="14">
<p>8086/<br />8088</p>
</td>
<td>16</td>
<td rowspan="4">
<p>通用寄存器</p>
<p>尽管属于通用寄存器，但是每个都有附加的特殊用途，例如CX可以作为循环指令的计数器</p>
<p>每个寄存器可以拆分为两个使用，例如AH、AL分别访问AX的高8位、低8位</p>
</td>
</tr>
<tr>
<td>BX </td>
<td>16 </td>
</tr>
<tr>
<td>CX </td>
<td>16 </td>
</tr>
<tr>
<td>DX </td>
<td>16 </td>
</tr>
<tr>
<td>CS</td>
<td>16 </td>
<td rowspan="4">8086起引入，区段寄存器，用于存放绝对地址<br />CS：代码段寄存器，指向当前执行代码所在内存区域<br />DS：数据段寄存器，指向当前运行着的程序的数据段，可以将其指向任何具有所属数据的地址<br />SS：栈段寄存器，指向栈段<br />ES：额外的段寄存器， 通常跟DI一起用来做指针操作</td>
</tr>
<tr>
<td>DS </td>
<td>16 </td>
</tr>
<tr>
<td>SS </td>
<td>16 </td>
</tr>
<tr>
<td>ES </td>
<td>16 </td>
</tr>
<tr>
<td>IP</td>
<td>16</td>
<td>指令指针寄存器，CS与IP共同决定了下一条CPU指令的内存地址，CS:IP相当于程序计数器（PC）</td>
</tr>
<tr>
<td>SP</td>
<td>16</td>
<td>栈顶指针寄存器</td>
</tr>
<tr>
<td>BP </td>
<td>16 </td>
<td>基指针，可以用来指向堆栈或存储器的其它地方，例如用来保存使用局部变量的地址 </td>
</tr>
<tr>
<td>SI</td>
<td>16</td>
<td rowspan="2">源/目标索引（指针）寄存器，这两个寄存器通常用来处理数组或字符串。SI通常指向源数组，DI通常指向目的数组，他们通常被用来成块地移动数据，比如移动数组或结构体  </td>
</tr>
<tr>
<td>DI </td>
<td>16 </td>
</tr>
<tr>
<td>FLAGS  </td>
<td>16</td>
<td>标记寄存器，每一位有单独用途，可以指示进位、溢出、结果为零等</td>
</tr>
<tr>
<td>EAX</td>
<td rowspan="12">80386            </td>
<td>32</td>
<td rowspan="4">通用寄存器，其低16位与原本的AX、BX、CX、DX重叠共用    </td>
</tr>
<tr>
<td>EBX </td>
<td>32 </td>
</tr>
<tr>
<td>ECX </td>
<td>32 </td>
</tr>
<tr>
<td>EDX </td>
<td>32 </td>
</tr>
<tr>
<td>EIP</td>
<td>32</td>
<td rowspan="5">指针寄存器，扩展对应16位版本</td>
</tr>
<tr>
<td>EBP </td>
<td>32 </td>
</tr>
<tr>
<td>ESP </td>
<td>32 </td>
</tr>
<tr>
<td>ESI </td>
<td>32 </td>
</tr>
<tr>
<td>EDI </td>
<td>32 </td>
</tr>
<tr>
<td>FS</td>
<td>32</td>
<td rowspan="2">新增加的两个区段寄存器，没有特定用途</p>
<p>区段寄存器在32位模式下改做为存储器区块的<span style="background-color: #c0c0c0;">选择子（Selector）寄存器</span>。 </p>
</td>
</tr>
<tr>
<td>GS </td>
<td>32</td>
</tr>
<tr>
<td>EFLAGS</td>
<td>32</td>
<td>标记寄存器，其低16位与原本的FLAGS重叠共用</td>
</tr>
<tr>
<td>MM0-<br />MM7 </td>
<td rowspan="12">MMX      </td>
<td>64</td>
<td rowspan="2">MMX寄存器与对应 FPU（浮点运算器）重叠，MMX与浮点运算不可同时使用，必须通过切换选择使用其中一种。</td>
</tr>
<tr>
<td>FP0-<br />FP7 </td>
<td>64 </td>
</tr>
<tr>
<td>RAX</td>
<td>64</td>
<td rowspan="4">通用寄存器，其低32位与原本的EAX、EBX、ECX、EDX重叠共用</td>
</tr>
<tr>
<td>RBX </td>
<td>64 </td>
</tr>
<tr>
<td>RCX </td>
<td>64 </td>
</tr>
<tr>
<td>RDX </td>
<td>64 </td>
</tr>
<tr>
<td>RIP</td>
<td>64</td>
<td rowspan="5">指针寄存器，扩展对应32位版本</td>
</tr>
<tr>
<td>RBP </td>
<td>64 </td>
</tr>
<tr>
<td>RSP </td>
<td>64 </td>
</tr>
<tr>
<td>RSI </td>
<td>64 </td>
</tr>
<tr>
<td>RDI </td>
<td>64 </td>
</tr>
<tr>
<td>R8-<br />R15</td>
<td>64</td>
<td>新增的八个通用寄存器</td>
</tr>
<tr>
<td>XMM0-<br />XMM15</td>
<td>SSE</td>
<td>128</td>
<td>
<p>单指令流多数据流（SIMD）寄存器</p>
<p>流式SIMD扩展（Streaming SIMD Extensions）是Intel在AMD的3D Now!发布一年后，在Pentium III中引入的指令集，是对MMX的扩充</p>
<p>SSE最初只加入了XMM0～XMM7这8个寄存器，AMD发布的x86_64加了额外的8个，这8个只能在64位模式下使用</p>
</td>
</tr>
<tr>
<td>YMM0-<br />YMM15</td>
<td>AVE</td>
<td>256</td>
<td>
<p>单指令流多数据流（SIMD）寄存器</p>
<p>高级矢量扩展（Advanced Vector Extensions）是在2008年提出的x86指令集架构扩展，在2011年Sandy Bridge系列处理器中首次被支持</p>
</td>
</tr>
<tr>
<td>ZMM0-<br />ZMM31</td>
<td>AVX-512 </td>
<td>512 </td>
<td>
<p>单指令流多数据流（SIMD）寄存器 </p>
<p>AVX-512在2013年首次提出，计划在2015年 Knights Landing 处理器中首次支持</p>
</td>
</tr>
</tbody>
</table>
<div class="blog_h2"><span class="graybg">ARM架构</span></div>
<p>ARM，即高级精简指令集机器（Advanced RISC Machine），是一种精简指令集的指令集架构，广泛的使用在嵌入式系统中。ARM具有低成本、高性能、低能耗的特点。到2011年，ARM占有了95%的智能手机、90%的硬盘驱动器、20%的移动电脑处理器份额。</p>
<p>ARM指令设计快速而精简，大多在一个CPU周期内执行，整体电路化，不使用微码。</p>
<div class="blog_h2"><span class="graybg">引导扇区</span></div>
<p>引导扇区是磁盘、软盘或光盘上的一个区域。其中包含由计算机固件负责加载到内存的机器码。</p>
<p>引导扇区的意义是，允许计算机启动过程能<span style="background-color: rgb(192, 192, 192);">加载相同磁盘上的一个程序</span>（通常是操作系统）。在IBM PC兼容机上，BIOS<span style="background-color: rgb(192, 192, 192);">选择一个启动设备</span>，然后将它的<span style="background-color: rgb(192, 192, 192);">第一扇区</span>拷贝到内存的<span style="background-color: rgb(192, 192, 192);">0x7C00地址</span>。其它系统中，可能完全不一样。</p>
<p>第一扇区可能存放着： MBR、VBR或者任何可执行代码。</p>
<p>MBR（Master Boot Record 主引导记录）是已经被分区的磁盘上的第一个扇区。MBR能够定位到活动分区（Active partition，Bootable）并调用其VBR。</p>
<p>VBR（Volume Boot Record 卷引导记录）可以是未分区磁盘（软盘、U盘）的第一扇区，或者某个分区的第一扇区。VBR可能包含用于加载（当前磁盘/当前分区）操作系统的代码。VBR也可能加载第二阶段引导程序（Bootloader）。</p>
<div class="blog_h1"><span class="graybg">操作系统基本概念</span></div>
<div class="blog_h2"><span class="graybg">操作系统的外延</span></div>
<p>一般的，可以把以下内容看作操作系统的组成部分：</p>
<ol>
<li>内核</li>
<li>设备驱动程序</li>
<li>启动引导程序</li>
<li>命令行Shell</li>
<li>其它基本的用户界面工具、文件管理工具、系统管理工具</li>
</ol>
<p>内核是操作系统的核心所在，通常包括以下部分：</p>
<ol>
<li>负责响应中断的中断服务程序</li>
<li>负责管理多个进程从而分享处理器时间的调度程序</li>
<li>负责管理进程地址空间的内存管理程序</li>
<li>负责网络、进程间通信的系统服务程序</li>
</ol>
<p><span style="background-color: #c0c0c0;">内核程序代码独立于普通应用程序</span>，一般处于内核态（亦称系统态）运行。</p>
<div class="blog_h2"><span class="graybg">中断（INTerrupt）</span></div>
<p>这个概念最初的含义是：外在的事件<span style="background-color: #c0c0c0;">打断正在执行的程序</span>，转而执行处理这个事件的特定处理程序，处理结束后，<span style="background-color: #c0c0c0;">回到被打断</span>的程序继续执行。</p>
<p>在实模式下，BIOS提供的中断机制是依赖于以下两部分实现的：</p>
<ol>
<li>中断向量表（Interrupt Vector Table）：实模式中断机制的重要组成部分，表中记录所有中断号对应的中断服务程序的内存地址</li>
<li>中断服务程序（Interrupt Services）：通过中断向量表的索引对中断进行响应，是一些具有特定功能的程序</li>
</ol>
<p>在操作系统启动过程中，通常会关闭中断，并把BIOS在内存中的中断向量表、中断服务程序擦除，并替换为操作系统的中断处理机制，然后打开中断。</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>该中断在操作系统中频繁发生，例如Linux中可能每10ms就发生一次。<span style="background-color: #c0c0c0;">时钟中断是进程轮询调度的基础</span></td>
</tr>
<tr>
<td>软中断</td>
<td>用户程序可以通过软中断来进入内核态，执行内核代码</td>
</tr>
</tbody>
</table>
<div class="blog_h2"><span class="graybg">缓冲区</span></div>
<p>操作系统的<span style="background-color: #c0c0c0;">“缓冲区”是一个内存区域</span>，主要作为<span style="background-color: #c0c0c0;">主机与外设（例如硬盘等块设备）进行数据交互的中转站</span>，让主内存区域与外设隔离。</p>
<p>缓冲区包含的数据有：硬盘引导块。</p>
<p>主内存区域存放进程的各种数据，例如程序代码。</p>
<div class="blog_h2"><span class="graybg">系统调用</span></div>
<p>系统调用是用户程序与操作系统内核交互的接口。通常，用户程序通过C库函数简洁的进行系统调用，库函数与系统调用并不一定是一一对应关系，比如printf函数中包含了write系统调用（将数据写到控制台），同时还包括了数据缓存、格式化等逻辑。</p>
<p>在Linux中，函数system_call是系统调用的总入口，用户程序可以产生“系统调用软中断”，操作系统经由system_call找到具体系统函数，并调用。</p>
<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>的操作，因为进入内核态  - 执行内核代码 - 返回用户代码这一过程本身就需要开销。应当尽量减少系统调用的次数，操作系统附带的标准函数库通常可以用来实现这一目的，例如带有I/O缓冲功能的标准I/O库。</p>
<div class="blog_h2"><span class="graybg">用户态与内核态</span></div>
<p>操作系统的内核代码一般在内核态运行，<span style="background-color: #c0c0c0;">内核态意味着独立的、受保护的内存空间以及完全的硬件访问权限</span>。内核态与用户态的<span style="background-color: #c0c0c0;">根本不同在于硬件控制的特权等级。</span></p>
<p>应用程序的代码则在用户态运行， 它们只能看到允许它们使用的部分系统资源，并且只使用某些特定的系统功能，<span style="background-color: #c0c0c0;">不能直接访问硬件</span>，也<span style="background-color: #c0c0c0;">不能访问内核划分给其它程序的内存范围</span>。</p>
<p>但是，应用程序进程在执行过程中，往往需要使用操作系统内核提供的功能，这里就涉及到<span style="background-color: #c0c0c0;">进程的“权限提升”的问题，亦即从用户态转换到内核态的问题</span>。</p>
<p>80386及以后的CPU包含了若干种特权级别的定义，在段描述符中，包含两位数字用于标记当前所执行代码的特权级，共可表示0、1、2、3四个级别，用户态对应的优先级是3，内核态对应的优先级是0，进程在运行过程中，可能多次改变其特权级别。</p>
<p>降低特权级别的改变有几种方法，其中一种是<span style="background-color: #c0c0c0;">“中断返回”。当CPU执行指令iret时，硬件会自动把特权级下降为3</span>，即导致进程在用户态运行。Linux系统函数move_to_user_mode函数可以模拟这种中断返回（所谓模拟，是指不发生真正中断的情况下“返回”）。</p>
<p>相应的，用户代码<span style="background-color: #c0c0c0;">触发（软）中断，则可进入内核态，即提升特权级别</span>。</p>
<p>CPU的活动，在某个时间点上，其活动必然是三者之一：</p>
<ol>
<li>运行于用户空间（用户态），执行用户进程</li>
<li>运行于内核空间（内核态），处于进程上下文， 代表某个特定的进程执行，<span style="background-color: #c0c0c0;">内核执行系统调用</span>时，就是这一情况</li>
<li>运行于内核空间（内核态），处于中断上下文， 与任何进程无关，处理某个特定的中断</li>
</ol>
<p><span style="background-color: #c0c0c0;">当CPU空闲的时候，内核可能运行于一个空进程，处于进程上下文，但运行于内核空间</span>。</p>
<p><img class="aligncenter  wp-image-5943" src="https://blog.gmem.cc/wp-content/uploads/2010/05/process-3.png" alt="process-3" width="519" height="459" /></p>
<div class="blog_h2"><span class="graybg">进程切换</span></div>
<p>本段内容不区分进程、线程两个概念。</p>
<p>CPU同一时刻只能运行一条指令，因而它只能同时执行一个进程。在多任务操作系统中，CPU不断的切换其执行的进程，给用户一种多个任务同时在执行的假象。</p>
<p>进程切换可能发生在下列场景：</p>
<ol>
<li>时间片用完时：每个进程在创建时，都被赋予有限的时间片，进程在用完时间片后，只要其处于用户态，就会立即切换到其它进程执行</li>
<li>进程不具备进一步执行（Unrunnable）的条件时：比如进程处于内核态，已经没有代码需要执行，或者下一步执行需要外设提供的数据。这种情况下就可以立即切换到其它进程，以免浪费CPU时间。这种情况典型的例子是等待网络I/O完成</li>
</ol>
<p>发生进程切换的时候，必然意味着上下文切换。</p>
<div class="blog_h2"><span class="graybg">上下文切换（Context Switch）</span></div>
<p>除非特别提及，本段内容不区分进程、线程两个概念。</p>
<p>在计算机领域，<span style="background-color: #c0c0c0;">上下文切换</span>是指<span style="background-color: #c0c0c0;">存储/恢复进程状态（即上下文）</span>的处理过程，该过程可以使进程恢复到下一次执行的最后状态，从而允许多个进程共享单颗CPU。上下文切换是多任务操作系统的基本特性。</p>
<p>以下三种原因会导致上下文切换：</p>
<ol>
<li>多任务（Multitasking）：进程不具备进一步执行的条件时，会立即执行上下文切换；对于抢占式多任务系统（Preemptive Multitasking）而言，当进程的<span style="background-color: #c0c0c0;">时间片（ Time Slice）用完时，会触发时钟中断</span>，强制的进行上下文切换</li>
<li>中断处理：当发生中断时，硬件会<span style="background-color: #c0c0c0;">自动切换一部分上下文（至少允许中断处理器能返回到被中断的代码处）</span>，切换后得到的空间用于存放中断上下文，中断处理器的代码在此上下文中执行，执行完毕后，则恢复到中断前的上下文状态。现代处理器和操作系统<span style="background-color: #c0c0c0;">倾向于最小化需要切换的上下文</span>部分，以减少中断处理消耗的时间</li>
<li>内核态与用户态之间切换时：尽管单纯的内核态-用户态切换，并不需要上下文切换，但是某些操作系统还是可能在此时执行上下文切换</li>
</ol>
<p>上下文包含的内容取决于CPU和操作系统，以Linux 2.6为例，以下内容需要被切换：</p>
<ol>
<li>CPU<span style="background-color: #c0c0c0;">寄存器的值，即所谓“硬件上下文”</span>，包含了大量进程实时状态信息</li>
<li><span style="background-color: #c0c0c0;">内核态栈</span>：当进程进入内核态运行时，该栈会被自动创建</li>
<li><span style="background-color: #c0c0c0;">页全局目录</span>（Page Global Directory）：与虚拟地址空间有关</li>
</ol>
<div class="blog_h2"><span class="graybg">单内核与微内核</span></div>
<p>这是两种不同的操作系统内核设计方式：</p>
<ol>
<li>单内核：内核整体上作为一个大的过程来实现，运行在单独的地址空间上。所有内核服务都运行在一个大的内核地址空间上，其间的通信开销是微不足道的</li>
<li>微内核：操作系统内核仅包含一个很小的函数集，通常包括几个同步原语、一个简单的调度程序、IPC机制，运行在内核之上的若干<span style="background-color: #c0c0c0;">系统进程</span>实现内存分配、系统调用处理、设备驱动等OS的核心功能。大部分微内核设计者最终都让系统进程运行于内核空间，例如Windows NT内核，这其实违背了微内核设计的原则</li>
</ol>
<p>单内核设计的优点是：</p>
<ol>
<li>设计简单，性能高：所有内核例程运行在单独地址空间上，没有IPC开销。内核例程之间也不会引入上下文切换</li>
</ol>
<p>微内核设计的优点是：</p>
<ol>
<li>模块化：微内核迫使程序员使用模块化方式设计，因为任何操作系统组件都是相对独立的程序，必须通过明确定义的接口与其他组件交互</li>
<li>易于移植：与硬件相关的代码可以被封装到微内核中</li>
<li>更加充分的利用内存：暂时不需要的系统进程可以被调出或撤销</li>
</ol>
<p>Linux是单内核OS，为了达到微内核的优势，内核引入了模块（Module）机制，所谓模块就是一个目标文件，遵循了<span style="background-color: #c0c0c0;">良好定义的接口</span>，其代码可以在运行时链接到内核（或解除链接）。模块通常包括一组函数，用来实现文件系统、驱动程序等内核上层功能。</p>
<div class="blog_h2"><span class="graybg">POSIX（Portable Operating System Based on Unix）</span></div>
<p>是IEEE发布的一套标准，该标准定义了一套API，从而使遵循POSIX的操作系统之间可以方便的进行应用程序的移植。所有类UNIX系统都遵循此标准。Windows NT内核也一定程度上实现了POSIX标准。</p>
</div><p>The post <a rel="nofollow" href="https://blog.gmem.cc/os-faq">操作系统知识集锦</a> appeared first on <a rel="nofollow" href="https://blog.gmem.cc">绿色记忆</a>.</p>
]]></content:encoded>
			<wfw:commentRss>https://blog.gmem.cc/os-faq/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Windows知识集锦</title>
		<link>https://blog.gmem.cc/windows-faq</link>
		<comments>https://blog.gmem.cc/windows-faq#comments</comments>
		<pubDate>Thu, 12 Mar 2009 06:08:49 +0000</pubDate>
		<dc:creator><![CDATA[Alex]]></dc:creator>
				<category><![CDATA[Windows]]></category>

		<guid isPermaLink="false">http://blog.gmem.cc/?p=2362</guid>
		<description><![CDATA[<p>常见问题 如何启用Zeroconf支持 要启用类似于Linux的mDNS以及基于.local的本地机器自动发现，可以安装Apple提供的Bonjour Print Services 如何删除已经移除的网卡 在重命名网卡名称时，如果遇到“cannot rename this connection”这样的错误，可以按如下方式处理： [crayon-69e0b266b4c46585144056/] 定制个人文件夹的位置 定位到注册表： [crayon-69e0b266b4c4c351325439/] 手工修改即可。 如何删除控制面板待删除程序中的垃圾条目 定位到注册表： [crayon-69e0b266b4c4f855575296/] 根据程序名称搜索子键，删除即可。 如何禁止开启CHKDSK 定位到注册表HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager，在右侧面板修改BootExecute。 <a class="read-more" href="https://blog.gmem.cc/windows-faq">[...]</a></p>
<p>The post <a rel="nofollow" href="https://blog.gmem.cc/windows-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>
<div class="blog_h3"><span class="graybg">如何启用Zeroconf支持</span></div>
<p>要启用类似于Linux的mDNS以及基于.local的本地机器自动发现，可以安装Apple提供的<a href="https://support.apple.com/kb/DL999?locale=zh_CN">Bonjour Print Services</a></p>
<div class="blog_h3"><span class="graybg">如何删除已经移除的网卡</span></div>
<p>在重命名网卡名称时，如果遇到“cannot rename this connection”这样的错误，可以按如下方式处理：</p>
<pre class="crayon-plain-tag">set DEVMGR_SHOW_NONPRESENT_DEVICES=1 
devmgmt.msc

rem 在打开的设备管理器中，选择View - Show Hidden Devices
rem 即可显示隐藏设备，这些设备都是垃圾，删除即可</pre>
<div class="blog_h3"><span class="graybg">定制个人文件夹的位置</span></div>
<p><span style="color: #272a30;">定位到注册表：</span></p>
<pre class="crayon-plain-tag">HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer\User Shell Folders</pre>
<p>手工修改即可。</p>
<div class="blog_h3"><span class="graybg">如何删除控制面板待删除程序中的垃圾条目</span></div>
<p>定位到注册表：</p>
<pre class="crayon-plain-tag">HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall</pre>
<p>根据程序名称搜索子键，删除即可。</p>
<div class="blog_h3"><span class="graybg">如何禁止开启CHKDSK</span></div>
<p>定位到注册表HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager，在右侧面板修改BootExecute。</p>
<p>取值<pre class="crayon-plain-tag">autocheck autochk /k:E /k:N *</pre> 表示禁止E、N盘的CHKDSK</p>
<div class="blog_h3"><span class="graybg">如何清理msconfig/Startup中的垃圾条目</span></div>
<p>定位到注册表：</p>
<pre class="crayon-plain-tag">HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Shared Tools\MSConfig\startupreg</pre>
<p>删除不需要的条目。 </p>
<div class="blog_h3"><span class="graybg">如何彻底删除数据</span></div>
<pre class="crayon-plain-tag">rem 把指定目录下，已经标记删除的数据彻底删除
cipher /w:绝对路径</pre>
<div class="blog_h3"><span class="graybg">MSTSC如何踢人</span></div>
<pre class="crayon-plain-tag">qwinsta /server:192.168.1.15
rwinsta 1 /server:192.168.1.15</pre>
<div class="blog_h3"><span class="graybg">把任意程序作为NT服务运行</span></div>
<pre class="crayon-plain-tag">sc create "Wlanap" binpath= "c:\Windows\System32\srvany.exe" displayname= "WLAN AccessPoint" depend= Tcpip start= auto 

rem 下面的内容导入注册表
Windows Registry Editor Version 5.00
[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\services\Wlanap\Parameters]
"application"="D:\\Programs\\Scripts\\startup.bat"</pre>
<div class="blog_h3"><span class="graybg">Win7无线网卡作为AP使用</span></div>
<pre class="crayon-plain-tag">rem 设置网卡：
netsh wlan set hostednetwork mode=allow ssid=ChinaNet-1o09 key=passw0rd
rem 启动服务：
netsh wlan start hostednetwork
rem 关闭服务：
netsh wlan stop  hostednetwork</pre>
<p>启动服务后，进入控制面板，设置当前<span style="background-color: #c0c0c0;">与外网连接的网络为共享</span>，并且设置Home networking connection为Windows自动创建的虚拟无线网卡。</p>
<p>设备无法通过此AP上网的可能原因：</p>
<ol>
<li>DNS不正确，尝试设置设备的DNS</li>
<li>与外网连接的网卡，如果设置多重IP地址，可能导致设备无法上网</li>
</ol>
<div class="blog_h3"><span class="graybg">防止Windows Server 2008远程桌面被自动注销</span></div>
<ol>
<li>打开组策略编辑器：<span style="color: #000000;">gpedit.msc  ，计算机配置 - 管理模板 - Windows组件 - 远程桌面服务 - 远程桌面会话主机 - 会话时间限制 ，全部改为未配置</span></li>
<li>开始菜单 - 管理工具 - 远程桌面服务 - 远程桌面会话主机配置，RDP-Tcp右击，会话选项卡，改写用户设置，全部设置为从不，最后一项选择从会话断开</li>
</ol>
<div class="blog_h3"><span class="graybg">修改Windows7的产品标识（Product ID）</span></div>
<p>定位到注册表HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion，修改右侧的键值ProductId。</p>
<div class="blog_h3"><span class="graybg">如何删除Ext2fsd产生的垃圾盘符</span></div>
<p>定位到注册表HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\DOS Devices，删除无效的盘符。</p>
<div class="blog_h3"><span class="graybg">如何修改设备管理器中的设备信息</span></div>
<ol>
<li>运行<pre class="crayon-plain-tag">devmgmt.msc</pre> 打开设备管理器，在目标设备上右击 ⇨ 属性 ⇨ 详细信息 ⇨ 驱动程序关键字（Driver key），拷贝此字段的值</li>
<li>打开注册表，定位到HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Enum，右击 ⇨ 权限，设置所有者（包括子容器）为当前用户，设置当前用户的权限为完全控制</li>
<li>在Enum上执行查找，把第1步拷贝的Driver Key作为查询关键字，定位到需要修改是设备</li>
<li>在右侧面板中执行修改</li>
</ol>
<div class="blog_h3"><span class="graybg">更改工具栏Open按钮的图标</span></div>
<p>修改注册表，下面是更改exe的Open图标的例子：</p>
<pre class="crayon-plain-tag">Windows Registry Editor Version 5.00

[HKEY_CLASSES_ROOT\exefile\shell\open]
"Icon"="%Windir%\\System32\\Application_Icon.ico,-1"</pre>
<div class="blog_h2"><span class="graybg">Windows 2008下NTP时间服务器搭建</span></div>
<div class="blog_h3"><span class="graybg">服务端设置</span></div>
<pre class="crayon-plain-tag">@echo off
sc config W32Time start= auto
net stop W32Time 

reg add HKLM\SYSTEM\CurrentControlSet\services\W32Time\TimeProviders\NtpServer /v Enabled /t REG_DWORD /d 0x00000001 /f 
reg add HKLM\SYSTEM\CurrentControlSet\services\W32Time\Config /v AnnounceFlags  /t REG_DWORD /d 0x00000005 /f

net start W32Time

rem 防止服务器与Internet时间同步
reg add HKLM\SYSTEM\CurrentControlSet\services\W32Time\TimeProviders\NtpClient /v Enabled /t REG_DWORD /d 0x00000000 /f </pre>
<div class="blog_h3"><span class="graybg">客户端设置</span></div>
<pre class="crayon-plain-tag">@echo off

sc config W32Time start= auto
net stop W32Time 
reg add HKLM\SYSTEM\CurrentControlSet\services\W32Time\TimeProviders\NtpClient /v Enabled /t REG_DWORD /d 0x00000001 /f 
rem 设置NTP服务器
reg add HKLM\SYSTEM\CurrentControlSet\services\W32Time\TimeProviders\NtpClient /v SpecialPollTimeRemaining /t REG_MULTI_SZ /d 192.168.0.200,0 /f
rem 每2小时同步
reg add HKLM\SYSTEM\CurrentControlSet\services\W32Time\TimeProviders\NtpClient /v SpecialPollInterval /t REG_DWORD /d 0x00001c20 /f

net start W32Time</pre>
</div><p>The post <a rel="nofollow" href="https://blog.gmem.cc/windows-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-faq/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>逆向常用Windows API记录</title>
		<link>https://blog.gmem.cc/windows-api-for-re</link>
		<comments>https://blog.gmem.cc/windows-api-for-re#comments</comments>
		<pubDate>Wed, 30 Jan 2008 14:33:26 +0000</pubDate>
		<dc:creator><![CDATA[Alex]]></dc:creator>
				<category><![CDATA[RE]]></category>
		<category><![CDATA[Windows]]></category>

		<guid isPermaLink="false">https://blog.gmem.cc/?p=10859</guid>
		<description><![CDATA[<p>日期与时间 函数 说明 GetSystemTime [crayon-69e0b266b5213865183093/]  SYSTEMTIME结构的定义如下： [crayon-69e0b266b5217108414086/] GetLocalTime [crayon-69e0b266b5219593587633/] GetSystemTimeAsFileTime [crayon-69e0b266b521b533734985/]  FILETIME 结构的定义如下： [crayon-69e0b266b521d102837850/] FILETIME难以阅读，可以使用下面的函数将其与SYSTEMTIME进行转换： [crayon-69e0b266b5220455152171/] SetSystemTime [crayon-69e0b266b5222751440744/]  如果操作失败，可以通过[crayon-69e0b266b5224245392774-i/] 获取错误代码 SetLocalTime [crayon-69e0b266b5226563336096/]</p>
<p>The post <a rel="nofollow" href="https://blog.gmem.cc/windows-api-for-re">逆向常用Windows API记录</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_h3"><span class="graybg">日期与时间</span></div>
<table class=" full-width fixed-word-wrap">
<thead>
<tr>
<td style="width: 27%; text-align: center;">函数</td>
<td style="text-align: center;">说明</td>
</tr>
</thead>
<tbody>
<tr>
<td>GetSystemTime</td>
<td>
<pre class="crayon-plain-tag">/**
 * 获得当前系统日期和时间，以UTC（世界标准时间表示）
 * @param lpSystemTime 用于接收时间，指向SYSTEMTIME结构的指针
 */
void WINAPI GetSystemTime(LPSYSTEMTIME lpSystemTime);</pre></p>
<p> SYSTEMTIME结构的定义如下：</p>
<pre class="crayon-plain-tag">typedef struct _SYSTEMTIME
{
    WORD wYear; //年度，1601-30827
    WORD wMonth; //月份，1-12
    WORD wDayOfWeek; //周几，0-6，0表示周日
    WORD wDay; //几号，1-31
    WORD wHour; //几点，0-23
    WORD wMinute; //几分，0-59
    WORD wSecond; //几秒，0-59
    WORD wMilliseconds; //毫秒数，0-999
} SYSTEMTIME, *PSYSTEMTIME;</pre>
</td>
</tr>
<tr>
<td>GetLocalTime</td>
<td>
<pre class="crayon-plain-tag">/**
 * 获得当前系统的本地时间
 * @param lpSystemTime 用于接收时间，指向SYSTEMTIME结构的指针
 */
void WINAPI GetLocalTime(LPSYSTEMTIME lpSystemTime);</pre>
</td>
</tr>
<tr>
<td>GetSystemTimeAsFileTime</td>
<td>
<pre class="crayon-plain-tag">/**
 * 获得当前系统日期和时间，以UTC（世界标准时间表示）
 * @param lpSystemTime 用于接收时间，指向FILETIME 结构的指针
 */
void WINAPI GetSystemTimeAsFileTime( LPFILETIME lpSystemTimeAsFileTime );</pre>
<p> FILETIME 结构的定义如下：</p>
<pre class="crayon-plain-tag">/**
 * 64位数字，表示从1601年1月1日（UTC）到目前流逝的100纳秒的数目
 */
typedef struct _FILETIME
{
    DWORD dwLowDateTime;//低32位
    DWORD dwHighDateTime;//高32位
} FILETIME, *PFILETIME;</pre>
<p>FILETIME难以阅读，可以使用下面的函数将其与SYSTEMTIME进行转换：</p>
<pre class="crayon-plain-tag">BOOL FileTimeToSystemTime( const FILETIME *lpFileTime, LPSYSTEMTIME lpSystemTime );
BOOL  SystemTimeToFileTime( const SYSTEMTIME *lpSystemTime,  LPFILETIME lpFileTime );</pre>
</td>
</tr>
<tr>
<td>SetSystemTime</td>
<td>
<pre class="crayon-plain-tag">/**
 * 以UTC时间设置系统日期时间
 * @param lpSystemTime 新的时间，wDayOfWeek被忽略
 * @return 如果设置成功，返回非0值
 */
BOOL WINAPI SetSystemTime( const SYSTEMTIME *lpSystemTime );</pre>
<p> 如果操作失败，可以通过<pre class="crayon-plain-tag">DWORD GetLastError(void)</pre> 获取错误代码</p>
</td>
</tr>
<tr>
<td>SetLocalTime</td>
<td>
<pre class="crayon-plain-tag">/**
 * 以本地时间设置系统日期时间
 * @param lpSystemTime 新的时间，wDayOfWeek被忽略
 * @return 如果设置成功，返回非0值
 */
BOOL WINAPI SetLocalTime( const SYSTEMTIME *lpSystemTime );

SYSTEMTIME systemtime;
//先清零，非法数据可能导致设置失败
ZeroMemory( &amp;systemtime, sizeof( systemtime ) );
SetLocalTime( &amp;systemtime );</pre>
</td>
</tr>
</tbody>
</table>
</div><p>The post <a rel="nofollow" href="https://blog.gmem.cc/windows-api-for-re">逆向常用Windows API记录</a> appeared first on <a rel="nofollow" href="https://blog.gmem.cc">绿色记忆</a>.</p>
]]></content:encoded>
			<wfw:commentRss>https://blog.gmem.cc/windows-api-for-re/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-69e0b266b5c28488162162-i/]、[crayon-69e0b266b5c2d341570944-i/]这两个虚拟目录，其中[crayon-69e0b266b5c2f455408744-i/]指向当前目录，[crayon-69e0b266b5c31035126386-i/]指向上级目录： [crayon-69e0b266b5c33011353035/] 基本命令与概念 符号  说明 @前缀 取消当前命令的回显 ECHO OFF 禁用命令回显 SET 显示、设置或删除环境变量 [crayon-69e0b266b5c35786551791/] 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>
