<?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>Litblue.net &#187; 技术相关</title>
	<atom:link href="http://litblue.net/p/category/tech/feed" rel="self" type="application/rss+xml" />
	<link>http://litblue.net</link>
	<description>...游荡在黑夜的灵魂...</description>
	<lastBuildDate>Sat, 10 Jul 2010 15:42:23 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.0.1</generator>
		<item>
		<title>python中readlines和split配合使用的问题</title>
		<link>http://litblue.net/p/1465</link>
		<comments>http://litblue.net/p/1465#comments</comments>
		<pubDate>Sat, 10 Jul 2010 15:36:10 +0000</pubDate>
		<dc:creator>blues</dc:creator>
				<category><![CDATA[技术相关]]></category>

		<guid isPermaLink="false">http://litblue.net/?p=1465</guid>
		<description><![CDATA[tempfile = open('./dicttest.txt','r') lines = tempfile.readlines() tempfile.close() for line in lines: item = line.split('\t') print item 结果是： ['a@qq.com', '111\n'] ['b@qq.com', '4214312\n'] ['c@qq.com', '3214\n'] ['cc@qq.com', '432\n'] ['a@qq.com', '43\n'] list最后一个元素多一个了\n 这显然不是我们要的结果。 解决方案，简单地把\n删除就好了： tempfile = open('./dicttest.txt','r') lines = tempfile.readlines() tempfile.close() for line in lines: item = line.strip('\n').split('\t') print item]]></description>
			<content:encoded><![CDATA[<p><code>tempfile = open('./dicttest.txt','r')<br />
lines = tempfile.readlines()<br />
tempfile.close()</p>
<p>for line in lines:<br />
    item = line.split('\t')<br />
    print item<br />
</code><br />
结果是：</p>
<blockquote><p>['a@qq.com', '111\n']<br />
['b@qq.com', '4214312\n']<br />
['c@qq.com', '3214\n']<br />
['cc@qq.com', '432\n']<br />
['a@qq.com', '43\n']</p></blockquote>
<p>list最后一个元素多一个了\n<br />
这显然不是我们要的结果。<br />
解决方案，简单地把\n删除就好了：<br />
<code>tempfile = open('./dicttest.txt','r')<br />
lines = tempfile.readlines()<br />
tempfile.close()</p>
<p>for line in lines:<br />
    item = line.strip('\n').split('\t')<br />
    print item<br />
</code></p>
]]></content:encoded>
			<wfw:commentRss>http://litblue.net/p/1465/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>win7:unable to create a new system partition</title>
		<link>http://litblue.net/p/1455</link>
		<comments>http://litblue.net/p/1455#comments</comments>
		<pubDate>Sun, 02 Aug 2009 15:30:27 +0000</pubDate>
		<dc:creator>blues</dc:creator>
				<category><![CDATA[技术相关]]></category>

		<guid isPermaLink="false">http://litblue.net/p/1455</guid>
		<description><![CDATA[x200没有光驱，手上只有一个4G的sd卡，于是想到用sd卡做成启动盘去安装。 按网上的教程使用diskpart格好盘，然后把win7的安装文件复制过去。 启动一切正常，结果到了选择分区时出现：Setup was unable to create a new system partition or locate an existing system partition. See the setup log files for more information. 自从rc7100开始装这个就遇到这个错误，当时有winpe在手上，折腾了一会顺利装上了，没想到这回又遇到了，试一下手中的winpe，启动不了。 系统盘被我格式化了，手中唯一一个能引导的就是这个sd卡了。 想啊想。 最后用如下方式搞定。 先用SD卡引导，进入系统修复模式。 格式化系统分区C，然后xcopy 把win7的安装文件都复制到C分区。 同时，把安装文件复制到另外一个非系统安装分区一份。 然后bootsect /nt60 c: 最后重启，这回从硬盘可以引导了。 还是到系统修复模式，格式化C分区。 到另一个有安装文件的分区里运行setup。 剩下就是普通的安装过程了。 嗯 大概记录下，省得下次再走弯路。 想不出来是什么问题，为什么一定要从硬盘引导起来才可以顺利安装。 PS:软改bios的方式激活还不错。]]></description>
			<content:encoded><![CDATA[<p>x200没有光驱，手上只有一个4G的sd卡，于是想到用sd卡做成启动盘去安装。<br />
按网上的教程使用diskpart格好盘，然后把win7的安装文件复制过去。<br />
启动一切正常，结果到了选择分区时出现：Setup was unable to create a new system partition or locate an existing system partition. See the setup log files for more information.<br />
自从rc7100开始装这个就遇到这个错误，当时有winpe在手上，折腾了一会顺利装上了，没想到这回又遇到了，试一下手中的winpe，启动不了。<br />
系统盘被我格式化了，手中唯一一个能引导的就是这个sd卡了。<br />
想啊想。<br />
最后用如下方式搞定。<br />
先用SD卡引导，进入系统修复模式。<br />
格式化系统分区C，然后xcopy 把win7的安装文件都复制到C分区。<br />
同时，把安装文件复制到另外一个非系统安装分区一份。<br />
然后bootsect /nt60 c:<br />
最后重启，这回从硬盘可以引导了。<br />
还是到系统修复模式，格式化C分区。<br />
到另一个有安装文件的分区里运行setup。<br />
剩下就是普通的安装过程了。</p>
<p>嗯<br />
大概记录下，省得下次再走弯路。</p>
<p>想不出来是什么问题，为什么一定要从硬盘引导起来才可以顺利安装。</p>
<p>PS:软改bios的方式激活还不错。</p>
]]></content:encoded>
			<wfw:commentRss>http://litblue.net/p/1455/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>提高工作效率,记住bash和vim的几个快捷键</title>
		<link>http://litblue.net/p/1454</link>
		<comments>http://litblue.net/p/1454#comments</comments>
		<pubDate>Tue, 28 Jul 2009 03:03:32 +0000</pubDate>
		<dc:creator>blues</dc:creator>
				<category><![CDATA[技术相关]]></category>

		<guid isPermaLink="false">http://litblue.net/p/1454</guid>
		<description><![CDATA[对我来说最应该记住的就是光标定位 另外有些键能按一个键搞定的就不要去按两个键 毕竟记住一个容易些 bash: Ctrl-A 相当于HOME键，用于将光标定位到本行最前面 Ctrl-E 相当于End键，即将光标移动到本行末尾 Ctrl-K 用于删除从光标处开始到结尾处的所有字符 Ctrl-L 清屏，相当于clear命令 Ctrl-R 进入历史命令查找状态，然后你输入几个关键字符，就可以找到你使用过的命令 Ctrl-U 用于删除从光标开始到行首的所有字符。一般在密码或命令输入错误时常用 Ctrl-W 用于删除当前光标左侧的一个单词 bind -P命令可以查看所有键盘绑定。 vim: vim太多了，我只记住几个我一直记不住的定位快捷键 按数字「0」：移到文章的开头。 按「G」：移动到文章的最后。 按「$」：移动到光标所在行的“行尾”。 按「^」：移动到光标所在行的“行首” 按「w」：光标跳到下个字的开头 按「e」：光标跳到下个字的字尾 按「b」：光标回到上个字的开头]]></description>
			<content:encoded><![CDATA[<p>对我来说最应该记住的就是光标定位<br />
另外有些键能按一个键搞定的就不要去按两个键<br />
毕竟记住一个容易些</p>
<p>bash:</p>
<p>Ctrl-A 相当于HOME键，用于将光标定位到本行最前面<br />
Ctrl-E 相当于End键，即将光标移动到本行末尾<br />
Ctrl-K 用于删除从光标处开始到结尾处的所有字符<br />
Ctrl-L 清屏，相当于clear命令<br />
Ctrl-R 进入历史命令查找状态，然后你输入几个关键字符，就可以找到你使用过的命令<br />
Ctrl-U 用于删除从光标开始到行首的所有字符。一般在密码或命令输入错误时常用<br />
Ctrl-W 用于删除当前光标左侧的一个单词<br />
bind -P命令可以查看所有键盘绑定。</p>
<p>vim:<br />
vim太多了，我只记住几个我一直记不住的定位快捷键</p>
<p>按数字「0」：移到文章的开头。<br />
按「G」：移动到文章的最后。<br />
按「$」：移动到光标所在行的“行尾”。<br />
按「^」：移动到光标所在行的“行首”<br />
按「w」：光标跳到下个字的开头<br />
按「e」：光标跳到下个字的字尾<br />
按「b」：光标回到上个字的开头</p>
]]></content:encoded>
			<wfw:commentRss>http://litblue.net/p/1454/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>shell脚本中ftp下载函数</title>
		<link>http://litblue.net/p/1451</link>
		<comments>http://litblue.net/p/1451#comments</comments>
		<pubDate>Sun, 26 Jul 2009 03:25:40 +0000</pubDate>
		<dc:creator>blues</dc:creator>
				<category><![CDATA[技术相关]]></category>

		<guid isPermaLink="false">http://litblue.net/p/1451</guid>
		<description><![CDATA[downlog() { ( echo "open ${1} ${2}"; echo "user ${3} ${4}"; echo "bell" echo "hash"; echo "binary"; echo "get ${5} ${6}"; echo "close"; echo "bye"; ) &#124; ftp -n -i; }; 函数调用 downlog ${Ip} ${Port} ${User} ${Pass} ${FileName} ${LocalName} 当然，如果你是多文件下载，例如做目录同步，建议使用lftp lftp -u user,passwd -e "mirror -R ‘$path’ –ignore-time –verbose &#038;&#038; quit" IP]]></description>
			<content:encoded><![CDATA[<p><code>downlog()<br />
{<br />
        (<br />
                echo "open ${1} ${2}";<br />
                echo "user ${3} ${4}";<br />
                echo "bell"<br />
                echo "hash";<br />
                echo "binary";<br />
                echo "get ${5} ${6}";<br />
                echo "close";<br />
                echo "bye";<br />
        ) | ftp -n -i;<br />
};</code></p>
<p>函数调用<br />
downlog ${Ip} ${Port} ${User} ${Pass} ${FileName} ${LocalName} </p>
<p>当然，如果你是多文件下载，例如做目录同步，建议使用lftp<br />
<code>lftp -u user,passwd -e "mirror  -R  ‘$path’ –ignore-time –verbose &#038;&#038; quit" IP</code></p>
]]></content:encoded>
			<wfw:commentRss>http://litblue.net/p/1451/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>openvpn推出OpenVPN-AS</title>
		<link>http://litblue.net/p/1095</link>
		<comments>http://litblue.net/p/1095#comments</comments>
		<pubDate>Mon, 01 Jun 2009 05:21:08 +0000</pubDate>
		<dc:creator>blues</dc:creator>
				<category><![CDATA[技术相关]]></category>

		<guid isPermaLink="false">http://litblue.net/p/1095</guid>
		<description><![CDATA[http://www.openvpn.net/index.php/access-server/download-openvpn-as.html OpenVPN Access Server (OpenVPN-AS) is a set of installation and configuration tools that simplify the rapid deployment of a VPN remote access solution. It is based on the popular OpenVPN open-source software, making the deployed VPN immediately compatible with OpenVPN client software across multiple user platforms. OpenVPN-AS features include: ■A simple, Web-based Admin UI [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://www.openvpn.net/index.php/access-server/download-openvpn-as.html">http://www.openvpn.net/index.php/access-server/download-openvpn-as.html</a><br />
OpenVPN Access Server (OpenVPN-AS) is a set of installation and configuration tools that simplify the rapid deployment of a VPN remote access solution. It is based on the popular OpenVPN open-source software, making the deployed VPN immediately compatible with OpenVPN client software across multiple user platforms.<br />
OpenVPN-AS features include:<br />
■A simple, Web-based Admin UI for configuration and management.<br />
■An easy-to-use, GUI-based OpenVPN Client software package for Windows.<br />
■A Client Web Server that automatically generates a client configuration and a pre-configured Windows VPN Client software installer for the user upon successful login.<br />
■Integration with existing authentication systems using RADIUS, LDAP, and PAM<br />
OpenVPN-AS gives you the broad support and robust security of the OpenVPN open-source software project, coupled with the configuration and management tools needed to deploy the VPN solution easily and quickly.</p>
]]></content:encoded>
			<wfw:commentRss>http://litblue.net/p/1095/feed</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>WL530g-V2与x200的intel 5100AGN网卡兼容性问题</title>
		<link>http://litblue.net/p/1092</link>
		<comments>http://litblue.net/p/1092#comments</comments>
		<pubDate>Sat, 09 May 2009 05:23:52 +0000</pubDate>
		<dc:creator>blues</dc:creator>
				<category><![CDATA[技术相关]]></category>

		<guid isPermaLink="false">http://litblue.net/p/1092</guid>
		<description><![CDATA[换上x200的第一天回到家 连接上无线后感觉上网非常慢 但我ping任何一个地址延时都很正常 打开网页却响应奇慢 依稀记得在公司的时候无线连接是没有问题的 于是去掉无线路由器 又回到了飞快的感觉 一周后 再次折腾无线路由器 发现只要把路由器无线的规模强制为802.11g 就不会有问题了 嗯 还是无线好用 不需要插线不需要拨号]]></description>
			<content:encoded><![CDATA[<p>换上x200的第一天回到家<br />
连接上无线后感觉上网非常慢<br />
但我ping任何一个地址延时都很正常<br />
打开网页却响应奇慢</p>
<p>依稀记得在公司的时候无线连接是没有问题的<br />
于是去掉无线路由器<br />
又回到了飞快的感觉</p>
<p>一周后<br />
再次折腾无线路由器<br />
发现只要把路由器无线的规模强制为802.11g<br />
就不会有问题了</p>
<p>嗯<br />
还是无线好用<br />
不需要插线不需要拨号</p>
]]></content:encoded>
			<wfw:commentRss>http://litblue.net/p/1092/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>blog中图片又回来了</title>
		<link>http://litblue.net/p/1055</link>
		<comments>http://litblue.net/p/1055#comments</comments>
		<pubDate>Wed, 11 Feb 2009 13:27:11 +0000</pubDate>
		<dc:creator>blues</dc:creator>
				<category><![CDATA[技术相关]]></category>

		<guid isPermaLink="false">http://litblue.net/p/1055</guid>
		<description><![CDATA[自从将url静态化变成http://litblue.net/p/850这样的形式后 blog中的很多图片就无法显示了 原因是我从pjblog转过来的 附件的引用地址是相对地址如&#8221;attachments/jpg.jpg&#8221; 原来的http://litblue.net/a.asp?850这样的文章中引用是不会有问题的 但现在多了一层“目录”/p/后相对地址出来的图片url就是http://litblue.net/p/attachments/jpg.jpg 执行如下命令，将数据库中的url全部替换一下，搞定了！ UPDATE wp_posts SET post_content=REPLACE(post_content,'\"attachments','\"/attachments');]]></description>
			<content:encoded><![CDATA[<p>自从将url静态化变成http://litblue.net/p/850这样的形式后<br />
blog中的很多图片就无法显示了<br />
原因是我从pjblog转过来的<br />
附件的引用地址是相对地址如&#8221;attachments/jpg.jpg&#8221;<br />
原来的http://litblue.net/a.asp?850这样的文章中引用是不会有问题的<br />
但现在多了一层“目录”/p/后相对地址出来的图片url就是http://litblue.net/p/attachments/jpg.jpg<br />
执行如下命令，将数据库中的url全部替换一下，搞定了！</p>
<p><code>UPDATE wp_posts SET post_content=REPLACE(post_content,'\"attachments','\"/attachments');</code></p>
]]></content:encoded>
			<wfw:commentRss>http://litblue.net/p/1055/feed</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>[转载]netfilter技术分析</title>
		<link>http://litblue.net/p/1054</link>
		<comments>http://litblue.net/p/1054#comments</comments>
		<pubDate>Thu, 05 Feb 2009 14:19:05 +0000</pubDate>
		<dc:creator>blues</dc:creator>
				<category><![CDATA[技术相关]]></category>

		<guid isPermaLink="false">http://litblue.net/p/1054</guid>
		<description><![CDATA[　　netfilter是由Rusty Russell提出的Linux 2.4内核防火墙框架，该框架既简洁又灵活，可实现安全策略应用中的许多功能，如数据包过滤、数据包处理、地址伪装、透明代理、动态网络地址转换(Network Address Translation，NAT)，以及基于用户及媒体访问控制(Media Access Control，MAC)地址的过滤和基于状态的过滤、包速率限制等。 　　1.1 netfilter框架 　　netfilter提供了一个抽象、通用化的框架[1]，作为中间件，为每种网络协议(IPv4、IPv6等)定义一套钩子函数。Ipv4定义了5个钩子函数，这些钩子函数在数据报流过协议栈的5个关键点被调用，也就是说，IPv4协议栈上定义了5个“允许垂钓点”。在每一个“垂钓点”，都可以让netfilter放置一个“鱼钩”，把经过的网络包(Packet)钓上来，与相应的规则链进行比较，并根据审查的结果，决定包的下一步命运，即是被原封不动地放回IPv4协议栈，继续向上层递交；还是经过一些修改，再放回网络；或者干脆丢弃掉。 　　Ipv4中的一个数据包通过netfilter系统的过程如图1所示。 　　图1 Netfilter的功能框架 　　1.2 netfilter的关键技术 　　netfilter主要采用连线跟踪(Connection Tracking)、包过滤(Packet Filtering)、地址转换、包处理(Packet Mangling)4种关键技术。 　　1.2.1 连线跟踪 　　连线跟踪是包过滤、地址转换的基础，它作为一个独立的模块运行。采用连线跟踪技术在协议栈低层截取数据包，将当前数据包及其状态信息与历史数据包及其状态信息进行比较，从而得到当前数据包的控制信息，根据这些信息决定对网络数据包的操作，达到保护网络的目的。 　　当下层网络接收到初始化连接同步(Synchronize，SYN)包，将被netfilter规则库检查。该数据包将在规则链中依次序进行比较。如果该包应被丢弃，发送一个复位(Reset，RST)包到远端主机，否则连接接收。这次连接的信息将被保存在连线跟踪信息表中，并表明该数据包所应有的状态。这个连线跟踪信息表位于内核模式下，其后的网络包就将与此连线跟踪信息表中的内容进行比较，根据信息表中的信息来决定该数据包的操作。因为数据包首先是与连线跟踪信息表进行比较，只有SYN包才与规则库进行比较，数据包与连线跟踪信息表的比较都是在内核模式下进行的，所以速度很快。 　　1.2.2 包过滤 　　包过滤检查通过的每个数据包的头部，然后决定如何处置它们，可以选择丢弃，让包通过，或者更复杂的操作。 　　1.2.3 地址转换 　　网络地址转换源(NAT)分为(Source NAT，SNAT)和目的NAT(Destination NAT, DNAT)2种不同的类型。SNAT是指修改数据包的源地址(改变连接的源IP)。SNAT会在数据包送出之前的最后一刻做好转换工作。地址伪装(Masquerading)是SNAT的一种特殊形式。DNAT 是指修改数据包的目标地址(改变连接的目的IP)。DNAT 总是在数据包进入以后立即完成转换。端口转发、负载均衡和透明代理都属于DNAT。 　　1.2.4 包处理 　　利用包处理可以设置或改变数据包的服务类型(Type of Service, TOS)字段；改变包的生存期(Time to Live, TTL)字段；在包中设置标志值，利用该标志值可以进行带宽限制和分类查询]]></description>
			<content:encoded><![CDATA[<p>　　netfilter是由Rusty Russell提出的Linux 2.4内核防火墙框架，该框架既简洁又灵活，可实现安全策略应用中的许多功能，如数据包过滤、数据包处理、地址伪装、透明代理、动态网络地址转换(Network Address Translation，NAT)，以及基于用户及媒体访问控制(Media Access Control，MAC)地址的过滤和基于状态的过滤、包速率限制等。<br />
　　1.1 netfilter框架<br />
　　netfilter提供了一个抽象、通用化的框架[1]，作为中间件，为每种网络协议(IPv4、IPv6等)定义一套钩子函数。Ipv4定义了5个钩子函数，这些钩子函数在数据报流过协议栈的5个关键点被调用，也就是说，IPv4协议栈上定义了5个“允许垂钓点”。在每一个“垂钓点”，都可以让netfilter放置一个“鱼钩”，把经过的网络包(Packet)钓上来，与相应的规则链进行比较，并根据审查的结果，决定包的下一步命运，即是被原封不动地放回IPv4协议栈，继续向上层递交；还是经过一些修改，再放回网络；或者干脆丢弃掉。<br />
　　Ipv4中的一个数据包通过netfilter系统的过程如图1所示。<br />
　　图1 Netfilter的功能框架<br />
　　1.2 netfilter的关键技术<br />
　　netfilter主要采用连线跟踪(Connection Tracking)、包过滤(Packet Filtering)、地址转换、包处理(Packet Mangling)4种关键技术。<br />
　　1.2.1 连线跟踪<br />
　　连线跟踪是包过滤、地址转换的基础，它作为一个独立的模块运行。采用连线跟踪技术在协议栈低层截取数据包，将当前数据包及其状态信息与历史数据包及其状态信息进行比较，从而得到当前数据包的控制信息，根据这些信息决定对网络数据包的操作，达到保护网络的目的。<br />
　　当下层网络接收到初始化连接同步(Synchronize，SYN)包，将被netfilter规则库检查。该数据包将在规则链中依次序进行比较。如果该包应被丢弃，发送一个复位(Reset，RST)包到远端主机，否则连接接收。这次连接的信息将被保存在连线跟踪信息表中，并表明该数据包所应有的状态。这个连线跟踪信息表位于内核模式下，其后的网络包就将与此连线跟踪信息表中的内容进行比较，根据信息表中的信息来决定该数据包的操作。因为数据包首先是与连线跟踪信息表进行比较，只有SYN包才与规则库进行比较，数据包与连线跟踪信息表的比较都是在内核模式下进行的，所以速度很快。<br />
　　1.2.2 包过滤<br />
　　包过滤检查通过的每个数据包的头部，然后决定如何处置它们，可以选择丢弃，让包通过，或者更复杂的操作。<br />
　　1.2.3 地址转换<br />
　　网络地址转换源(NAT)分为(Source NAT，SNAT)和目的NAT(Destination NAT, DNAT)2种不同的类型。SNAT是指修改数据包的源地址(改变连接的源IP)。SNAT会在数据包送出之前的最后一刻做好转换工作。地址伪装(Masquerading)是SNAT的一种特殊形式。DNAT 是指修改数据包的目标地址(改变连接的目的IP)。DNAT 总是在数据包进入以后立即完成转换。端口转发、负载均衡和透明代理都属于DNAT。<br />
　　1.2.4 包处理<br />
　　利用包处理可以设置或改变数据包的服务类型(Type of Service, TOS)字段；改变包的生存期(Time to Live, TTL)字段；在包中设置标志值，利用该标志值可以进行带宽限制和分类查询</p>
]]></content:encoded>
			<wfw:commentRss>http://litblue.net/p/1054/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>强大的awk</title>
		<link>http://litblue.net/p/1041</link>
		<comments>http://litblue.net/p/1041#comments</comments>
		<pubDate>Sun, 07 Dec 2008 13:31:24 +0000</pubDate>
		<dc:creator>blues</dc:creator>
				<category><![CDATA[技术相关]]></category>

		<guid isPermaLink="false">http://litblue.net/?p=1041</guid>
		<description><![CDATA[一直都知道awk是一个很强大的东西 但是一直都没有太多机会去使用 这几天一个离职跳去Tencent的同事在QQ问我一些问题 仔细一想 这不正是当初Tencent笔试的题目吗 看来Tencent的笔试还算实在 都是平时工作遇到最多的问题拿出来考 趁机学习了一下搞懂了当初笔试没弄明白的一个问题 有下面一个文本，包含两个字段，邮箱、发送邮件字节数，分别求出每个邮箱发送字节数总和及平均数 a.txt 42116 tengxun@qq.com 41288 tengyzw@qq.com 41017 tengxun@qq.com 489389 abc@qq.com 848 fkj@qq.com 322 abc@qq.com 904 fkj@qq.com 如果不用关联数组 你可以把不同的邮箱记录提取到不同的文件中然后求和及平均，显然这很麻烦 awk一条命令搞定 cat a.txt &#124;awk &#8216;{sum[$2]+=$1;count[$2]++}END{for (i in sum) print i,sum[i], sum[i]/count[i] }&#8217; 这条简短的语句包含了很多功能，sum[$2]+=$1创建了一个以邮箱字符串为索引的数组并且把不同邮箱的发送字节数求和，count[$2]++则对邮箱出现的次数做了计数相当于uniq -c。 显示结果如下：第一列为邮箱名 第二列为和发送字节数总和 第三列为平均字节数 abc@qq.com 489711 244856 tengyzw@qq.com 41288 41288 tengxun@qq.com 83133 41566.5 fkj@qq.com 1752 876]]></description>
			<content:encoded><![CDATA[<p>一直都知道awk是一个很强大的东西<br />
但是一直都没有太多机会去使用<br />
这几天一个离职跳去Tencent的同事在QQ问我一些问题<br />
仔细一想<br />
这不正是当初Tencent笔试的题目吗<br />
看来Tencent的笔试还算实在<br />
都是平时工作遇到最多的问题拿出来考</p>
<p>趁机学习了一下搞懂了当初笔试没弄明白的一个问题</p>
<p>有下面一个文本，包含两个字段，邮箱、发送邮件字节数，分别求出每个邮箱发送字节数总和及平均数<br />
a.txt<br />
<em><br />
42116    tengxun@qq.com<br />
41288    tengyzw@qq.com<br />
41017    tengxun@qq.com<br />
489389  abc@qq.com<br />
848       fkj@qq.com<br />
322       abc@qq.com<br />
904       fkj@qq.com<br />
</em></p>
<p>如果不用关联数组<br />
你可以把不同的邮箱记录提取到不同的文件中然后求和及平均，显然这很麻烦<br />
awk一条命令搞定<br />
<strong>cat a.txt |awk &#8216;{sum[$2]+=$1;count[$2]++}END{for (i in sum) print i,sum[i], sum[i]/count[i] }&#8217; </strong><br />
这条简短的语句包含了很多功能，sum[$2]+=$1创建了一个以邮箱字符串为索引的数组并且把不同邮箱的发送字节数求和，count[$2]++则对邮箱出现的次数做了计数相当于uniq -c。<br />
显示结果如下：第一列为邮箱名 第二列为和发送字节数总和 第三列为平均字节数<br />
<em>abc@qq.com 489711 244856<br />
tengyzw@qq.com 41288 41288<br />
tengxun@qq.com 83133 41566.5<br />
fkj@qq.com 1752 876</em></p>
]]></content:encoded>
			<wfw:commentRss>http://litblue.net/p/1041/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>HTTP 状态代码</title>
		<link>http://litblue.net/p/1037</link>
		<comments>http://litblue.net/p/1037#comments</comments>
		<pubDate>Wed, 03 Dec 2008 02:27:40 +0000</pubDate>
		<dc:creator>blues</dc:creator>
				<category><![CDATA[技术相关]]></category>

		<guid isPermaLink="false">http://litblue.net/p/1037</guid>
		<description><![CDATA[作为一个互联网运维工程师 与http协议打交道和吃饭一样频繁 了解这些有助于更快速地判断故障 HTTP 状态代码 如果某项请求发送到您的服务器要求显示您网站上的某个网页（例如，用户通过浏览器访问您的网页或 Googlebot 抓取网页时），服务器将会返回 HTTP 状态代码以响应请求。 此状态代码提供关于请求状态的信息， 告诉 Googlebot 关于您的网站和请求的网页的信息。 一些常见的状态代码包括： 200 &#8211; 服务器成功返回网页 404 &#8211; 请求的网页不存在 503 &#8211; 服务器暂时不可用 下面提供 HTTP 状态代码的完整列表。 点击链接可了解详情。 您也可以访问有关 HTTP 状态代码的 W3C 网页以获得更多信息。 1xx（临时响应） 表示临时响应并需要请求者继续执行操作的状态代码。 代码 说明 100（继续） 请求者应当继续提出请求。 服务器返回此代码表示已收到请求的第一部分，正在等待其余部分。 101（切换协议） 请求者已要求服务器切换协议，服务器已确认并准备切换。 2xx（成功） 表示服务器成功处理了请求的状态代码。 代码 说明 200（成功） 服务器已成功处理了请求。 通常，这表示服务器提供了请求的网页。 如果针对您的 robots.txt 文件显示此状态，则表示 Googlebot 已成功检索到该文件。 201（已创建） [...]]]></description>
			<content:encoded><![CDATA[<p>作为一个互联网运维工程师<br />
与http协议打交道和吃饭一样频繁<br />
了解这些有助于更快速地判断故障</p>
<div class="answer_heading">
<h2 class="answer_title">HTTP 状态代码</h2>
</div>
<p>如果某项请求发送到您的服务器要求显示您网站上的某个网页（例如，用户通过浏览器访问您的网页或 Googlebot 抓取网页时），服务器将会返回 HTTP 状态代码以响应请求。</p>
<p>此状态代码提供关于请求状态的信息， 告诉 Googlebot 关于您的网站和请求的网页的信息。</p>
<p>一些常见的状态代码包括：</p>
<ul>
<li><strong>200</strong> &#8211; 服务器成功返回网页</li>
<li><strong>404</strong> &#8211; 请求的网页不存在</li>
<li><strong>503</strong> &#8211; 服务器暂时不可用</li>
</ul>
<p>下面提供 HTTP 状态代码的完整列表。 点击链接可了解详情。 您也可以访问有关 HTTP 状态代码的 <a onclick="pageTracker._trackPageview('/outgoing/www.w3.org/Protocols/rfc2616/rfc2616-sec10.html?referer=');" href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html">W3C 网页以获得更多信息</a>。</p>
<p>1xx（临时响应）<br />
表示临时响应并需要请求者继续执行操作的状态代码。</p>
<p>代码 说明<br />
100（继续） 请求者应当继续提出请求。 服务器返回此代码表示已收到请求的第一部分，正在等待其余部分。<br />
101（切换协议） 请求者已要求服务器切换协议，服务器已确认并准备切换。 </p>
<p>2xx（成功）</p>
<p>表示服务器成功处理了请求的状态代码。</p>
<p>代码 说明<br />
200（成功） 服务器已成功处理了请求。 通常，这表示服务器提供了请求的网页。 如果针对您的 robots.txt 文件显示此状态，则表示 Googlebot 已成功检索到该文件。<br />
201（已创建） 请求成功并且服务器创建了新的资源。<br />
202（已接受） 服务器已接受请求，但尚未处理。<br />
203（非授权信息） 服务器已成功处理了请求，但返回的信息可能来自另一来源。<br />
204（无内容） 服务器成功处理了请求，但没有返回任何内容。<br />
205（重置内容） 服务器成功处理了请求，但没有返回任何内容。 与 204 响应不同，此响应要求请求者重置文档视图（例如，清除表单内容以输入新内容）。<br />
206（部分内容） 服务器成功处理了部分 GET 请求。 </p>
<p>3xx（重定向）<br />
要完成请求，需要进一步操作。 通常，这些状态代码用来重定向。 Google 建议您在每次请求中使用重定向不要超过 5 次。 您可以使用网站管理员工具查看一下 Googlebot 在抓取重定向网页时是否遇到问题。 诊断下的网络抓取页面列出了由于重定向错误而导致 Googlebot 无法抓取的网址。</p>
<p>代码 说明<br />
300（多种选择） 针对请求，服务器可执行多种操作。 服务器可根据请求者（用户代理）选择一项操作，或提供操作列表供请求者选择。<br />
301（永久移动） 请求的网页已永久移动到新位置。 服务器返回此响应（对 GET 或 HEAD 请求的响应）时，会自动将请求者转到新位置。 您应使用此代码告诉 Googlebot 某个网页或网站已永久移动到新位置。<br />
302（暂时移动） 服 务器目前从不同位置的网页响应请求，但请求者应继续使用原有位置来进行以后的请求。 此代码与响应 GET 或 HEAD 请求的 301 代码类似，会自动将请求者转到不同的位置，但您不应使用此代码来告诉 Googlebot 某个网页或网站已经移动，因为 Googlebot 会继续抓取原有位置并编入索引。<br />
303（查看其他位置） 请求者应当对不同的位置使用单独的 GET 请求来检索响应时，服务器返回此代码。 对于除 HEAD 之外的所有请求，服务器会自动转到其他位置。<br />
304（未修改） 自从上次请求后，请求的网页未修改过。 服务器返回此响应时，不会返回网页内容。</p>
<p>如果网页自请求者上次请求后再也没有更改过，您应当将服务器配置为返回此响应（称为 If-Modified-Since HTTP 标头）。 由于服务器可以告诉 Googlebot 自从上次抓取后网页没有更改过，因此可节省带宽和开销</p>
<p>。</p>
<p>305（使用代理） 请求者只能使用代理访问请求的网页。 如果服务器返回此响应，还表示请求者应使用代理。<br />
307（暂时重定向） 服 务器目前从不同位置的网页响应请求，但请求者应继续使用原有位置来进行以后的请求。 此代码与响应 GET 和 HEAD 请求的 301 代码类似，会自动将请求者转到不同的位置，但您不应使用此代码来告诉 Googlebot 某个页面或网站已经移动，因为 Googlebot 会继续抓取原有位置并编入索引。 </p>
<p>4xx（请求错误）<br />
这些状态代码表示请求可能出错，妨碍了服务器的处理。</p>
<p>代码 说明<br />
400（错误请求） 服务器不理解请求的语法。<br />
401（未授权） 请求要求身份验证。 对于需要登录的网页，服务器可能返回此响应。<br />
403（禁止） 服务器拒绝请求。 如果您看到 Googlebot 在尝试抓取您网站上的有效网页时收到此状态代码（可以在 Google 网站管理员工具诊断下的网络抓取页面上看到此信息），可能是您的服务器或主机拒绝 Googlebot 访问。<br />
404（未找到） 服务器找不到请求的网页。 例如，如果请求服务器上不存在的网页，服务器通常会返回此代码。</p>
<p>如果您的网站上没有 robots.txt 文件，而您在 Google 网站管理员工具”诊断”标签的 robots.txt 页上看到此状态，那么这是正确的状态。 但是，如果您有 robots.txt 文件而又看到此状态，则说明您的 robots.txt 文件可能命名错误或位于错误的位置 （该文件应当位于顶级域名，名为 robots.txt）。</p>
<p>如果您看到有关 Googlebot 尝试抓取的网址的此状态（在”诊断”标签的 HTTP 错误页上），则表示 Googlebot 追踪的可能是另一个页面的无效链接（是旧链接或输入有误的链接）。</p>
<p>405（禁用的方法） 禁用请求中指定的方法。<br />
406（不可接受） 无法使用请求的内容特性响应请求的网页。<br />
407（需要代理授权） 此状态代码与 401（未授权）类似，但指定请求者应当授权使用代理。 如果服务器返回此响应，还会指明请求者应当使用的代理。<br />
408（请求超时） 服务器等候请求时发生超时。<br />
409（冲突） 服务器在完成请求时发生冲突。 服务器必须在响应中包含有关冲突的信息。 服务器在响应与前一个请求相冲突的 PUT 请求时可能会返回此代码，同时会附上两个请求的差异列表。<br />
410（已删除） 如果请求的资源已永久删除，服务器就会返回此响应。 该代码与 404（未找到）代码相似，但在资源以前存在而现在不存在的情况下，有时会用来替代 404 代码。 如果资源已永久删除，您应当使用 301 指定资源的新位置。<br />
411（需要有效长度） 服务器不接受不含有效内容长度标头字段的请求。<br />
412（未满足前提条件） 服务器未满足请求者在请求中设置的其中一个前提条件。<br />
413（请求实体过大） 服务器无法处理请求，因为请求实体过大，超出服务器的处理能力。<br />
414（请求的 URI 过长） 请求的 URI（通常为网址）过长，服务器无法处理。<br />
415（不支持的媒体类型） 请求的格式不受请求页面的支持。<br />
416（请求范围不符合要求） 如果页面无法提供请求的范围，则服务器会返回此状态代码。<br />
417（未满足期望要求） 服务器未满足”期望”请求标头字段的要求。 </p>
<p>5xx（服务器错误）<br />
这些状态代码表示服务器在尝试处理请求时发生内部错误。 这些错误可能是服务器本身的错误，而不是请求出错。</p>
<p>代码 说明<br />
500（服务器内部错误） 服务器遇到错误，无法完成请求。<br />
501（尚未实施） 服务器不具备完成请求的功能。 例如，服务器无法识别请求方法时可能会返回此代码。<br />
502（错误网关） 服务器充当网关或代理，从上游服务器收到无效响应。<br />
503（服务不可用） 服务器目前无法使用（由于超载或停机维护）。 通常，这只是暂时状态。<br />
504（网关超时） 服务器充当网关或代理，但没有及时从上游服务器收到请求。<br />
505（HTTP 版本不受支持） 服务器不支持请求中所用的 HTTP 协议版本。 </p>
]]></content:encoded>
			<wfw:commentRss>http://litblue.net/p/1037/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Web压力测试工具介绍</title>
		<link>http://litblue.net/p/1031</link>
		<comments>http://litblue.net/p/1031#comments</comments>
		<pubDate>Mon, 24 Nov 2008 05:56:41 +0000</pubDate>
		<dc:creator>blues</dc:creator>
				<category><![CDATA[技术相关]]></category>

		<guid isPermaLink="false">http://litblue.net/p/1031</guid>
		<description><![CDATA[原文出自Web压力测试工具介绍 Web压力测试工具介绍 1 http_load 1.1 官方网站 1.2 具体操作及说明 2 ab 2.1 官方网站 2.2 具体操作 2.3 文档说明 1 http_load 1.1 官方网站 描述： http_load runs multiple http fetches in parallel, to test the throughput of a web server. However unlike most such test clients, it runs in a single process, so it doesn&#8217;t bog down the client [...]]]></description>
			<content:encoded><![CDATA[<p>原文出自<a href="http://my.huhoo.net/archives/2008/01/web.html">Web压力测试工具介绍</a></p>
<h3 class="entry-header">Web压力测试工具介绍</h3>
<div class="entry-content">
<div class="entry-body">
<div class="twikiToc">
<ul>
<li><a href="http://litblue.net/p/1031#1_http_load">1 http_load</a>
<ul>
<li><a href="http://litblue.net/p/1031#1_1">1.1 官方网站</a></li>
<li><a href="http://litblue.net/p/1031#1_2">1.2 具体操作及说明</a></li>
</ul>
</li>
<li><a href="http://litblue.net/p/1031#2_ab">2 ab</a>
<ul>
<li><a href="http://litblue.net/p/1031#2_1">2.1 官方网站</a></li>
<li><a href="http://litblue.net/p/1031#2_2">2.2 具体操作</a></li>
<li><a href="http://litblue.net/p/1031#2_3">2.3 文档说明</a></li>
</ul>
</li>
</ul>
</div>
</div>
<div id="more" class="entry-more">
<h2><a name="1_http_load" href="http://my.huhoo.net/mt-static/html/editor-content.html?cs=utf-8"></a>1 http_load</h2>
<h3><a name="1_1" href="http://my.huhoo.net/mt-static/html/editor-content.html?cs=utf-8"></a><a name="1_1_" href="http://my.huhoo.net/mt-static/html/editor-content.html?cs=utf-8"></a>1.1 官方网站</h3>
<ul>
<li>描述：
<ul>
<li>http_load runs multiple http fetches in parallel, to test the throughput of a web server. However unlike most such test clients, it runs in a single process, so it doesn&#8217;t bog down the client machine. It can be configured to do https fetches as well.</li>
<li>You give it a file containing a list of URLs that may be fetched, a flag specifying how to start connections (either by rate or by number of simulated users), and a flag specifying when to quit (either after a given number of fetches or a given elapsed time). There are also optional flags for checksums, throttling, random jitter, and progress reports.</li>
</ul>
</li>
<li>地址：
<ul>
<li><a href="http://www.acme.com/software/http_load/" target="_top">http://www.acme.com/software/http_load/</a></li>
</ul>
</li>
</ul>
<h3><a name="1_2" href="http://my.huhoo.net/mt-static/html/editor-content.html?cs=utf-8"></a><a name="1_2_" href="http://my.huhoo.net/mt-static/html/editor-content.html?cs=utf-8"></a>1.2 具体操作及说明</h3>
<ul>
<li>常用样例</li>
</ul>
<pre>http_load -parallel 5 -fetches 1000 urls.txt
http_load -rate 2 -seconds 300 urls.txt</pre>
<ul>
<li>样例含义
<ul>
<li>-parallel 简写-p ：含义是并发的用户进程数。</li>
<li>-fetches 简写-f ：含义是总计的访问次数</li>
<li>-rate 简写-r ：含义是每秒的访问频率</li>
<li>-seconds简写-s ：含义是总计的访问时间</li>
<li>urls.txt 是一个url 列表，每个url 单独的一行；不可以直接跟一个url，有些博客主说的可以跟一个url是错误的说法。</li>
</ul>
</li>
<li>返回结果</li>
</ul>
<pre>http_load -rate 5 -seconds 10 urls
49 fetches, 2 max parallel, 289884 bytes, in 10.0148 seconds
5916 mean bytes/connection
4.89274 fetches/sec, 28945.5 bytes/sec
msecs/connect: 28.8932 mean, 44.243 max, 24.488 min
msecs/first-response: 63.5362 mean, 81.624 max, 57.803 min
HTTP response codes:
code 200 -- 49</pre>
<ul>
<li>结果含义
<ul>
<li>49 fetches, 2 max parallel, 289884 bytes, in 10.0148 seconds</li>
<li>说明在上面的测试中运行了49个请求，最大的并发进程数是2，总计传输的数据是289884bytes，运行的时间是10.0148秒</li>
</ul>
</li>
</ul>
<ul>
<li>
<ul>
<li>5916 mean bytes/connection</li>
<li>说明每一连接平均传输的数据量289884/49=5916</li>
</ul>
</li>
</ul>
<ul>
<li>
<ul>
<li>4.89274 fetches/sec, 28945.5 bytes/sec</li>
<li>说明每秒的响应请求为4.89274，每秒传递的数据为28945.5 bytes/sec</li>
</ul>
</li>
</ul>
<ul>
<li>
<ul>
<li>msecs/connect: 28.8932 mean, 44.243 max, 24.488 min</li>
<li>说明每连接的平均响应时间是28.8932 msecs，最大的响应时间44.243 msecs，最小的响应时间24.488 msecs</li>
</ul>
</li>
</ul>
<ul>
<li>
<ul>
<li>msecs/first-response: 63.5362 mean, 81.624 max, 57.803 min</li>
</ul>
</li>
</ul>
<ul>
<li>
<ul>
<li>HTTP response codes: code 200 &#8212; 49</li>
<li>说明打开响应页面的类型，如果403的类型过多，那可能要注意是否系统遇到了瓶颈。</li>
</ul>
</li>
</ul>
<ul>
<li>特殊说明
<ul>
<li>一般会关注到的指标是fetches/sec、msecs/connect，它们分别对应的常用性能指标参数QPS-每秒响应用户数和response time，每连接响应用户时间。测试的结果主要也是看这两个值。当然仅有这两个指标并不能完成对性能的分析，我们还需要对服务器的cpu、men进行分析，才能得出结论；</li>
<li>如果要测试HTTPS，需要在编译前指定Makefile中 <strong>SSL_TREE</strong> 的路径：一般为 <em>/usr</em> 或 <em>/usr/local</em> 。</li>
</ul>
</li>
</ul>
<h2><a name="2_ab" href="http://my.huhoo.net/mt-static/html/editor-content.html?cs=utf-8"></a>2 ab</h2>
<h3><a name="2_1" href="http://my.huhoo.net/mt-static/html/editor-content.html?cs=utf-8"></a><a name="2_1_" href="http://my.huhoo.net/mt-static/html/editor-content.html?cs=utf-8"></a>2.1 官方网站</h3>
<ul>
<li>描述：
<ul>
<li>ab is a tool for benchmarking your Apache Hypertext Transfer Protocol (HTTP) server. It is designed to give you an impression of how your current Apache installation performs. This especially shows you how many requests per second your Apache installation is capable of serving.</li>
</ul>
</li>
<li>地址：
<ul>
<li><a href="http://httpd.apache.org/docs/2.0/programs/ab.html" target="_top">http://httpd.apache.org/docs/2.0/programs/ab.html</a></li>
</ul>
</li>
</ul>
<h3><a name="2_2" href="http://my.huhoo.net/mt-static/html/editor-content.html?cs=utf-8"></a><a name="2_2_" href="http://my.huhoo.net/mt-static/html/editor-content.html?cs=utf-8"></a>2.2 具体操作</h3>
<ul>
<li>常用样例</li>
</ul>
<pre>ab -n 1000 -c 50 http://www.domain.com/myapp.php</pre>
<ul>
<li>样例说明
<ul>
<li>ab将同时向http://www.domain.com/myapp.php发出50个并发请求，共发出1000次。</li>
</ul>
</li>
<li>返回结果</li>
</ul>
<pre>Server Software:        nginx/0.6.25
Server Hostname:        www.domain.com
Server Port:            80

Document Path:          /myapp.php
Document Length:        37899 bytes

Concurrency Level:      100
Time taken for tests:   26.507540 seconds
Complete requests:      2000
Failed requests:        14
   (Connect: 0, Length: 14, Exceptions: 0)
Write errors:           0
Keep-Alive requests:    0
Total transferred:      75931178 bytes
HTML transferred:       75439670 bytes
Requests per second:    75.45 [#/sec] (mean)
Time per request:       1325.377 [ms] (mean)
Time per request:       13.254 [ms] (mean, across all concurrent requests)
Transfer rate:          2797.36 [Kbytes/sec] received

Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:       24  640 1310.9     34    7478
Processing:    86  590 2230.9    124   23256
Waiting:        0   55 207.7     41    8292
Total:        112 1230 2501.0    169   23304</pre>
<ul>
<li>
<ul>
<li>部分返回字串省略，这里只表示关键部分；</li>
<li>myapp.php每秒钟可以处理的请求数为75.45个</li>
</ul>
</li>
<li>特殊说明
<ul>
<li>若将请求数增加，看看服务器能否处理更大的压力，需要调节Apache的 <strong>MaxClients、ThreadsPerChild、MaxThreadsPerChild</strong> 等参数，基于httpd.conf中的MPM模块选择。</li>
<li>若本地服务器不是Apache，请使用其它测试方法。</li>
</ul>
</li>
</ul>
<h3><a name="2_3" href="http://my.huhoo.net/mt-static/html/editor-content.html?cs=utf-8"></a><a name="2_3_" href="http://my.huhoo.net/mt-static/html/editor-content.html?cs=utf-8"></a>2.3 文档说明</h3>
<ul>
<li>见 <a href="http://httpd.apache.org/docs/2.0/programs/ab.html" target="_top">http://httpd.apache.org/docs/2.0/programs/ab.html</a> 细节。</li>
</ul>
</div>
</div>
]]></content:encoded>
			<wfw:commentRss>http://litblue.net/p/1031/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>openvpn中的topology subnet</title>
		<link>http://litblue.net/p/982</link>
		<comments>http://litblue.net/p/982#comments</comments>
		<pubDate>Sun, 14 Sep 2008 05:46:13 +0000</pubDate>
		<dc:creator>blues</dc:creator>
				<category><![CDATA[技术相关]]></category>

		<guid isPermaLink="false">http://litblue.net/?p=982</guid>
		<description><![CDATA[openvpn是一个不可多得的好软件 而且难得作者还在维护 可以说这个vpn软件不比市场上某些商业性质的vpn差 离开上家公司后 没怎么摆弄openvpn了 最近看到主页上有更新 最新的版本为2.1 rc10 仔细看了一下更新中有一个很有意思的特性 topology subnet feature, allowing intuitive tun-based VPN subnets having 1 IP address per client. 这个特性应该在2.1版本中很早就有 不过一直没有注意到 使用这个特性后，在tun模式下，就不需要每个客户端占用/30大小的子网了，确实很棒，因为之前公司使用openvpn作大规模部署中因为/30子网这个问题带来不少麻烦，现在都解决了。 man page中这样描述 &#8211;topology mode               Configure virtual addressing topology when running in &#8211;dev tun mode.  This directive  has  no  meaning  in               &#8211;dev tap mode, which always uses a [...]]]></description>
			<content:encoded><![CDATA[<p>openvpn是一个不可多得的好软件<br />
而且难得作者还在维护<br />
可以说这个vpn软件不比市场上某些商业性质的vpn差</p>
<p>离开上家公司后<br />
没怎么摆弄openvpn了<br />
最近看到主页上有更新<br />
最新的版本为2.1 rc10<br />
仔细看了一下更新中有一个很有意思的特性</p>
<blockquote>
<li><strong>topology subnet</strong> feature, allowing intuitive tun-based VPN subnets having 1 IP address per client.</li>
</blockquote>
<p>这个特性应该在2.1版本中很早就有<br />
不过一直没有注意到<br />
使用这个特性后，在tun模式下，就不需要每个客户端占用/30大小的子网了，确实很棒，因为之前公司使用openvpn作大规模部署中因为/30子网这个问题带来不少麻烦，现在都解决了。</p>
<p>man page中这样描述</p>
<blockquote><p>&#8211;topology mode<br />
              Configure virtual addressing topology when running in &#8211;dev tun mode.  This directive  has  no  meaning  in<br />
              &#8211;dev tap mode, which always uses a subnet topology.</p>
<p>              If  you  set  this  directive on the server, the &#8211;server and &#8211;server-bridge directives will automatically<br />
              push your chosen topology setting to clients as well.  This  directive  can  also  be  manually  pushed  to<br />
              clients.  Like the &#8211;dev directive, this directive must always be compatible between client and server.</p>
<p>              mode can be one of:</p>
<p>              net30 &#8212; Use a point-to-point topology, by allocating one /30 subnet per client.  This is designed to allow<br />
              point-to-point semantics when some or all of the connecting clients might be Windows systems.  This is  the<br />
              default on OpenVPN 2.0.</p>
<p>              p2p  &#8212; Use a point-to-point topology where the remote endpoint of the client&#8217;s tun interface always points<br />
              to the local endpoint of the server&#8217;s tun interface.  This mode allocates a single IP address per  connect-<br />
              ing  client.   Only use when none of the connecting clients are Windows systems.  This mode is functionally<br />
              equivalent to the &#8211;ifconfig-pool-linear directive which is available in OpenVPN 2.0 and is now deprecated.</p>
<p>              subnet  &#8212; Use a subnet rather than a point-to-point topology by configuring the tun interface with a local<br />
              IP address and subnet mask, similar to the topology used in &#8211;dev tap and  ethernet  bridging  mode.   This<br />
              mode allocates a single IP address per connecting client and works on Windows as well.  Only available when<br />
              server and clients are OpenVPN 2.1 or higher, or OpenVPN 2.0.x which has been  manually  patched  with  the<br />
              &#8211;topology  directive  code.  When used on Windows, requires version 8.2 or higher of the TAP-Win32 driver.<br />
              When used on *nix, requires that the tun driver supports an ifconfig(8) command which sets a subnet instead<br />
              of a remote endpoint IP address.</p>
<p>              This option exists in OpenVPN 2.1 or higher.</p></blockquote>
]]></content:encoded>
			<wfw:commentRss>http://litblue.net/p/982/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>shell中的几个特殊变量</title>
		<link>http://litblue.net/p/975</link>
		<comments>http://litblue.net/p/975#comments</comments>
		<pubDate>Fri, 05 Sep 2008 13:45:13 +0000</pubDate>
		<dc:creator>blues</dc:creator>
				<category><![CDATA[技术相关]]></category>

		<guid isPermaLink="false">http://litblue.net/p/975</guid>
		<description><![CDATA[灵活运用这些变量 会让你编写脚本更加自如 $0 shell或shell脚本的名字 $* 以一对双引号给出参数列表 $@ 将各个参数分别加双引号返回 $# 参数的个数 $_ 代表上一个命令的最后一个参数 $$ 代表所在命令的PID $! 代表最后执行的后台命令的PID $? 代表上一个命令执行后的退出状态]]></description>
			<content:encoded><![CDATA[<p>灵活运用这些变量<br />
会让你编写脚本更加自如</p>
<blockquote><p>$0<br />
 shell或shell脚本的名字<br />
$*<br />
 以一对双引号给出参数列表<br />
$@<br />
 将各个参数分别加双引号返回<br />
$#<br />
 参数的个数<br />
$_<br />
 代表上一个命令的最后一个参数<br />
$$<br />
 代表所在命令的PID<br />
$!<br />
 代表最后执行的后台命令的PID<br />
$?<br />
 代表上一个命令执行后的退出状态</p></blockquote>
]]></content:encoded>
			<wfw:commentRss>http://litblue.net/p/975/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>HP瘦客户端</title>
		<link>http://litblue.net/p/916</link>
		<comments>http://litblue.net/p/916#comments</comments>
		<pubDate>Tue, 03 Jun 2008 12:59:17 +0000</pubDate>
		<dc:creator>blues</dc:creator>
				<category><![CDATA[技术相关]]></category>

		<guid isPermaLink="false">http://litblue.net/?p=916</guid>
		<description><![CDATA[最近测试的hp瘦客户端 和无盘类似 这个小机器里内置了Win CE 连接到服务器的终端服务 内置了VNC用于远程管理]]></description>
			<content:encoded><![CDATA[<p>最近测试的hp瘦客户端<br />
和无盘类似<br />
这个小机器里内置了Win CE<br />
连接到服务器的终端服务<br />
内置了VNC用于远程管理<br />
<a href='http://litblue.net/attachments/2008/06/img_0126.jpg'><img src="http://litblue.net/attachments/2008/06/img_0126.jpg" alt="" title="img_0126" width="422" height="322" class="alignnone size-medium wp-image-917" /></a></p>
<p><a href='http://litblue.net/attachments/2008/06/img_0128.jpg'><img src="http://litblue.net/attachments/2008/06/img_0128.jpg" alt="" title="img_0128" width="322" height="422" class="alignnone size-medium wp-image-918" /></a></p>
<p><a href='http://litblue.net/attachments/2008/06/img_0118.jpg'><img src="http://litblue.net/attachments/2008/06/img_0118.jpg" alt="" title="img_0118" width="422" height="322" class="alignnone size-medium wp-image-919" /></a></p>
]]></content:encoded>
			<wfw:commentRss>http://litblue.net/p/916/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>iptables日志简单处理脚本</title>
		<link>http://litblue.net/p/886</link>
		<comments>http://litblue.net/p/886#comments</comments>
		<pubDate>Sat, 12 Apr 2008 13:28:25 +0000</pubDate>
		<dc:creator>blues</dc:creator>
				<category><![CDATA[技术相关]]></category>

		<guid isPermaLink="false">http://litblue.net/?p=453</guid>
		<description><![CDATA[对于iptables的日志,找了很久都没有一个好的工具来输出我自己想要的格式,按条件来查询日志. 于是自己动手写了一个脚本.脚本很简单,几个grep组合而已. 当然这个脚本还很不完善,比如-l参数还不可用,-t参数还很粗糙.但是基本的功能已经实现了,用来做点小查询已经够用了.如果发挥你的想象力,可以用来定期处理日志,再加工处理一下,输出到web或者其它介质也是有可能的. 不过我没这个精力去完成. PS:使用这个脚本的前提是,你要在iptables规则中输出日志,并给日志加上形如log-prefix &#8216;Firewall &#8216;的前缀,注意引号里面单词后面有一个空格.否则可能得不到脚本预期的输出结果.     文件名:fwlog     用途:     根据条件分析处理iptables日志，只输出我们关心的内容以方便查看     输入格式为  Apr 11 13:40:04 iptablesforward SRC=192.168.39.67 DST=74.220.215.221 PROTO=TCP SPT=1081 DPT=80     用法:     chmod +x fwlog           ./fwlog  [-l language] [-h help] [-s SRC] [-d DST] [-S SPT]            [-D DPT] [-t time] [-m mark] [-p protocol] [-i inputfilename]            [-o inputfilename]             [...]]]></description>
			<content:encoded><![CDATA[<p>对于iptables的日志,找了很久都没有一个好的工具来输出我自己想要的格式,按条件来查询日志.<br />
于是自己动手写了一个脚本.脚本很简单,几个grep组合而已.<br />
当然这个脚本还很不完善,比如-l参数还不可用,-t参数还很粗糙.但是基本的功能已经实现了,用来做点小查询已经够用了.如果发挥你的想象力,可以用来定期处理日志,再加工处理一下,输出到web或者其它介质也是有可能的.<br />
不过我没这个精力去完成.</p>
<p>PS:使用这个脚本的前提是,你要在iptables规则中输出日志,并给日志加上形如log-prefix &#8216;Firewall &#8216;的前缀,注意引号里面单词后面有一个空格.否则可能得不到脚本预期的输出结果.</p>
<p>    文件名:fwlog</p>
<p>    用途:     根据条件分析处理iptables日志，只输出我们关心的内容以方便查看<br />
    输入格式为  Apr 11 13:40:04 iptablesforward SRC=192.168.39.67 DST=74.220.215.221 PROTO=TCP SPT=1081 DPT=80</p>
<p>    用法:     chmod +x fwlog</p>
<p>          ./fwlog  [-l language] [-h help] [-s SRC] [-d DST] [-S SPT]<br />
           [-D DPT] [-t time] [-m mark] [-p protocol] [-i inputfilename]<br />
           [-o inputfilename]<br />
            -l 结果显示的语言 en 为英语,chs为中文.<br />
            -h 显示帮助<br />
            -s 源IP 形如192.168.1.1<br />
            -d 目的IP<br />
            -S 源端口 形如80<br />
            -D 目的端口 形如80<br />
            -p 协议类型 形如TCP(大写)<br />
            -m iptables chain标识(需要自己在日志中自定义)<br />
            -i 日志文件所在路径<br />
            -o 处理脚本输出路径 不选则输出到屏幕<br />
    日期:     2008年4月8日<br />
    版本:     version 0.9 build 20080408</p>
<blockquote><p><span id="more-886"></span> #! /bin/bash<br />
##############################################################################<br />
##<br />
## 文件名:   fwlog�<br />
## 用途:     根据条件分析处理iptables日志<br />
## 用法:     chmod +x fwlog;<br />
##          ./fwlog  [-l language] [-h help] [-s SIP] [-d DIP] [-S SPT]<br />
##          [-D DPT] [-t time] [-c chain] [-p protocol]<br />
##          -l 结果显示的语言 en 为英语,chs为中文<br />
##          -h 显示帮助<br />
##          -s 源IP 形如192.168.1.1<br />
##          -d 目的IP<br />
##          -S 源端口 形如80<br />
##          -D 目的端口 形如80<br />
##          -p 协议类型 形如TCP(大写)<br />
##          -m iptables日志标识(需要自己在日志中自定义)<br />
##          -m iptables chain标识(需要自己在日志中自定义)<br />
##          -i 日志文件所在路径<br />
##          -o 处理脚本输出路径 不选则输出到屏幕<br />
##<br />
## 日期:     2008年4月8日<br />
## 版本:     version 0.9 build 20080408<br />
## MailTo: �<br />
##<br />
##############################################################################<br />
# common location<br />
DATUM=`date +%Y%m%d%H%M%S`</p>
<p># parse args<br />
loglanguage=<br />
prog=`basename $0`<br />
SIP=<br />
DIP=<br />
SPT=<br />
time=<br />
markstring=<br />
protocol=<br />
datum=<br />
file=<br />
outputfilename=<br />
inputfilename=</p>
<p>usage()<br />
{<br />
    echo &#8220;    文件名:   fwlog                                                         �<br />
    用途:     根据条件分析处理iptables日志，只输出我们关心的内容以方便查看<br />
    输入格式为  Apr 11 13:40:04 iptablesforward SRC=192.168.39.67 DST=74.220.215.221 PROTO=TCP SPT=1081 DPT=80<br />
    用法:     chmod +x fwlog; �<br />
          ./fwlog  [-l language] [-h help] [-s SRC] [-d DST] [-S SPT]<br />
           [-D DPT] [-t time] [-m mark] [-p protocol] [-i inputfilename]<br />
           [-o inputfilename]<br />
            -l 结果显示的语言 en 为英语,chs为中文<br />
            -h 显示帮助<br />
            -s 源IP 形如192.168.1.1<br />
            -d 目的IP<br />
            -S 源端口 形如80<br />
            -D 目的端口 形如80<br />
            -p 协议类型 形如TCP(大写)<br />
            -m iptables chain标识(需要自己在日志中自定义)<br />
            -i 日志文件所在路径<br />
            -o 处理脚本输出路径 不选则输出到屏幕<br />
    日期:     2008年4月8日<br />
    版本:     version 0.9 build 20080408 &#8221;  </p>
<p>}</p>
<p>if [ -z "$1" ]; then<br />
    usage; exit 1<br />
fi<br />
while getopts l:s:S:d:D:t:m:p:i:o:h opt ; do<br />
 case &#8220;$opt&#8221; in<br />
 l) loglanguage=&#8221;$OPTARG&#8221; ;;<br />
 s) SRC=\|grep\ SRC=&#8221;$OPTARG&#8221; ;;<br />
 S) SPT=\|grep\ SPT=&#8221;$OPTARG&#8221; ;;<br />
 d) DST=\|grep\ DST=&#8221;$OPTARG&#8221; ;;<br />
 D) DPT=\|grep\ DPT=&#8221;$OPTARG&#8221; ;;<br />
 p) protocol=\|grep\ PROTO=&#8221;$OPTARG&#8221; ;;<br />
    t) time=\|grep\ &#8220;$OPTARG&#8221; ;;<br />
 m) markstring=\|grep\ &#8220;$OPTARG&#8221; ;;<br />
 o) outputfilename=&#8221;&gt; $OPTARG&#8221; ;;<br />
 i) inputfilename=&#8221;$OPTARG&#8221; ;;<br />
 h) usage; exit 0 ;;<br />
 *) usage; exit 1 ;;<br />
 esac<br />
done<br />
if [ -z "$inputfilename" ]; then<br />
    usage;echo &#8220;!!!!!!请输入日志文件路径!1!!!!!!!!&#8221;;exit 1<br />
fi</p>
<p>grepstring=&#8221;grep SRC $inputfilename |grep DF |sed &#8216;s/\[.*\]//g&#8217;|grep -v MAC $SRC $SPT $DST $DPT $protocal $time $markstring  | awk &#8216;{print \$1 \&#8221; \&#8221;\$2\&#8221; \&#8221;\$3\&#8221; \&#8221;\$6\&#8221; \&#8221;\$9\&#8221; \&#8221;\$10\&#8221; \&#8221;\$17\&#8221; \&#8221;\$18\&#8221; \&#8221;\$19 }&#8217; $outputfilename&#8221;<br />
if [ -z "$outputfilename" ]; then<br />
    grepstringnodf=&#8221;grep SRC $inputfilename |grep -v DF |sed &#8216;s/\[.*\]//g&#8217;|grep -v MAC $SRC $SPT $DST $DPT $protocal $time $markstring  | awk &#8216;{print \$1 \&#8221; \&#8221;\$2\&#8221; \&#8221;\$3\&#8221; \&#8221;\$6\&#8221; \&#8221;\$9\&#8221; \&#8221;\$10\&#8221; \&#8221;\$16\&#8221; \&#8221;\$17\&#8221; \&#8221;\$18 }&#8217; $outputfilename&#8221;</p>
<p>    grepstringmac=&#8221;grep SRC $inputfilename |grep MAC |sed &#8216;s/\[.*\]//g&#8217;$SRC $SPT $DST $DPT $protocal $time $markstring  | awk &#8216;{print \$1 \&#8221; \&#8221;\$2\&#8221; \&#8221;\$3\&#8221; \&#8221;\$6\&#8221; \&#8221;\$10\&#8221; \&#8221;\$11\&#8221; \&#8221;\$18\&#8221; \&#8221;\$19\&#8221; \&#8221;\$20 }&#8217; $outputfilename&#8221;<br />
else<br />
    grepstringnodf=&#8221;grep SRC $inputfilename |grep -v DF |sed &#8216;s/\[.*\]//g&#8217;|grep -v MAC $SRC $SPT $DST $DPT $protocal $time $markstring  | awk &#8216;{print \$1 \&#8221; \&#8221;\$2\&#8221; \&#8221;\$3\&#8221; \&#8221;\$6\&#8221; \&#8221;\$9\&#8221; \&#8221;\$10\&#8221; \&#8221;\$16\&#8221; \&#8221;\$17\&#8221; \&#8221;\$18 }&#8217; &gt;$outputfilename&#8221;</p>
<p>    grepstringmac=&#8221;grep SRC $inputfilename |grep MAC |sed &#8216;s/\[.*\]//g&#8217;$SRC $SPT $DST $DPT $protocal $time $markstring  | awk &#8216;{print \$1 \&#8221; \&#8221;\$2\&#8221; \&#8221;\$3\&#8221; \&#8221;\$6\&#8221; \&#8221;\$10\&#8221; \&#8221;\$11\&#8221; \&#8221;\$18\&#8221; \&#8221;\$19\&#8221; \&#8221;\$20 }&#8217; &gt;$outputfilename&#8221;<br />
fi<br />
bash -c &#8220;$grepstring&#8221;<br />
bash -c &#8220;$grepstringnodf&#8221;<br />
bash -c &#8220;$grepstringmac&#8221;</p></blockquote>
]]></content:encoded>
			<wfw:commentRss>http://litblue.net/p/886/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>wubi安装ubuntu</title>
		<link>http://litblue.net/p/885</link>
		<comments>http://litblue.net/p/885#comments</comments>
		<pubDate>Sun, 06 Apr 2008 04:42:06 +0000</pubDate>
		<dc:creator>blues</dc:creator>
				<category><![CDATA[技术相关]]></category>

		<guid isPermaLink="false">http://litblue.net/?p=451</guid>
		<description><![CDATA[在ubuntu 8.04中，正式引入了wubi这种全新的安装方式。对于我的破笔记本来说简直就是一种福音啊。 之前装linux&#38;xp双系统，带来的结果就是两次分区表出错，差点硬盘废了。第二次出错时我就很坚决地把linux分区格式化了。 于是在wubi下安装了ubuntu. 总的来说，这种安装方式还是很不错的，不用分区，不用搞那些乱七八糟的引导，像装个应用程序那么简单。 实际运行的性能，没感觉到有太大的损失，或许我这种普通的应用感觉不出性能，又或许我的破笔记本没有性能可言。 Linux下比较大的问题就是中文字体的问题，wqy字体渲染太耗cpu，还好有雅黑，虽然不是那么纯粹的linux主义，但总算让自己的眼睛舒服了很多。 Anyway,尽管大家对于ubuntu有各种各样的争议，我觉得我们都应该感谢ubuntu在linux桌面化做出的努力。 顺便期待一下ubuntu 8.04的正式版。 当然，我还是要抱怨一下，ubuntu那黄色的主题真是难看，而且我安装其它主题总是费了很大劲还是不能彻底地去掉那些黄色。]]></description>
			<content:encoded><![CDATA[<p>在ubuntu 8.04中，正式引入了wubi这种全新的安装方式。对于我的破笔记本来说简直就是一种福音啊。<br />
之前装linux&amp;xp双系统，带来的结果就是两次分区表出错，差点硬盘废了。第二次出错时我就很坚决地把linux分区格式化了。<br />
于是在wubi下安装了ubuntu.</p>
<p>总的来说，这种安装方式还是很不错的，不用分区，不用搞那些乱七八糟的引导，像装个应用程序那么简单。<br />
实际运行的性能，没感觉到有太大的损失，或许我这种普通的应用感觉不出性能，又或许我的破笔记本没有性能可言。</p>
<p>Linux下比较大的问题就是中文字体的问题，wqy字体渲染太耗cpu，还好有雅黑，虽然不是那么纯粹的linux主义，但总算让自己的眼睛舒服了很多。</p>
<p>Anyway,尽管大家对于ubuntu有各种各样的争议，我觉得我们都应该感谢ubuntu在linux桌面化做出的努力。</p>
<p>顺便期待一下ubuntu 8.04的正式版。</p>
<p>当然，我还是要抱怨一下，ubuntu那黄色的主题真是难看，而且我安装其它主题总是费了很大劲还是不能彻底地去掉那些黄色。</p>
]]></content:encoded>
			<wfw:commentRss>http://litblue.net/p/885/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>记录linux用户的操作记录</title>
		<link>http://litblue.net/p/881</link>
		<comments>http://litblue.net/p/881#comments</comments>
		<pubDate>Fri, 28 Mar 2008 13:54:52 +0000</pubDate>
		<dc:creator>blues</dc:creator>
				<category><![CDATA[技术相关]]></category>

		<guid isPermaLink="false">http://litblue.net/?p=442</guid>
		<description><![CDATA[当很多人共同管理一批服务器的时候 当大家都有权限的时候 头疼的问题来了 人员素质参差不齐 到底是谁的误操作导致了系统故障呢? 我们需要操作记录 但尽管我们给每个人分配了用户 但进行的一个系统管理操作都会切换到root用户进行 光看history显然不行 而且更为糟糕的是history是一个极易删除的东西 如果你有这样的烦恼 那么下面的方法或许适合你 script可以录制屏幕 你可以自己写一个脚本使用script来录制屏幕并生成对应的文件最后输出到一个只有少数人有权限的服务器上 然后在/etc/bash.bashrc里加载这个脚本 这样就实现了每个用户只要登录 屏幕信息就被记录 当然如果你仔细去推敲的话你会发现这种方法只能防君子不能防小人 呵呵]]></description>
			<content:encoded><![CDATA[<p>当很多人共同管理一批服务器的时候<br />
当大家都有权限的时候<br />
头疼的问题来了<br />
人员素质参差不齐<br />
到底是谁的误操作导致了系统故障呢?</p>
<p>我们需要操作记录<br />
但尽管我们给每个人分配了用户<br />
但进行的一个系统管理操作都会切换到root用户进行<br />
光看history显然不行<br />
而且更为糟糕的是history是一个极易删除的东西</p>
<p>如果你有这样的烦恼<br />
那么下面的方法或许适合你</p>
<p>script可以录制屏幕<br />
你可以自己写一个脚本使用script来录制屏幕并生成对应的文件最后输出到一个只有少数人有权限的服务器上<br />
然后在/etc/bash.bashrc里加载这个脚本<br />
这样就实现了每个用户只要登录<br />
屏幕信息就被记录</p>
<p>当然如果你仔细去推敲的话你会发现这种方法只能防君子不能防小人<br />
呵呵</p>
]]></content:encoded>
			<wfw:commentRss>http://litblue.net/p/881/feed</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>vmware各版本区别</title>
		<link>http://litblue.net/p/879</link>
		<comments>http://litblue.net/p/879#comments</comments>
		<pubDate>Sun, 23 Mar 2008 06:13:16 +0000</pubDate>
		<dc:creator>blues</dc:creator>
				<category><![CDATA[技术相关]]></category>

		<guid isPermaLink="false">http://litblue.net/?p=439</guid>
		<description><![CDATA[一直使用vmware workstation,对于其它版本不甚了解. 在vmware server免费推出的时候,曾经试过一次,但当时的环境让我觉得远程管理方式多此一举,不如使用vmware workstation来得方便. 近来需要在托管在IDC的服务器上安装wmware,vmware workstation版本的局限性就暴露出来了,我使用ssh连接上我的服务器,根本不可能完成安装任务. 于是了解了一下vmware三个版本的区别,简述如下: 1. vmware workstation,看名字就知道他是一个适合于单机工作站的版本.他的虚拟子系统的安装必须在宿主系统里完成.vmware server (前身为vmware gsx server)则主要改进了远程控制方面,适用于工作组.他的子系统安装和控制都可以远程进行.而vmware esx server则是企业级的虚拟化解决方案,功能也是最强大,性能也是最好的. 2.vmware workstation和vmware server都可以认为是一个应用程序,他需要安装于一个宿主系统.而vmware esx server我们可以认为他本身就是一个操作系统,他直接安装于裸机,子系统运行于vmware esx server之上.这就不难理解vmware esx server为什么性能是最高了,但同时他也会要求你的硬件足够强大. 3.vmware server 是免费的,可以到官方网站上申请序列号. vmware esx server则需要高昂的费用方可使用. 就是这么简单!]]></description>
			<content:encoded><![CDATA[<p>一直使用vmware workstation,对于其它版本不甚了解.<br />
在vmware server免费推出的时候,曾经试过一次,但当时的环境让我觉得远程管理方式多此一举,不如使用vmware workstation来得方便.<br />
近来需要在托管在IDC的服务器上安装wmware,vmware workstation版本的局限性就暴露出来了,我使用ssh连接上我的服务器,根本不可能完成安装任务.<br />
于是了解了一下vmware三个版本的区别,简述如下:</p>
<p>1. vmware workstation,看名字就知道他是一个适合于单机工作站的版本.他的虚拟子系统的安装必须在宿主系统里完成.vmware server (前身为vmware gsx server)则主要改进了远程控制方面,适用于工作组.他的子系统安装和控制都可以远程进行.而vmware esx server则是企业级的虚拟化解决方案,功能也是最强大,性能也是最好的.</p>
<p>2.vmware workstation和vmware server都可以认为是一个应用程序,他需要安装于一个宿主系统.而vmware esx server我们可以认为他本身就是一个操作系统,他直接安装于裸机,子系统运行于vmware esx server之上.这就不难理解vmware esx server为什么性能是最高了,但同时他也会要求你的硬件足够强大.</p>
<p>3.vmware server 是免费的,可以到官方网站上申请序列号. vmware esx server则需要高昂的费用方可使用.</p>
<p>就是这么简单!</p>
]]></content:encoded>
			<wfw:commentRss>http://litblue.net/p/879/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>kickstart安装redhat</title>
		<link>http://litblue.net/p/874</link>
		<comments>http://litblue.net/p/874#comments</comments>
		<pubDate>Fri, 07 Mar 2008 14:41:40 +0000</pubDate>
		<dc:creator>blues</dc:creator>
				<category><![CDATA[技术相关]]></category>

		<guid isPermaLink="false">http://litblue.net/?p=434</guid>
		<description><![CDATA[工作中需要经常安装linux系统，为了安装过程遵循统一的标准 ，查看了一些无人值守安装的方法。总结如下： 关键字：无人值守 linux安装 方法：使用kickstart 建立ks.cfg,然后安装时使用linux ks=XXX:/ks.cfg  尽情发挥你的想象力，XXX处使用你想用的媒体。]]></description>
			<content:encoded><![CDATA[<p>工作中需要经常安装linux系统，为了安装过程遵循统一的标准 ，查看了一些无人值守安装的方法。总结如下：</p>
<p>关键字：无人值守 linux安装</p>
<p>方法：使用kickstart 建立ks.cfg,然后安装时使用linux ks=XXX:/ks.cfg </p>
<p>尽情发挥你的想象力，XXX处使用你想用的媒体。</p>
]]></content:encoded>
			<wfw:commentRss>http://litblue.net/p/874/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>[转载]Expect基本用法</title>
		<link>http://litblue.net/p/873</link>
		<comments>http://litblue.net/p/873#comments</comments>
		<pubDate>Wed, 05 Mar 2008 08:27:24 +0000</pubDate>
		<dc:creator>blues</dc:creator>
				<category><![CDATA[技术相关]]></category>

		<guid isPermaLink="false">http://litblue.net/?p=433</guid>
		<description><![CDATA[一、概述 我们通过Shell可以实现简单的控制流功能，如：循环、判断等。但是对于需要交互的场合则必须通过人工来干预，有时候我们可能会需要实现和交互程序如telnet服务器等进行交互的功能。而Expect就使用来实现这种功能的工具。 Expect是一个免费的编程工具语言，用来实现自动和交互式任务进行通信，而无需人的干预。Expect的作者Don Libes在1990年开始编写Expect时对Expect做有如下定义：Expect是一个用来实现自动交互功能的软件套件(Expect [is a] software suite for automating interactive tools)。使用它系统管理员的可以创建脚本用来实现对命令或程序提供输入，而这些命令和程序是期望从终端（terminal）得到输入，一般来说这些输入都需要手工输入进行的。Expect则可以根据程序的提示模拟标准输入提供给程序需要的输入来实现交互程序执行。甚至可以实现实现简单的BBS聊天机器人。 Expect是不断发展的，随着时间的流逝，其功能越来越强大，已经成为系统管理员的的一个强大助手。Expect需要Tcl编程语言的支持，要在系统上运行Expect必须首先安装Tcl。 二、Expect工作原理 从最简单的层次来说，Expect的工作方式象一个通用化的Chat脚本工具。Chat脚本最早用于UUCP网络内，以用来实现计算机之间需要建立连接时进行特定的登录会话的自动化。 Chat脚本由一系列expect-send对组成：expect等待输出中输出特定的字符，通常是一个提示符，然后发送特定的响应。例如下面的Chat脚本实现等待标准输出出现Login:字符串，然后发送somebody作为用户名；然后等待Password:提示符，并发出响应sillyme。 QUOTE: Login: somebody Password: sillyme 这个脚本用来实现一个登录过程，并用特定的用户名和密码实现登录。 Expect最简单的脚本操作模式本质上和Chat脚本工作模式是一样的。 例子： 1、实现功能 下面我们分析一个响应chsh命令的脚本。我们首先回顾一下这个交互命令的格式。假设我们要为用户chavez改变登录脚本，要求实现的命令交互过程如下： QUOTE: # chsh chavez Changing the login shell for chavez Enter the new value, or press return for the default Login Shell [/bin/bash]: /bin/tcsh # 可以看到该命令首先输出若干行提示信息并且提示输入用户新的登录shell。我们必须在提示信息后面输入用户的登录shell或者直接回车不修改登录shell。 2、下面是一个能用来实现自动执行该命令的Expect脚本： [Copy to [...]]]></description>
			<content:encoded><![CDATA[<p>一、概述</p>
<p>我们通过Shell可以实现简单的控制流功能，如：循环、判断等。但是对于需要交互的场合则必须通过人工来干预，有时候我们可能会需要实现和交互程序如telnet服务器等进行交互的功能。而Expect就使用来实现这种功能的工具。</p>
<p>Expect是一个免费的编程工具语言，用来实现自动和交互式任务进行通信，而无需人的干预。Expect的作者Don Libes在1990年开始编写Expect时对Expect做有如下定义：Expect是一个用来实现自动交互功能的软件套件(Expect [is a] software suite for automating interactive tools)。使用它系统管理员的可以创建脚本用来实现对命令或程序提供输入，而这些命令和程序是期望从终端（terminal）得到输入，一般来说这些输入都需要手工输入进行的。Expect则可以根据程序的提示模拟标准输入提供给程序需要的输入来实现交互程序执行。甚至可以实现实现简单的BBS聊天机器人。 <img src='http://litblue.net/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
<p>Expect是不断发展的，随着时间的流逝，其功能越来越强大，已经成为系统管理员的的一个强大助手。Expect需要Tcl编程语言的支持，要在系统上运行Expect必须首先安装Tcl。<br />
<span id="more-873"></span><br />
二、Expect工作原理</p>
<p>从最简单的层次来说，Expect的工作方式象一个通用化的Chat脚本工具。Chat脚本最早用于UUCP网络内，以用来实现计算机之间需要建立连接时进行特定的登录会话的自动化。</p>
<p>Chat脚本由一系列expect-send对组成：expect等待输出中输出特定的字符，通常是一个提示符，然后发送特定的响应。例如下面的Chat脚本实现等待标准输出出现Login:字符串，然后发送somebody作为用户名；然后等待Password:提示符，并发出响应sillyme。</p>
<p>QUOTE:<br />
Login: somebody Password: sillyme<br />
这个脚本用来实现一个登录过程，并用特定的用户名和密码实现登录。</p>
<p>Expect最简单的脚本操作模式本质上和Chat脚本工作模式是一样的。</p>
<p>例子：<br />
1、实现功能<br />
下面我们分析一个响应chsh命令的脚本。我们首先回顾一下这个交互命令的格式。假设我们要为用户chavez改变登录脚本，要求实现的命令交互过程如下：</p>
<p>QUOTE:<br />
# chsh chavez<br />
Changing the login shell for chavez<br />
Enter the new value, or press return for the default<br />
Login Shell [/bin/bash]: /bin/tcsh<br />
#<br />
可以看到该命令首先输出若干行提示信息并且提示输入用户新的登录shell。我们必须在提示信息后面输入用户的登录shell或者直接回车不修改登录shell。</p>
<p>2、下面是一个能用来实现自动执行该命令的Expect脚本：</p>
<p>[Copy to clipboard] [ - ]CODE:<br />
#!/usr/bin/expect<br />
# Change a login shell to tcsh</p>
<p>set user [lindex $argv 0]<br />
spawn chsh $user<br />
expect &#8220;]:&#8221;<br />
send &#8220;/bin/tcsh &#8221;<br />
expect eof<br />
exit<br />
这个简单的脚本可以解释很多Expect程序的特性。和其他脚本一样首行指定用来执行该脚本的命令程序，这里是/usr/bin/expect。程序第一行用来获得脚本的执行参数(其保存在数组$argv中，从0号开始是参数)，并将其保存到变量user中。</p>
<p>第二个参数使用Expect的spawn命令来启动脚本和命令的会话，这里启动的是chsh命令，实际上命令是以衍生子进程的方式来运行的。</p>
<p>随后的expect和send命令用来实现交互过程。脚本首先等待输出中出现]:字符串，一旦在输出中出现chsh输出到的特征字符串(一般特征字符串往往是等待输入的最后的提示符的特征信息)。对于其他不匹配的信息则会完全忽略。当脚本得到特征字符串时，expect将发送/bin/tcsh和一个回车符给chsh命令。最后脚本等待命令退出(chsh结束)，一旦接收到标识子进程已经结束的eof字符，expect脚本也就退出结束。</p>
<p>3、决定如何响应</p>
<p>管理员往往有这样的需求，希望根据当前的具体情况来以不同的方式对一个命令进行响应。我们可以通过后面的例子看到expect可以实现非常复杂的条件响应，而仅仅通过简单的修改预处理脚本就可以实现。下面的例子是一个更复杂的expect-send例子：</p>
<p>[Copy to clipboard] [ - ]CODE:<br />
expect -re &#8220;\[(.*)]:&#8221;<br />
if {$expect_out(1,string)!=&#8221;/bin/tcsh&#8221;} {<br />
send &#8220;/bin/tcsh&#8221; }<br />
send &#8221; &#8221;<br />
expect eof<br />
在这个例子中，第一个expect命令现在使用了-re参数，这个参数表示指定的的字符串是一个正则表达式，而不是一个普通的字符串。对于上面这个例子里是查找一个左方括号字符(其必须进行三次逃逸(escape)，因此有三个符号，因为它对于expect和正则表达时来说都是特殊字符)后面跟有零个或多个字符，最后是一个右方括号字符。这里.*表示表示一个或多个任意字符，将其存放在()中是因为将匹配结果存放在一个变量中以实现随后的对匹配结果的访问。</p>
<p>当发现一个匹配则检查包含在[]中的字符串，查看是否为/bin/tcsh。如果不是则发送/bin/tcsh给chsh命令作为输入，如果是则仅仅发送一个回车符。这个简单的针对具体情况发出不同相响应的小例子说明了expect的强大功能。</p>
<p>在一个正则表达时中，可以在()中包含若干个部分并通过expect_out数组访问它们。各个部分在表达式中从左到右进行编码，从1开始(0包含有整个匹配输出)。()可能会出现嵌套情况，这这种情况下编码从最内层到最外层来进行的。</p>
<p>4、使用超时</p>
<p>下一个expect例子中将阐述具有超时功能的提示符函数。这个脚本提示用户输入，如果在给定的时间内没有输入，则会超时并返回一个默认的响应。这个脚本接收三个参数：提示符字串，默认响应和超时时间(秒)。</p>
<p>[Copy to clipboard] [ - ]CODE:<br />
#!/usr/bin/expect<br />
# Prompt function with timeout and default.<br />
set prompt [lindex $argv 0]<br />
set def [lindex $argv 1]<br />
set response $def<br />
set tout [lindex $argv 2]<br />
脚本的第一部分首先是得到运行参数并将其保存到内部变量中。</p>
<p>[Copy to clipboard] [ - ]CODE:<br />
send_tty &#8220;$prompt: &#8221;<br />
set timeout $tout<br />
expect &#8221; &#8221; {<br />
set raw $expect_out(buffer)<br />
# remove final carriage return<br />
set response [string trimright "$raw" " "]<br />
}<br />
if {&#8220;$response&#8221; == &#8220;} {set response $def}<br />
send &#8220;$response &#8221;<br />
# Prompt function with timeout and default.<br />
set prompt [lindex $argv 0]<br />
set def [lindex $argv 1]<br />
set response $def<br />
set tout [lindex $argv 2]<br />
这是脚本其余的内容。可以看到send_tty命令用来实现在终端上显示提示符字串和一个冒号及空格。set timeout命令设置后面所有的expect命令的等待响应的超时时间为$tout(-l参数用来关闭任何超时设置)。</p>
<p>然后expect命令就等待输出中出现回车字符。如果在超时之前得到回车符，那么set命令就会将用户输入的内容赋值给变脸raw。随后的命令将用户输入内容最后的回车符号去除以后赋值给变量response。</p>
<p>然后，如果response中内容为空则将response值置为默认值(如果用户在超时以后没有输入或者用户仅仅输入了回车符)。最后send命令将response变量的值加上回车符发送给标准输出。</p>
<p>一个有趣的事情是该脚本没有使用spawn命令。 该expect脚本会与任何调用该脚本的进程交互。</p>
<p>如果该脚本名为prompt，那么它可以用在任何C风格的shell中。</p>
<p>% set a=&#8217;prompt &#8220;Enter an answer&#8221; silence 10&#8242;<br />
Enter an answer: test</p>
<p>% echo Answer was &#8220;$a&#8221;<br />
Answer was test<br />
prompt设定的超时为10秒。如果超时或者用户仅仅输入了回车符号，echo命令将输出</p>
<p>Answer was &#8220;silence&#8221;</p>
<p>5、一个更复杂的例子</p>
<p>下面我们将讨论一个更加复杂的expect脚本例子，这个脚本使用了一些更复杂的控制结构和很多复杂的交互过程。这个例子用来实现发送write命令给任意的用户，发送的消息来自于一个文件或者来自于键盘输入。</p>
<p>[Copy to clipboard] [ - ]CODE:<br />
#!/usr/bin/expect<br />
# Write to multiple users from a prepared file<br />
# or a message input interactively</p>
<p>if {$argc&lt;2} {<br />
send_user &#8220;usage: $argv0 file user1 user2 &#8230; &#8221;<br />
exit<br />
}<br />
send_user命令用来显示使用帮助信息到父进程(一般为用户的shell)的标准输出。</p>
<p>[Copy to clipboard] [ - ]CODE:<br />
set nofile 0<br />
# get filename via the Tcl lindex function<br />
set file [lindex $argv 0]<br />
if {$file==&#8221;i&#8221;} {<br />
set nofile 1<br />
} else {<br />
# make sure message file exists<br />
if {[file isfile $file]!=1} {<br />
send_user &#8220;$argv0: file $file not found. &#8221;<br />
exit }}<br />
这部分实现处理脚本启动参数，其必须是一个储存要发送的消息的文件名或表示使用交互输入得到发送消的内容的&#8221;i&#8221;命令。</p>
<p>变量file被设置为脚本的第一个参数的值，是通过一个Tcl函数lindex来实现的，该函数从列表/数组得到一个特定的元素。[]用来实现将函数lindex的返回值作为set命令的参数。</p>
<p>如果脚本的第一个参数是小写的&#8221;i&#8221;，那么变量nofile被设置为1，否则通过调用Tcl的函数isfile来验证参数指定的文件存在，如果不存在就报错退出。</p>
<p>可以看到这里使用了if命令来实现逻辑判断功能。该命令后面直接跟判断条件，并且执行在判断条件后的{}内的命令。if条件为false时则运行else后的程序块。</p>
<p>[Copy to clipboard] [ - ]CODE:<br />
set procs {}<br />
# start write processes<br />
for {set i 1} {$i&lt;$argc}<br />
{incr i} {<br />
spawn -noecho write<br />
[lindex $argv $i]<br />
lappend procs $spawn_id<br />
}<br />
最后一部分使用spawn命令来启动write进程实现向用户发送消息。这里使用了for命令来实现循环控制功能，循环变量首先设置为1，然后因此递增。循环体是最后的{}的内容。这里我们是用脚本的第二个和随后的参数来spawn一个write命令，并将每个参数作为发送消息的用户名。lappend命令使用保存每个spawn的进程的进程ID号的内部变量$spawn_id在变量procs中构造了一个进程ID号列表。</p>
<p>[Copy to clipboard] [ - ]CODE:<br />
if {$nofile==0} {<br />
setmesg [open "$file" "r"]<br />
} else {<br />
send_user &#8220;enter message,<br />
ending with ^D: &#8221; }<br />
最后脚本根据变量nofile的值实现打开消息文件或者提示用户输入要发送的消息。</p>
<p>[Copy to clipboard] [ - ]CODE:<br />
set timeout -1<br />
while 1 {<br />
if {$nofile==0} {<br />
if {[gets $mesg chars] == -1} break<br />
set line &#8220;$chars &#8221;<br />
} else {<br />
expect_user {<br />
-re &#8221; &#8221; {}<br />
eof break }<br />
set line $expect_out(buffer) }</p>
<p>foreach spawn_id $procs {<br />
send $line }<br />
sleep 1}<br />
exit<br />
上面这段代码说明了实际的消息文本是如何通过无限循环while被发送的。while循环中的 if判断消息是如何得到的。在非交互模式下，下一行内容从消息文件中读出，当文件内容结束时while循环也就结束了。(break命令实现终止循环) 。</p>
<p>在交互模式下，expect_user命令从用户接收消息，当用户输入ctrl+D时结束输入，循环同时结束。 两种情况下变量$line都被用来保存下一行消息内容。当是消息文件时，回车会被附加到消息的尾部。</p>
<p>foreach循环遍历spawn的所有进程，这些进程的ID号都保存在列表变量$procs中，实现分别和各个进程通信。send命令组成了foreach的循环体，发送一行消息到当前的write进程。while循环的最后是一个sleep命令，主要是用于处理非交互模式情况下，以确保消息不会太快的发送给各个write进程。当while循环退出时，expect脚本结束。</p>
<p>三、参考资源</p>
<p>Expect软件版本深带有很多例子脚本，不但可以用于学习和理解expect脚本，而且是非常使用的工具。一般可以在/usr/doc/packages/expect/example看到它们，在某些linux发布中有些expect脚本保存在/usr/bin目录下。</p>
<p>Don Libes, Exploring Expect, O&#8217;Reilly &amp; Associates, 1995.</p>
<p>John Ousterhout, Tcl and the Tk Toolkit, Addison-Wesley, 1994.</p>
<p>一些有用的expect脚本</p>
<p>autoexpect:这个脚本将根据自身在运行时用户的操作而生成一个expect脚本。它的功能某种程度上类似于在Emacs编辑器的键盘宏工具。一个自动创建的脚本可能是创建自己定制脚本的好的开始。</p>
<p>kibitz:这是一个非常有用的工具。通过它两个或更多的用户可以连接到同一个shell进程。</p>
<p>tkpasswd: 这个脚本提供了修改用户密码的GUI工具，包括可以检查密码是否是基于字典模式。这个工具同时是一个学习expect和tk的好实例。</p>
<p>另附：</p>
<p>QUOTE:<br />
创建时间：2001-04-29<br />
文章属性：转载<br />
文章来源：中国科大BBS站<br />
文章提交：quack (quack_at_xfocus.org)</p>
<p>[版权声明]<br />
　　<br />
　　Copyright(c) 1999<br />
　　　　<br />
　　本教程由*葫芦娃*翻译，并做了适当的修改，可以自由的用于非商业目的。<br />
　　但Redistribution时必须拷贝本[版权声明]。　　　　　　</p>
<p>[BUG]</p>
<p>　　有不少部分，翻译的时候不能作到“信，达”。当然了，任何时候都没有做到“雅”，希望各位谅解。</p>
<p>[原著]<br />
　<br />
　　Don Libes: National Institute of Standards and Technology<br />
　　　　libes@cme.nist.gov</p>
<p>[目录]<br />
　　<br />
　　1.摘要<br />
　　2.关键字<br />
　　3.简介<br />
　　4.Expect综述<br />
　　5.callback<br />
　　6.passwd 和一致性检查<br />
　　7.rogue 和伪终端<br />
　　8.ftp<br />
　　9.fsck<br />
　　10.多进程控制：作业控制<br />
　　11.交互式使用Expect<br />
　　12.交互式Expect编程<br />
　　13.非交互式程序的控制<br />
　　14.Expect的速度<br />
　　15.安全方面的考虑<br />
　　16.Expect资源<br />
　　17.参考书籍</p>
<p>1.[摘要]</p>
<p>　 现代的Shell对程序提供了最小限度的控制(开始，停止，等等)，而把交互的特性留给了用户。 这意味着有些程序，你不能非交互的运行，比如说passwd。 有一些程序可以非交互的运行，但在很大程度上丧失了灵活性，比如说fsck。这表明Unix的工具构造逻辑开始出现问题。Expect恰恰填补了其中的一些裂痕，解决了在Unix环境中长期存在着的一些问题。</p>
<p>　 Expect使用Tcl作为语言核心。不仅如此，不管程序是交互和还是非交互的，Expect都能运用。这是一个小语言和Unix的其他工具配合起来产生强大功能的经典例子。<br />
　<br />
　 本部分教程并不是有关Expect的实现，而是关于Expect语言本身的使用，这主要也是通过不同的脚本描述例子来体现。其中的几个例子还例证了Expect的几个新特征。<br />
　<br />
2.[关键字]<br />
　　<br />
　　Expect,交互，POSIX,程序化的对话，Shell,Tcl,Unix;</p>
<p>3.[简介]<br />
　<br />
　　一个叫做fsck的Unix文件系统检查程序，可以从Shell里面用-y或者-n选项来执行。　在手册[1]里面，-y选项的定义是象这样的。</p>
<p>　　“对于fsck的所有问题都假定一个“yes”响应；在这样使用的时候，必须特别的小心，因为它实际上允许程序无条件的继续运行，即使是遇到了一些非常严重的错误”<br />
　　<br />
　　相比之下，-n选项就安全的多，但它实际上几乎一点用都没有。这种接口非常的糟糕，但是却有许多的程序都是这种风格。　文件传输程序ftp有一个选项可以禁止交互式的提问，以便能从一个脚本里面运行。但一旦发生了错误，它没有提供的处理措施。</p>
<p>　　Expect是一个控制交互式程序的工具。他解决了fsck的问题，用非交互的方式实现了所有交互式的功能。Expect不是特别为fsck设计的，它也能进行类似ftp的出错处理。</p>
<p>　　fsck和ftp的问题向我们展示了象sh,csh和别的一些shell提供的用户接口的局限性。　Shell没有提供从一个程序读和象一个程序写的功能。这意味着shell可以运行fsck但只能以牺牲一部分fsck的灵活性做代价。有一些程序根本就不能被执行。比如说，如果没有一个用户接口交互式的提供输入，就没法运行下去。其他还有象Telnet,crypt,su,rlogin等程序无法在shell脚本里面自动执行。还有很多其他的应用程序在设计是也是要求用户输入的。</p>
<p>　　Expect被设计成专门针和交互式程序的交互。一个Expect程序员可以写一个脚本来描述程序和用户的对话。接着Expect程序可以非交互的运行“交互式”的程序。写交互式程序的脚本和写非交互式程序的脚本一样简单。Expect还可以用于对对话的一部分进行自动化，因为程序的控制可以在键盘和脚本之间进行切换。</p>
<p>bes[2]里面有详细的描述。简单的说，脚本是用一种解释性语言写的。(也有C和C++的Expect库可供使用，但这超出了本文的范围).Expect提供了创建交互式进程和读写它们的输入和输出的命令。　Expect是由于它的一个同名的命令而命名的。</p>
<p>　　Expect语言是基于Tcl的。Tcl实际上是一个子程序库，这些子程序库可以嵌入到程序里从而提供语言服务。　最终的语言有点象一个典型的Shell语言。里面有给变量赋值的set命令，控制程序执行的if,for,continue等命令，还能进行普通的数学和字符串操作。当然了，还可以用exec来调用Unix程序。所有这些功能，Tcl都有。Tcl在参考书籍 Outerhour[3][4]里有详细的描述。</p>
<p>　　Expect是在Tcl基础上创建起来的，它还提供了一些Tcl所没有的命令。spawn命令激活一个Unix程序来进行交互式的运行。　send命令向进程发送字符串。expect命令等待进程的某些字符串。　expect支持正规表达式并能同时等待多个字符串，并对每一个字符串执行不同的操作。expect还能理解一些特殊情况，如超时和遇到文件尾。</p>
<p>　　expect命令和Tcl的case命令的风格很相似。都是用一个字符串去匹配多个字符串。(只要有可能，新的命令总是和已有的Tcl命令相似，以使得该语言保持工具族的继承性)。下面关于expect的定义是从手册[5]上摘录下来的。</p>
<p>　　　　　　expect　patlist1 action1 patlist2 action2&#8230;..</p>
<p>　　　　该命令一直等到当前进程的输出和以上的某一个模式相匹配，或者等　　　　到时间超过一个特定的时间长度，或者等到遇到了文件的结束为止。<br />
　　　　<br />
　　　　如果最后一个action是空的，就可以省略它。</p>
<p>　　　　每一个patlist都由一个模式或者模式的表(lists)组成。如果有一个模式匹配成功，相应的action就被执行。执行的结果从expect返回。<br />
　　　　被精确匹配的字符串(或者当超时发生时，已经读取但未进行匹配的字符串)被存贮在变量expect_match里面。如果patlist是eof或者timeout,则发生文件结束或者超时时才执行相应的action.一般超时的时值是10秒，但可以用类似&#8221;set timeout 30&#8243;之类的命令把超时时值设定为30秒。<br />
　　　　<br />
　　　　下面的一个程序段是从一个有关登录的脚本里面摘取的。abort是在脚本的别处定义的过程，而其他的action使用类似与C语言的Tcl原语。</p>
<p>　　　　　　expect &#8220;*welcome*&#8221;　　　　　　　　break 　　　　<br />
　　　　　　　　　　 &#8220;*busy*&#8221;　　　　　　　　{print busy;continue}<br />
　　　　　　　　　 &#8220;*failed*&#8221;　　　　　　　　abort　<br />
　　　　　　　　　 timeout　　　　　　　　abort</p>
<p>　　　　模式是通常的C Shell风格的正规表达式。模式必须匹配当前进程的从上一个expect或者interact开始的所有输出(所以统配符*使用的非常)的普遍。但是，一旦输出超过2000个字节，前面的字符就会被忘记，这可以通过设定match_max的值来改变。</p>
<p>　　expect命令确实体现了expect语言的最好和最坏的性质。特别是，expect命令的灵活性是以经常出现令人迷惑的语法做代价。除了关键字模式(比如说eof,timeout)那些模式表可以包括多个模式。这保证提供了一种方法来区分他们。但是分开这些表需要额外的扫描，如果没有恰当的用["]括起来，这有可能会把和当成空白字符。由于Tcl提供了两种字符串引用的方法：单引和双引，情况变的更糟。(在Tcl里面，如果不会出现二义性话，没有必要使用引号)。在expect的手册里面，还有一个独立的部分来解释这种复杂性。幸运的是：有一些很好的例子似乎阻止了这种抱怨。但是，这个复杂性很有可能在将来的版本中再度出现。为了增强可读性，在本文中，提供的脚本都假定双引号是足够的。</p>
<p>　　字符可以使用反斜杠来单独的引用，反斜杠也被用于对语句的延续，如果不加反斜杠的话，语句到一行的结尾处就结束了。这和Tcl也是一致的。Tcl在发现有开的单引号或者开的双引号时都会继续扫描。而且，分号可以用于在一行中分割多个语句。这乍听起来有点让人困惑，但是，这是解释性语言的风格，但是，这确实是Tcl的不太漂亮的部分。</p>
<p>5.[callback]</p>
<p>　　令人非常惊讶的是，一些小的脚本如何的产生一些有用的功能。下面是一个拨电话号码的脚本。他用来把收费反向，以便使得长途电话对计算机计费。这个脚本用类似“expect callback.exp 12016442332”来激活。其中，脚本的名字便是callback.exp，而+1(201)644-2332是要拨的电话号码。</p>
<p>　　　　#first give the user some time to logout<br />
　　　　exec sleep 4<br />
　　　　spawn tip modem<br />
　　　　expect &#8220;*connected*&#8221;<br />
　　　　send &#8220;ATD [llindex $argv 1] &#8221;<br />
　　　　#modem takes a while to connect<br />
　　　　set timeout 60<br />
　　　　expect &#8220;*CONNECT*&#8221;</p>
<p>　　第一行是注释，第二行展示了如何调用没有交互的Unix程序。sleep 4会使程序阻塞4秒，以使得用户有时间来退出，因为modem总是会回叫用户已经使用的电话号码。</p>
<p>　　下面一行使用spawn命令来激活tip程序，以便使得tip的输出能够被expect所读取，使得tip能从send读输入。一旦tip说它已经连接上，modem就会要求去拨打大哥电话号码。(假定modem都是贺氏兼容的，但是本脚本可以很容易的修改成能适应别的类型的modem)。不论发生了什么，expect都会终止。如果呼叫失败，expect脚本可以设计成进行重试，但这里没有。如果呼叫成功，getty会在expect退出后检测到DTR，并且向用户提示loging:。(实用的脚本往往提供更多的错误检测)。</p>
<p>　　这个脚本展示了命令行参数的使用，命令行参数存贮在一个叫做argv的表里面(这和C语言的风格很象)。在这种情况下，第一个元素就是电话号码。方括号使得被括起来的部分当作命令来执行，结果就替换被括起来的部分。这也和C Shell的风格很象。</p>
<p>　　这个脚本和一个大约60K的C语言程序实现的功能相似。<br />
　　　　</p>
<p>6.[passwd和一致性检查]</p>
<p>　　在前面，我们提到passwd程序在缺乏用户交互的情况下，不能运行，passwd会忽略I/O重定向，也不能嵌入到管道里边以便能从别的程序或者文件里读取输入。这个程序坚持要求真正的与用户进行交互。因为安全的原因，passwd被设计成这样，但结果导致没有非交互式的方法来检验passwd。这样一个对系统安全至关重要的程序竟然没有办法进行可靠的检验，真实具有讽刺意味。</p>
<p>　　passwd以一个用户名作为参数，交互式的提示输入密码。下面的expect脚本以用户名和密码作为参数而非交互式的运行。</p>
<p>　　　　spawn oasswd [lindex $argv 1]<br />
　　　　set password [lindex $argv 2]<br />
　　　　expect &#8220;*password:&#8221;<br />
　　　　send &#8220;$password &#8221;<br />
　　　　expect &#8220;*password:&#8221;<br />
　　　　send &#8220;$password &#8221;<br />
　　　　expect eof</p>
<p>　　第一行以用户名做参数启动passwd程序，为方便起见，第二行把密码存到一个变量里面。和shell类似，变量的使用也不需要提前声明。</p>
<p>　　在第三行，expect搜索模式&#8221;*password:&#8221;，其中*允许匹配任意输入，所以对于避免指定所有细节而言是非常有效的。 上面的程序里没有action,所以expect检测到该模式后就继续运行。</p>
<p>　　一旦接收到提示后，下一行就就把密码送给当前进程。表明回车。(实际上，所有的C的关于字符的约定都支持)。上面的程序中有两个expect-send序列，因为passwd为了对输入进行确认，要求进行两次输入。在非交互式程序里面，这是毫无必要的，但由于假定passwd是在和用户进行交互，所以我们的脚本还是这样做了。</p>
<p>　　最后，&#8221;expect eof&#8221;这一行的作用是在passwd的输出中搜索文件结束符，这一行语句还展示了关键字的匹配。另外一个关键字匹配就是timeout了，timeout被用于表示所有匹配的失败而和一段特定长度的时间相匹配。在这里eof是非常有必要的，因为passwd被设计成会检查它的所有I/O是否都成功了，包括第二次输入密码时产生的最后一个新行。</p>
<p>　　这个脚本已经足够展示passwd命令的基本交互性。另外一个更加完备的例子回检查别的一些行为。比如说，下面的这个脚本就能检查passwd程序的别的几个方面。所有的提示都进行了检查。对垃圾输入的检查也进行了适当的处理。进程死亡，超乎寻常的慢响应，或者别的非预期的行为都进行了处理。</p>
<p>　　　　spawn passwd [lindex $argv 1]<br />
　　　　expect 　　　　eof　　　　　　　　　　　　{exit 1} 　　　　<br />
　　　　　　　　timeout　　　　　　　　　　　　{exit 2}　　　　<br />
　　　　　　　　&#8221;*No such user.*&#8221;　　　　{exit 3}　　　　<br />
　　　　　　　　&#8221;*New password:&#8221;　　　　<br />
　　　　send　&#8221;[lindex $argv 2 "<br />
　　　　expect 　　　　eof　　　　　　　　　　　　{exit 4}　　　　<br />
　　　　　　　　timeout　　　　　　　　　　　　{exit 2}　　　　<br />
　　　　　　　　"*Password too long*"　　　　{exit 5}　　　　<br />
　　　　　　　　"*Password too short*"　　　　{exit 5}　　　　<br />
　　　　　　　　"*Retype ew password:"<br />
　　　　send "[lindex $argv 3] &#8221;<br />
　　　　expect 　　　　timeout　　　　　　　　　　　　{exit 2}　　　　<br />
　　　　　　　　&#8221;*Mismatch*&#8221;　　　　　　　　{exit 6}　　　　<br />
　　　　　　　　&#8221;*Password unchanged*&#8221;　　　　{exit 7}　　　　<br />
　　　　　　　　&#8221; &#8220;　　　　　　　　<br />
　　　　expect　　　　timeout　　　　　　　　　　　　{exit 2}　　　　<br />
　　　　　　　　&#8221;*&#8221;　　　　　　　　　　　　{exit 6}　　　　<br />
　　　　　　　　eof</p>
<p>　　　<br />
　　这个脚本退出时用一个数字来表示所发生的情况。0表示passwd程序正常运行，1表示非预期的死亡，2表示锁定，等等。使用数字是为了简单起见。expect返回字符串和返回数字是一样简单的，即使是派生程序自身产生的消息也是一样的。实际上，典型的做法是把整个交互的过程存到一个文件里面，只有当程序的运行和预期一样的时候才把这个文件删除。否则这个log被留待以后进一步的检查。</p>
<p>　　这个passwd检查脚本被设计成由别的脚本来驱动。这第二个脚本从一个文件里面读取参数和预期的结果。对于每一个输入参数集，它调用第一个脚本并且把结果和预期的结果相比较。(因为这个任务是非交互的，一个普通的老式shell就可以用来解释第二个脚本)。比如说，一个passwd的数据文件很有可能就象下面一样。</p>
<p>　　　　passwd.exp　　　　3　　　　bogus　　　　-　　　　　　　　-<br />
　　　　passwd.exp　　　　0　　　　fred　　　　abledabl　　　　abledabl<br />
　　　　passwd.exp　　　　5　　　　fred　　　　abcdefghijklm　　　　-<br />
　　　　passwd.exp　　　　5　　　　fred　　　　abc　　　　　　　　-<br />
　　　　passwd.exp　　　　6　　　　fred　　　　foobar　　　　　　　　bar　　　　<br />
　　　　passwd.exp　　　　4　　　　fred　　　　^C　　　　　　　　-</p>
<p>　　第一个域的名字是要被运行的回归脚本。第二个域是需要和结果相匹配的退出值。第三个域就是用户名。第四个域和第五个域就是提示时应该输入的密码。减号仅仅表示那里有一个域，这个域其实绝对不会用到。在第一个行中，bogus表示用户名是非法的，因此passwd会响应说：没有此用户。expect在退出时会返回3，3恰好就是第二个域。在最后一行中，^C就是被切实的送给程序来验证程序是否恰当的退出。</p>
<p>　　通过这种方法，expect可以用来检验和调试交互式软件，这恰恰是IEEE的POSIX 1003.2(shell和工具)的一致性检验所要求的。进一步的说明请参考Libes[6]。</p>
<p>7.[rogue 和伪终端]</p>
<p>　　Unix用户肯定对通过管道来和其他进程相联系的方式非常的熟悉(比如说：一个shell管道)。expect使用伪终端来和派生的进程相联系。伪终端提供了终端语义以便程序认为他们正在和真正的终端进行I/O操作。</p>
<p>　　比如说，BSD的探险游戏rogue在生模式下运行，并假定在连接的另一端是一个可寻址的字符终端。可以用expect编程，使得通过使用用户界面可以玩这个游戏。</p>
<p>　　rogue这个探险游戏首先提供给你一个有各种物理属性，比如说力量值，的角色。在大部分时间里，力量值都是16，但在几乎每20次里面就会有一个力量值是18。很多的rogue玩家都知道这一点，但没有人愿意启动程序20次以获得一个好的配置。下面的这个脚本就能达到这个目的。</p>
<p>　　　　for {} {1} {} {<br />
　　　　　　　　spawn rogue<br />
　　　　　　　　expect &#8220;*Str:18*&#8221;　　　　break　　　　<br />
　　　　　　　　　　　 &#8220;*Str:16*&#8221;　　　　<br />
　　　　　　　　close<br />
　　　　　　　　wait<br />
　　　　}<br />
　　　　interact</p>
<p>　　第一行是个for循环，和C语言的控制格式很象。rogue启动后，expect就检查看力量值是18还是16，如果是16，程序就通过执行close和wait来退出。这两个命令的作用分别是关闭和伪终端的连接和等待进程退出。rogue读到一个文件结束符就推出，从而循环继续运行，产生一个新的rogue游戏来检查。</p>
<p>　　当一个值为18的配置找到后，控制就推出循环并跳到最后一行脚本。interact把控制转移给用户以便他们能够玩这个特定的游戏。</p>
<p>　　想象一下这个脚本的运行。你所能真正看到的就是20或者30个初始的配置在不到一秒钟的时间里掠过屏幕，最后留给你的就是一个有着很好配置的游戏。唯一比这更好的方法就是使用调试工具来玩游戏。</p>
<p>　　我们很有必要认识到这样一点：rogue是一个使用光标的图形游戏。expect程序员必须了解到：光标的运动并不一定以一种直观的方式在屏幕上体现。幸运的是，在我们这个例子里，这不是一个问题。将来的对expect的改进可能会包括一个内嵌的能支持字符图形区域的终端模拟器。</p>
<p>8.[ftp]</p>
<p>　　我们使用expect写第一个脚本并没有打印出&#8221;Hello,World&#8221;。实际上，它实现了一些更有用的功能。它能通过非交互的方式来运行ftp。ftp是用来在支持TCP/IP的网络上进行文件传输的程序。除了一些简单的功能，一般的实现都要求用户的参与。</p>
<p>　　下面这个脚本从一个主机上使用匿名ftp取下一个文件来。其中，主机名是第一个参数。文件名是第二个参数。</p>
<p>　　　　　　　　spawn　　　　ftp　　　　[lindex $argv 1]<br />
　　　　　　　　expect　&#8221;*Name*&#8221;<br />
　　　　　　　　send　　　　　&#8221;anonymous &#8221;<br />
　　　　　　　　expect　&#8221;*Password:*&#8221;<br />
　　　　　　　　send [exec whoami]<br />
　　　　　　　　expect &#8220;*ok*ftp&gt;*&#8221;<br />
　　　　　　　　send &#8220;get [lindex $argv 2] &#8221;<br />
　　　　　　　　expect &#8220;*ftp&gt;*&#8221;</p>
<p>　　上面这个程序被设计成在后台进行ftp。虽然他们在底层使用和expect类似的机制，但他们的可编程能力留待改进。因为expect提供了高级语言，你可以对它进行修改来满足你的特定需求。比如说，你可以加上以下功能：</p>
<p>　　　　：坚持－－如果连接或者传输失败，你就可以每分钟或者每小时，甚<br />
　　　　　　　　至可以根据其他因素，比如说用户的负载，来进行不定期的<br />
　　　　　　　　重试。<br />
　　　　：通知－－传输时可以通过mail,write或者其他程序来通知你，甚至<br />
　　　　　　　　可以通知失败。<br />
　　　　：初始化－每一个用户都可以有自己的用高级语言编写的初始化文件<br />
　　　　　　　　(比如说，.ftprc)。这和C shell对.cshrc的使用很类似。</p>
<p>　　expect还可以执行其他的更复杂的任务。比如说，他可以使用McGill大学的Archie系统。Archie是一个匿名的Telnet服务，它提供对描述Internet上可通过匿名ftp获取的文件的数据库的访问。通过使用这个服务，脚本可以询问Archie某个特定的文件的位置，并把它从ftp服务器上取下来。这个功能的实现只要求在上面那个脚本中加上几行就可以。</p>
<p>　　现在还没有什么已知的后台-ftp能够实现上面的几项功能，能不要说所有的功能了。在expect里面，它的实现却是非常的简单。“坚持”的实现只要求在expect脚本里面加上一个循环。“通知”的实现只要执行mail和write就可以了。“初始化文件”的实现可以使用一个命令，source .ftprc，就可以了，在.ftprc里面可以有任何的expect命令。</p>
<p>　　虽然这些特征可以通过在已有的程序里面加上钩子函数就可以，但这也不能保证每一个人的要求都能得到满足。唯一能够提供保证的方法就是提供一种通用的语言。一个很好的解决方法就是把Tcl自身融入到ftp和其他的程序中间去。实际上，这本来就是Tcl的初衷。在还没有这样做之前，expect提供了一个能实现大部分功能但又不需要任何重写的方案。</p>
<p>9.[fsck]</p>
<p>　　fsck是另外一个缺乏足够的用户接口的例子。fsck几乎没有提供什么方法来预先的回答一些问题。你能做的就是给所有的问题都回答&#8221;yes&#8221;或者都回答&#8221;no&#8221;。</p>
<p>　　下面的程序段展示了一个脚本如何的使的自动的对某些问题回答&#8221;yes&#8221;，而对某些问题回答&#8221;no&#8221;。下面的这个脚本一开始先派生fsck进程，然后对其中两种类型的问题回答&#8221;yes&#8221;，而对其他的问题回答&#8221;no&#8221;。</p>
<p>　　　　for {} {1} {} {<br />
　　　　　　　　expect<br />
　　　　　　　　　　　　eof　　　　　　　　break　　　　　　　　<br />
　　　　　　　　　　　　&#8221;*UNREF FILE*CLEAR?&#8221;　　　　{send &#8220;r &#8220;}　　　　<br />
　　　　　　　　　　　　&#8221;*BAD INODE*FIX?&#8221;　　　　{send &#8220;y &#8220;}　　　　<br />
　　　　　　　　　　　　&#8221;*?&#8221;　　　　　　　　　　　　{send &#8220;n &#8220;}　　　　<br />
　　　　}</p>
<p>　　在下面这个版本里面，两个问题的回答是不同的。而且，如果脚本遇到了什么它不能理解的东西，就会执行interact命令把控制交给用户。用户的击键直接交给fsck处理。当执行完后，用户可以通过按&#8221;+&#8221;键来退出或者把控制交还给expect。如果控制是交还给脚本了，脚本就会自动的控制进程的剩余部分的运行。</p>
<p>　　　　for {} {1} {}{<br />
　　　　　　　　expect 　　　　　　　　　　　　<br />
　　　　　　　　　　　　eof　　　　　　　　break　　　　　　　　<br />
　　　　　　　　　　　　&#8221;*UNREF FILE*CLEAR?&#8221;　　　　{send &#8220;y &#8220;}　　　　<br />
　　　　　　　　　　　　&#8221;*BAD INODE*FIX?&#8221;　　　　{send &#8220;y &#8220;}　　　　<br />
　　　　　　　　　　　　&#8221;*?&#8221;　　　　　　　　　　　　{interact +}　　　　<br />
　　　　}</p>
<p>　　如果没有expect，fsck只有在牺牲一定功能的情况下才可以非交互式的运行。fsck几乎是不可编程的，但它却是系统管理的最重要的工具。许多别的工具的用户接口也一样的不足。实际上，正是其中的一些程序的不足导致了expect的诞生。</p>
<p>10.[控制多个进程：作业控制]</p>
<p>　 expect的作业控制概念精巧的避免了通常的实现困难。其中包括了两个问题：一个是expect如何处理经典的作业控制，即当你在终端上按下^Z键时expect如何处理；另外一个就是expect是如何处理多进程的。</p>
<p>　 对第一个问题的处理是：忽略它。expect对经典的作业控制一无所知。比如说，你派生了一个程序并且发送一个^Z给它，它就会停下来(这是伪终端的完美之处)而expect就会永远的等下去。</p>
<p>　 但是，实际上，这根本就不成一个问题。对于一个expect脚本，没有必要向进程发送^Z。也就是说，没有必要停下一个进程来。expect仅仅是忽略了一个进程，而把自己的注意力转移到其他的地方。这就是expect的作业控制思想，这个思想也一直工作的很好。</p>
<p>　　从用户的角度来看是象这样的：当一个进程通过spawn命令启动时，变量spawn_id就被设置成某进程的描述符。由spawn_id描述的进程就被认为是当前进程。(这个描述符恰恰就是伪终端文件的描述符，虽然用户把它当作一个不透明的物体)。expect和send命令仅仅和当前进程进行交互。所以，切换一个作业所需要做的仅仅是把该进程的描述符赋给spawn_id。</p>
<p>　　这儿有一个例子向我们展示了如何通过作业控制来使两个chess进程进行交互。在派生完两个进程之后，一个进程被通知先动一步。在下面的循环里面，每一步动作都送给另外一个进程。其中，read_move和write_move两个过程留给读者来实现。(实际上，它们的实现非常的容易，但是，由于太长了所以没有包含在这里)。</p>
<p>　　　　spawn chess　　　　　　　　　　　　;# start player one<br />
　　　　set id1　　　　$spawn_id<br />
　　　　expect &#8220;Chess &#8221;<br />
　　　　send &#8220;first &#8220;　　　　　　　　　　　　;# force it to go first<br />
　　　　read_move</p>
<p>　　　　spawn chess　　　　　　　　　　　　;# start player two<br />
　　　　set id2　　　　$spawn_id<br />
　　　　expect &#8220;Chess &#8221;<br />
　　　　<br />
　　　　for {} {1} {}{<br />
　　　　　　　　send_move<br />
　　　　　　　　read_move<br />
　　　　　　　　set spawn_id　　　　$id1<br />
　　　　　　　　<br />
　　　　　　　　send_move<br />
　　　　　　　　read_move<br />
　　　　　　　　set spawn_id　　　　$id2<br />
　　　　}</p>
<p>　　 有一些应用程序和chess程序不太一样，在chess程序里，的两个玩家轮流动。下面这个脚本实现了一个冒充程序。它能够控制一个终端以便用户能够登录和正常的工作。但是，一旦系统提示输入密码或者输入用户名的时候，expect就开始把击键记下来，一直到用户按下回车键。这有效的收集了用户的密码和用户名，还避免了普通的冒充程序的&#8221;Incorrect password-tryagain&#8221;。而且，如果用户连接到另外一个主机上，那些额外的登录也会被记录下来。</p>
<p>　　　　spawn tip /dev/tty17　　　　　　　　;# open connection to<br />
　　　　set tty $spawn_id　　　　　　　　;# tty to be spoofed</p>
<p>　　　　spawn login<br />
　　　　set login $spawn_id</p>
<p>　　　　log_user 0<br />
　　　　<br />
　　　　for {} {1} {} {<br />
　　　　　　　　set ready　[select $tty $login]<br />
　　　　　　　　<br />
　　　　　　　　case $login in $ready {<br />
　　　　　　　　　　　　set spawn_id $login<br />
　　　　　　　　　　　　expect 　　　　　　　　<br />
　　　　　　　　　　　　　　{&#8220;*password*&#8221; &#8220;*login*&#8221;}{<br />
　　　　　　　　　　　　　　　　　 send_user $expect_match<br />
　　　　　　　　　　　　　　　　　 set log 1<br />
　　　　　　　　　　　　　　　　 }　　　　<br />
　　　　　　　　　　　　　 &#8220;*&#8221;　　　　　　　　;# ignore everything else<br />
　　　　　　　　　　　　set spawn_id　　　　$tty;<br />
　　　　　　　　　　　　send $expect_match<br />
　　　　　　　　}<br />
　　　　　　　　case $tty in $ready {<br />
　　　　　　　　　　　　set spawn_id　　　　$tty<br />
　　　　　　　　　　　　expect &#8220;* *&#8221;{<br />
　　　　　　　　　　　　　　　　　　　　if $log {<br />
　　　　　　　　　　　　　　　　　　　　　 send_user $expect_match<br />
　　　　　　　　　　　　　　　　　　　　　 set log 0<br />
　　　　　　　　　　　　　　　　　　　　}<br />
　　　　　　　　　　　　　　　　　　 }　　　　<br />
　　　　　　　　　　　　　　　　&#8221;*&#8221;　{<br />
　　　　　　　　　　　　　　　　　　　　send_user $expect_match<br />
　　　　　　　　　　　　　　　　　　 }<br />
　　　　　　　　　　　　set spawn_id 　　　　$login;<br />
　　　　　　　　　　　　send $expect_match<br />
　　　　　　　　}<br />
　　　　}<br />
　　　　　　　　</p>
<p>　　 这个脚本是这样工作的。首先连接到一个login进程和终端。缺省的，所有的对话都记录到标准输出上(通过send_user)。因为我们对此并不感兴趣，所以，我们通过命令&#8221;log_user 0&#8243;来禁止这个功能。(有很多的命令来控制可以看见或者可以记录的东西)。</p>
<p>　　 在循环里面，select等待终端或者login进程上的动作，并且返回一个等待输入的spawn_id表。如果在表里面找到了一个值的话，case就执行一个action。比如说，如果字符串&#8221;login&#8221;出现在login进程的输出中，提示就会被记录到标准输出上，并且有一个标志被设置以便通知脚本开始记录用户的击键，直至用户按下了回车键。无论收到什么，都会回显到终端上，一个相应的action会在脚本的终端那一部分执行。</p>
<p>　　 这些例子显示了expect的作业控制方式。通过把自己插入到对话里面，expect可以在进程之间创建复杂的I/O流。可以创建多扇出，复用扇入的，动态的数据相关的进程图。</p>
<p>　　 相比之下，shell使得它自己一次一行的读取一个文件显的很困难。shell强迫用户按下控制键(比如，^C,^Z)和关键字(比如fg和bg)来实现作业的切换。这些都无法从脚本里面利用。相似的是：以非交互方式运行的shell并不处理“历史记录”和其他一些仅仅为交互式使用设计的特征。这也出现了和前面哪个passwd程序的相似问题。相似的，也无法编写能够回归的测试shell的某些动作的shell脚本。结果导致shell的这些方面无法进行彻底的测试。</p>
<p>　　 如果使用expect的话，可以使用它的交互式的作业控制来驱动shell。一个派生的shell认为它是在交互的运行着，所以会正常的处理作业控制。它不仅能够解决检验处理作业控制的shell和其他一些程序的问题。还能够在必要的时候，让shell代替expect来处理作业。可以支持使用shell风格的作业控制来支持进程的运行。这意味着：首先派生一个shell，然后把命令送给shell来启动进程。如果进程被挂起，比如说，发送了一个^Z，进程就会停下来，并把控制返回给shell。对于expect而言，它还在处理同一个进程(原来那个shell)。</p>
<p>　　expect的解决方法不仅具有很大的灵活性，它还避免了重复已经存在于shell中的作业控制软件。通过使用shell，由于你可以选择你想派生的shell，所以你可以根据需要获得作业控制权。而且，一旦你需要(比如说检验的时候)，你就可以驱动一个shell来让这个shell以为它正在交互式的运行。这一点对于在检测到它们是否在交互式的运行之后会改变输出的缓冲的程序来说也是很重要的。</p>
<p>　　为了进一步的控制，在interact执行期间，expect把控制终端(是启动expect的那个终端，而不是伪终端)设置成生模式以便字符能够正确的传送给派生的进程。当expect在没有执行interact的时候，终端处于熟模式下，这时候作业控制就可以作用于expect本身。</p>
<p>11.[交互式的使用expect]</p>
<p>　　在前面，我们提到可以通过interact命令来交互式的使用脚本。基本上来说，interact命令提供了对对话的自由访问，但我们需要一些更精细的控制。这一点，我们也可以使用expect来达到，因为expect从标准输入中读取输入和从进程中读取输入一样的简单。 但是，我们要使用expect_user和send_user来进行标准I/O，同时不改变spawn_id。</p>
<p>　　下面的这个脚本在一定的时间内从标准输入里面读取一行。这个脚本叫做timed_read，可以从csh里面调用，比如说，set answer=&#8221;timed_read 30&#8243;就能调用它。</p>
<p>　　　　#!/usr/local/bin/expect -f<br />
　　　　set timeout [lindex $argv 1]<br />
　　　　expect_user &#8220;* &#8221;<br />
　　　　send_user $expect_match</p>
<p>　　 第三行从用户那里接收任何以新行符结束的任何一行。最后一行把它返回给标准输出。如果在特定的时间内没有得到任何键入，则返回也为空。</p>
<p>　　 第一行支持&#8221;#!&#8221;的系统直接的启动脚本。(如果把脚本的属性加上可执行属性则不要在脚本前面加上expect)。当然了脚本总是可以显式的用&#8221;expect scripot&#8221;来启动。在-c后面的选项在任何脚本语句执行前就被执行。比如说，不要修改脚本本身，仅仅在命令行上加上-c &#8220;trace&#8230;&#8221;，该脚本可以加上trace功能了(省略号表示trace的选项)。</p>
<p>　　 在命令行里实际上可以加上多个命令，只要中间以&#8221;;&#8221;分开就可以了。比如说，下面这个命令行：</p>
<p>　　　　expect -c &#8220;set timeout 20;spawn foo;expect&#8221;</p>
<p>　　　一旦你把超时时限设置好而且程序启动之后，expect就开始等待文件结束符或者20秒的超时时限。 如果遇到了文件结束符(EOF)，该程序就会停下来，然后expect返回。如果是遇到了超时的情况，expect就返回。在这两中情况里面，都隐式的杀死了当前进程。</p>
<p>　　 如果我们不使用expect而来实现以上两个例子的功能的话，我们还是可以学习到很多的东西的。在这两中情况里面，通常的解决方案都是fork另一个睡眠的子进程并且用signal通知原来的shell。如果这个过程或者读先发生的话，shell就会杀司那个睡眠的进程。 传递pid和防止后台进程产生启动信息是一个让除了高手级shell程序员之外的人头痛的事情。提供一个通用的方法来象这样启动多个进程会使shell脚本非常的复杂。 所以几乎可以肯定的是，程序员一般都用一个专门C程序来解决这样一个问题。</p>
<p>　　　expect_user,send_user,send_error(向标准错误终端输出)在比较长的，用来把从进程来的复杂交互翻译成简单交互的expect脚本里面使用的比较频繁。在参考[7]里面，Libs描述怎样用脚本来安全的包裹(wrap)adb，怎样把系统管理员从需要掌握adb的细节里面解脱出来，同时大大的降低了由于错误的击键而导致的系统崩溃。</p>
<p>　　　一个简单的例子能够让ftp自动的从一个私人的帐号里面取文件。在这种情况里，要求提供密码。 即使文件的访问是受限的，你也应该避免把密码以明文的方式存储在文件里面。把密码作为脚本运行时的参数也是不合适的，因为用ps命令能看到它们。有一个解决的方法就是在脚本运行的开始调用expect_user来让用户输入以后可能使用的密码。这个密码必须只能让这个脚本知道，即使你是每个小时都要重试ftp。</p>
<p>　　　即使信息是立即输入进去的，这个技巧也是非常有用。比如说，你可以写一个脚本，把你每一个主机上不同的帐号上的密码都改掉，不管他们使用的是不是同一个密码数据库。如果你要手工达到这样一个功能的话，你必须Telnet到每一个主机上，并且手工输入新的密码。而使用expect,你可以只输入密码一次而让脚本来做其它的事情。</p>
<p>　　　expect_user和interact也可以在一个脚本里面混合的使用。考虑一下在调试一个程序的循环时，经过好多步之后才失败的情况。一个expect脚本可以驱动哪个调试器，设置好断点，执行该程序循环的若干步，然后将控制返回给键盘。它也可以在返回控制之前，在循环体和条件测试之间来回的切换。</p>
]]></content:encoded>
			<wfw:commentRss>http://litblue.net/p/873/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
