﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>BlogJava-joan-文章分类-Linux</title><link>http://www.blogjava.net/joan/category/32989.html</link><description>私は张で

QQ:774199038</description><language>zh-cn</language><lastBuildDate>Fri, 18 Sep 2009 05:31:29 GMT</lastBuildDate><pubDate>Fri, 18 Sep 2009 05:31:29 GMT</pubDate><ttl>60</ttl><item><title>linux常用端口对照</title><link>http://www.blogjava.net/joan/articles/236558.html</link><dc:creator>joan</dc:creator><author>joan</author><pubDate>Sat, 25 Oct 2008 08:48:00 GMT</pubDate><guid>http://www.blogjava.net/joan/articles/236558.html</guid><wfw:comment>http://www.blogjava.net/joan/comments/236558.html</wfw:comment><comments>http://www.blogjava.net/joan/articles/236558.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/joan/comments/commentRss/236558.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/joan/services/trackbacks/236558.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: linux常用端口对照<br>著名端口<br>1 tcpmux TCP 端口服务多路复用<br>5 rje 远程作业入口<br>7 echo Echo 服务<br>9 discard 用于连接测试的空服务<br>11 systat 用于列举连接了的端口的系统状态<br>13 daytime 给请求主机发送日期和时间<br>&nbsp;&nbsp;<a href='http://www.blogjava.net/joan/articles/236558.html'>阅读全文</a><img src ="http://www.blogjava.net/joan/aggbug/236558.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/joan/" target="_blank">joan</a> 2008-10-25 16:48 <a href="http://www.blogjava.net/joan/articles/236558.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Solaris下MySQL5安装笔记</title><link>http://www.blogjava.net/joan/articles/236552.html</link><dc:creator>joan</dc:creator><author>joan</author><pubDate>Sat, 25 Oct 2008 07:59:00 GMT</pubDate><guid>http://www.blogjava.net/joan/articles/236552.html</guid><wfw:comment>http://www.blogjava.net/joan/comments/236552.html</wfw:comment><comments>http://www.blogjava.net/joan/articles/236552.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/joan/comments/commentRss/236552.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/joan/services/trackbacks/236552.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: Solaris下MySQL5安装笔记<br>&nbsp;&nbsp;<a href='http://www.blogjava.net/joan/articles/236552.html'>阅读全文</a><img src ="http://www.blogjava.net/joan/aggbug/236552.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/joan/" target="_blank">joan</a> 2008-10-25 15:59 <a href="http://www.blogjava.net/joan/articles/236552.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>LINUX COMMANDS LINE</title><link>http://www.blogjava.net/joan/articles/234751.html</link><dc:creator>joan</dc:creator><author>joan</author><pubDate>Thu, 16 Oct 2008 12:12:00 GMT</pubDate><guid>http://www.blogjava.net/joan/articles/234751.html</guid><wfw:comment>http://www.blogjava.net/joan/comments/234751.html</wfw:comment><comments>http://www.blogjava.net/joan/articles/234751.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/joan/comments/commentRss/234751.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/joan/services/trackbacks/234751.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: LINUX COMMANDS LINE                        命令            描述                            &nbsp;                                                                           ...&nbsp;&nbsp;<a href='http://www.blogjava.net/joan/articles/234751.html'>阅读全文</a><img src ="http://www.blogjava.net/joan/aggbug/234751.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/joan/" target="_blank">joan</a> 2008-10-16 20:12 <a href="http://www.blogjava.net/joan/articles/234751.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>linux 中文乱码解决</title><link>http://www.blogjava.net/joan/articles/233559.html</link><dc:creator>joan</dc:creator><author>joan</author><pubDate>Fri, 10 Oct 2008 04:34:00 GMT</pubDate><guid>http://www.blogjava.net/joan/articles/233559.html</guid><wfw:comment>http://www.blogjava.net/joan/comments/233559.html</wfw:comment><comments>http://www.blogjava.net/joan/articles/233559.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/joan/comments/commentRss/233559.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/joan/services/trackbacks/233559.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: linux 中文乱码解决方法&nbsp;&nbsp;<a href='http://www.blogjava.net/joan/articles/233559.html'>阅读全文</a><img src ="http://www.blogjava.net/joan/aggbug/233559.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/joan/" target="_blank">joan</a> 2008-10-10 12:34 <a href="http://www.blogjava.net/joan/articles/233559.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Linux 文件和目录管理之列出、删除、复制、移动及改名</title><link>http://www.blogjava.net/joan/articles/233124.html</link><dc:creator>joan</dc:creator><author>joan</author><pubDate>Wed, 08 Oct 2008 05:31:00 GMT</pubDate><guid>http://www.blogjava.net/joan/articles/233124.html</guid><wfw:comment>http://www.blogjava.net/joan/comments/233124.html</wfw:comment><comments>http://www.blogjava.net/joan/articles/233124.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/joan/comments/commentRss/233124.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/joan/services/trackbacks/233124.html</trackback:ping><description><![CDATA[<p><font id="1" size="4"><strong><br />
1、列文件或目录的信息工具 ls或dir;<br />
</strong></font></p>
<p>ls 命令可以用于显示目录的内容，也可以显示文件的属性，比如节点、文件种类、权限、拥有者、大小、创建时间等；在目前最新版本的Linux中dir和ls命令的用法是一样的；有兴趣的不仿尝试一下；</p>
<p><font id="1.1" size="3"><strong><br />
1.1 ls 的基础语法和参数；<br />
</strong></font></p>
<p><strong>语法格式：</strong></p>
<p>
<div class="codeblock"><code>#ls ［参数]&nbsp;&nbsp; [目录或文件名]</code></div>
<p>&nbsp;</p>
<p><strong>参数：</strong></p>
<p>
<div class="codeblock"><code>-a 显示所有文件，包含隐藏文件；包括&#8220;.&#8220;和&#8220;..&#8220;<br />
-A 显示所有文件，包含隐藏文件，不包括&#8220;.&#8220;和&#8220;..&#8220;目录；<br />
-B 不列出文件名以~结尾的文件；<br />
-C 按列列出文件；<br />
-d 仅可以查看目录的属性参数及信息；<br />
-F 这个参数加上后，能给目录添加上/，给可执行文件加上*，给符号链接加上@&nbsp; 等等，来标记文件名，目的是让用户方便查看； <br />
-l 长格式输出<br />
-h 习惯人们可阅读的方式来显示文件或目录的大小，比如K、M或G等；<br />
-p 在目录的后面附加/标记；<br />
-r 逆序列出文件；<br />
-t&nbsp; 按文件最后访问（或修改）的时间排序，最新的排在最前面；<br />
-U 按原始排序，<br />
-L 递归显示，也就是说，当我们列某个目录的下的所有文件和目录时，能把它的下级目录的内容显示出来。<br />
--help&nbsp; 获得帮助；</code></div>
<p>&nbsp;</p>
<p>在这里，位于[]之内的都是可选的。如果您只输入ls ，就会列出用户所处当前目录的所有文件，用短格式输出，但不会列出隐藏文件。</p>
<p>判断用户所处目录的命令是pwd，也就是</p>
<p>
<div class="codeblock"><code>[root@localhost ~]# pwd<br />
/root</code></div>
<p>&nbsp;</p>
<p><font id="1.2" size="3"><strong><br />
1.2 ls 的参数示例应用；<br />
</strong></font></p>
<p><font id="1.21" size="2"><strong><br />
1.21 列出目录下所有文件，包含或不包含隐藏文件，-a 参数及-l参数的运用；<br />
</strong></font></p>
<p>
<div class="codeblock"><code>#ls -la ［目录名]</code></div>
<p>&nbsp;</p>
<p>如果不接目录名，表示输出当前用户所处目录内的所有文件，包括隐藏文件；</p>
<p>
<div class="codeblock"><code>[root@localhost ~]# pwd<br />
/root<br />
[root@localhost ~]# ls -la</code></div>
<p>&nbsp;</p>
<p><strong>列出某一目录下的的文件或目录，但不包括隐藏文件，我们只用-l参数</strong></p>
<p>
<div class="codeblock"><code>#ls -l&nbsp; 目录</code></div>
<p>&nbsp;</p>
<p>比如：<br />
<div class="codeblock"><code>[root@localhost ~]# ls&nbsp; -l /root/<br />
总计 13968<br />
-rw-r--r-- 1 root root&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 0 04-19 14:09 123.txt<br />
-rw------- 1 root root&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1375 03-16 08:55 anaconda-ks.cfg<br />
-rw-r--r-- 1 root root&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 2 03-27 02:00 fonts.scale<br />
-rw-r--r-- 1 root root&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 5423 03-16 08:52 install.log.syslog<br />
-rw-r--r-- 1 root root&nbsp; 14087155 03-16 07:53 kernel-2.6.15-1.2025_FC5.i686.rpm<br />
lrwxrwxrwx 1 root root&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 33 04-19 11:27 kernel.rpm -&gt; kernel-2.6.15-1.2025_FC5.i686.rpm<br />
drwxr-xr-x 2 1000 users&nbsp;&nbsp;&nbsp;&nbsp; 4096 04-04 23:30 mkuml-2004.07.17<br />
-rw-r--r-- 1 root root&nbsp;&nbsp;&nbsp;&nbsp; 68012 04-04 20:28 mkuml-2004.07.17-ananas.tar.bz2<br />
drwxr-xr-x 2 root root&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 4096 04-19 10:53 mydir<br />
-rw-r--r-- 1 root root&nbsp;&nbsp;&nbsp;&nbsp; 53992 03-16 08:54 myinstall.log<br />
-rw-r--r-- 1 root root&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 0 04-19 14:10 plinux.txt<br />
drwxr-xr-x 2 root root&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 4096 03-17 04:25 Public<br />
-rw-r--r-- 1 root root&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 613 03-26 18:41 upgrade.log<br />
-rw-r--r-- 1 root root&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 0 03-26 18:39 upgrade.log.syslog<br />
lrwxrwxrwx 1 root root&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 6 04-19 11:17 yourdir -&gt; mydir/</code></div>
<p>&nbsp;</p>
<p><strong>说明：如果以长格式输入，总共显示出八段内容：</strong></p>
<p><strong>第一段</strong>文件种类及权限，也就是类似这样的-rw-r--r-- ，我们在前面讲到，如果在这段中，第一字符表示文件的类型，如果出现-，表示普通文件。如果是d开头的就是目录。在这个例子中，123.txt是普通文件，而mkuml-2004.07.17就是一个目录。关于文件的种类，请参考 ：<br />
rw-r--r--是权限位，我们在以后的教程中会讲到。<br />
<strong>第二段</strong> 硬链接个数（文件系增加一个硬链接，数字会增加1，默认从1开始，1表示无硬链接文件，如果是一个目录，它的默认值应该是2。目录是不能做硬链接的）<br />
如果我们不以长格式输出的话，可以把参数省略；<br />
<strong>第三段</strong> 文件或目录所占用的字节数，如果您想用K来表示，请用ls -lh /root<br />
<strong>第四段 </strong>最后访问日期<br />
<strong>第五段</strong> 最后访问时间<br />
<strong>第六段</strong> 文件名</p>
<p>
<div class="codeblock"><code>[root@localhost ~]# ls /root</code></div>
<p>&nbsp;</p>
<p><font id="1.22" size="2"><strong><br />
1.22 仅查看目录的属性的-d参数的运用示例；<br />
</strong></font></p>
<p>
<div class="codeblock"><code>[root@localhost ~]# ls -ld&nbsp; /etc&nbsp; /boot&nbsp; 注：查看/etc和/boot目录的信息；<br />
<br />
drwxr-xr-x&nbsp;&nbsp; 4 root root&nbsp; 4096 04-11 16:22 /boot<br />
drwxr-xr-x 108 root root 12288 04-20 12:36 /etc</code></div>
<p>&nbsp;</p>
<p><font id="1.23" size="2"><strong><br />
1.23 查看文件或目录的inode节点，-i参数的运用；<br />
</strong></font></p>
<p>查看文件或目录的节点，我们要用到i参数。如果节点相同，能确认他们是相同的文件，是通过通过ln 创建的硬链接文件；链接接有何用？如果您想把一个文件复制时保持原文件或目录的节点、大小、权限以及访问（或修改）时间都和原文件一致的文件。必须通过硬链接来实现，用cp命令是不可能实现的。</p>
<p><strong>比如：</strong></p>
<p>
<div class="codeblock"><code>[root@localhost ~]# ls -li /root</code></div>
<br />
<br />
<br />
<div class="codeblock"><code>[root@localhost ~]# ls -li kernel*<br />
2408323 -rw-r--r-- 3 root root 14087155 03-16 07:53 kernel00.rpm<br />
2408270 lrwxrwxrwx 1 root root&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 33 04-19 14:56 kernel1.rpm -&gt; kernel-2.6.15-1.2025_FC5.i686.rpm<br />
2408323 -rw-r--r-- 3 root root 14087155 03-16 07:53 kernel-2.6.15-1.2025_FC5.i686.rpm<br />
2408323 -rw-r--r-- 3 root root 14087155 03-16 07:53 kernel.rpm</code></div>
<p>&nbsp;</p>
<p>我们看一下kernel00.rpm 、kernel.rpm 和 kernel-2.6.15-1.2025_FC5.i686.rpm 是不是节点相同？？他们的大小是不是一样，他们的访问日期是不是一样？只是他们的文件名不一样。文件名不一样没有关系，这能证明其中两个文件是由另一个文件通过ln 创建而成。</p>
<p>您可以尝试着用cp 把 kernel-2.6.15-1.2025_FC5.i686.rpm 复制为kernel002.rpm ，看看能不能保持节点相同？</p>
<p>
<div class="codeblock"><code>[root@localhost ~]# ls -li kernel*<br />
2408272 -rw-r--r-- 1 root root 14087155 04-19 16:05 kernel002.rpm<br />
2408323 -rw-r--r-- 3 root root 14087155 03-16 07:53 kernel00.rpm<br />
2408270 lrwxrwxrwx 1 root root&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 33 04-19 14:56 kernel1.rpm -&gt; kernel-2.6.15-1.2025_FC5.i686.rpm<br />
2408323 -rw-r--r-- 3 root root 14087155 03-16 07:53 kernel-2.6.15-1.2025_FC5.i686.rpm<br />
2408323 -rw-r--r-- 3 root root 14087155 03-16 07:53 kernel.rpm</code></div>
<p>&nbsp;</p>
<p>不是是kernel002.rpm 的节点和 kernel-2.6.15-1.2025_FC5.i686.rpm 不一样了？</p>
<p><font id="1.24" size="2"><strong><br />
1.24 关于排序的参数的应用；<br />
</strong></font></p>
<p><font color="blue">ls 显示目录的内容时，会将文件按a到z的字母顺序显示，优先级如下；</font></p>
<p>
<div class="codeblock"><code>数字&nbsp; <br />
a-z&nbsp; <br />
A-Z</code></div>
<p>&nbsp;</p>
<p>也就是说如果不加任何排序的参数，文件名第一个字母是数字的，将优先显示；其次才是A－Z，然后才是a-z；下面是几个排序的参数，大家练习一下就知道了；</p>
<p>
<div class="codeblock"><code>在文件的大小排序上，我们要用到-S参数； <br />
如果是逆序排序时，我们要用到-r参数；<br />
按最后访问的时候排序，要用到-t参数；<br />
根据扩展名进行排序，要用到参数 -X ； </code></div>
<p>&nbsp;</p>
<p><strong>举例</strong></p>
<p>
<div class="codeblock"><code>[root@localhost ~]# ls<br />
123.txt&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; fonts.scale&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; kernel&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; myinstall.log&nbsp; upgrade.log<br />
anaconda-ks.cfg&nbsp; install.log.syslog&nbsp; mkuml-2004.07.17-ananas.tar.bz2&nbsp; plinux.txt&nbsp;&nbsp;&nbsp;&nbsp; upgrade.log.syslog</code></div>
<p>&nbsp;</p>
<p>
<div class="codeblock"><code>[root@localhost ~]# ls -lS /root<br />
[root@localhost ~]# ls -lS<br />
总计 180<br />
-rw-r--r-- 1 root root 68012 04-04 20:28 mkuml-2004.07.17-ananas.tar.bz2<br />
-rw-r--r-- 1 root root 53992 03-16 08:54 myinstall.log<br />
-rw-r--r-- 1 root root&nbsp; 5423 03-16 08:52 install.log.syslog<br />
drwxr-xr-x 2 root root&nbsp; 4096 04-19 20:04 kernel<br />
-rw------- 1 root root&nbsp; 1375 04-19 15:04 anaconda-ks.cfg<br />
-rw-r--r-- 1 root root&nbsp;&nbsp; 613 03-26 18:41 upgrade.log<br />
-rw-r--r-- 1 root root&nbsp;&nbsp;&nbsp; 21 04-19 15:06 123.txt<br />
-rw-r--r-- 1 root root&nbsp;&nbsp;&nbsp;&nbsp; 2 03-27 02:00 fonts.scale<br />
-rw-r--r-- 1 root root&nbsp;&nbsp;&nbsp;&nbsp; 0 04-19 14:10 plinux.txt<br />
-rw-r--r-- 1 root root&nbsp;&nbsp;&nbsp;&nbsp; 0 03-26 18:39 upgrade.log.syslog</code></div>
<p>&nbsp;</p>
<p>举例：</p>
<p>
<div class="codeblock"><code>[root@localhost ~]# ls -lr<br />
总计 180<br />
-rw-r--r-- 1 root root&nbsp;&nbsp;&nbsp;&nbsp; 0 03-26 18:39 upgrade.log.syslog<br />
-rw-r--r-- 1 root root&nbsp;&nbsp; 613 03-26 18:41 upgrade.log<br />
-rw-r--r-- 1 root root&nbsp;&nbsp;&nbsp;&nbsp; 0 04-19 14:10 plinux.txt<br />
-rw-r--r-- 1 root root 53992 03-16 08:54 myinstall.log<br />
-rw-r--r-- 1 root root 68012 04-04 20:28 mkuml-2004.07.17-ananas.tar.bz2<br />
drwxr-xr-x 2 root root&nbsp; 4096 04-19 20:04 kernel<br />
-rw-r--r-- 1 root root&nbsp; 5423 03-16 08:52 install.log.syslog<br />
-rw-r--r-- 1 root root&nbsp;&nbsp;&nbsp;&nbsp; 2 03-27 02:00 fonts.scale<br />
-rw------- 1 root root&nbsp; 1375 04-19 15:04 anaconda-ks.cfg<br />
-rw-r--r-- 1 root root&nbsp;&nbsp;&nbsp; 21 04-19 15:06 123.txt</code></div>
<p>&nbsp;</p>
<p>
<div class="codeblock"><code>[root@localhost ~]# ls -lt<br />
总计 180<br />
drwxr-xr-x 2 root root&nbsp; 4096 04-19 20:04 kernel<br />
-rw-r--r-- 1 root root&nbsp;&nbsp;&nbsp; 21 04-19 15:06 123.txt<br />
-rw------- 1 root root&nbsp; 1375 04-19 15:04 anaconda-ks.cfg<br />
-rw-r--r-- 1 root root&nbsp;&nbsp;&nbsp;&nbsp; 0 04-19 14:10 plinux.txt<br />
-rw-r--r-- 1 root root 68012 04-04 20:28 mkuml-2004.07.17-ananas.tar.bz2<br />
-rw-r--r-- 1 root root&nbsp;&nbsp;&nbsp;&nbsp; 2 03-27 02:00 fonts.scale<br />
-rw-r--r-- 1 root root&nbsp;&nbsp; 613 03-26 18:41 upgrade.log<br />
-rw-r--r-- 1 root root&nbsp;&nbsp;&nbsp;&nbsp; 0 03-26 18:39 upgrade.log.syslog<br />
-rw-r--r-- 1 root root 53992 03-16 08:54 myinstall.log<br />
-rw-r--r-- 1 root root&nbsp; 5423 03-16 08:52 install.log.syslog</code></div>
<p>&nbsp;</p>
<p><font id="1.25" size="2"><strong><br />
1.25 递归显示目录的文件，-R参数的应用；<br />
</strong></font></p>
<p>递归显示目录下的所有文件，如果该目录下有子目录，也会把子目录的文件一并显示出来。</p>
<p><strong>比如</strong> </p>
<p>
<div class="codeblock"><code>[root@localhost ~]# ls -lR /</code></div>
<p>&nbsp;</p>
<p><strong>注：</strong>也就是把Linux下/根目录下的所有文件显示出来，但不会显示隐藏文件。自己试着输入上面的命令就知道怎么回事了。</p>
<p><font id="1.26" size="2"><strong><br />
1.26 关于ls 输出内容在终端显示颜色的参数 --color；<br />
</strong></font></p>
<p>在一般的情况下，ls输出内容是有颜色的，比如目录是蓝色，压缩文件是红字的显示。如果没有颜色，可以加上参数。当然也可以去掉颜色。</p>
<p>
<div class="codeblock"><code>--color=never&nbsp; 表示输出输出没有彩色<br />
--color=auto&nbsp; 表示自动<br />
--color=always 表示输出内容有彩色 </code></div>
<p>&nbsp;</p>
<p><strong>举例：</strong></p>
<p>
<div class="codeblock"><code>[root@localhost ~]# ls -la --color=never <br />
[root@localhost ~]# ls -la --color=any<br />
[root@localhost ~]# ls -la --color=always</code></div>
<p>&nbsp;</p>
<p>如果您的终端或控制台输出的内容没有颜色，可以自己来定义。在当前用户的家目录下的.bashrc 中加入下面的一行；</p>
<p>
<div class="codeblock"><code>alias ls="ls --color=always"</code></div>
<p>&nbsp;</p>
<p><font id="1.27" size="2"><strong><br />
1.27 ls的-F参数的示例；<br />
</strong></font></p>
<p>
<div class="codeblock"><code>[root@localhost ~]# ls -F<br />
crondw.sh*&nbsp; kernel/&nbsp; mkuml-2004.07.17-ananas.tar.bz2&nbsp; openQreadme.txt@&nbsp; sun.txt&nbsp; upgrade.log&nbsp; youdir/<br />
<br />
[root@localhost ~]# ls -lF<br />
总计 92<br />
-rwxr-xr-x 1 root root&nbsp;&nbsp;&nbsp;&nbsp; 0 04-20 14:18 crondw.sh*<br />
drwxr-xr-x 3 root root&nbsp; 4096 04-20 14:17 kernel/<br />
-rw-r--r-- 1 root root 68012 04-04 20:28 mkuml-2004.07.17-ananas.tar.bz2<br />
lrwxrwxrwx 1 root root&nbsp;&nbsp;&nbsp;&nbsp; 7 04-20 14:18 openQreadme.txt -&gt; sun.txt<br />
-rw-r--r-- 1 root root&nbsp;&nbsp;&nbsp; 11 04-20 14:17 sun.txt<br />
-rw-r--r-- 1 root root&nbsp;&nbsp; 613 03-26 18:41 upgrade.log<br />
drwxr-xr-x 6 root root&nbsp; 4096 04-20 14:17 youdir/</code></div>
<p>&nbsp;</p>
<p><font id="1.3" size="3"><strong><br />
1.3 通配符在ls命令中的应用；<br />
</strong></font></p>
<p>
<div class="codeblock"><code>* 代表0个或多个字符<br />
[]内部包括任何字符<br />
? 任何单个字符</code></div>
<p>&nbsp;</p>
<p><strong>举例：</strong></p>
<p>比如我们显示以k开头的所有文件，在/root目录中的；</p>
<p>
<div class="codeblock"><code>[root@localhost ~]# ls /root/k*<br />
kernel002.rpm&nbsp; kernel00.rpm&nbsp; kernel1.rpm&nbsp; kernel-2.6.15-1.2025_FC5.i686.rpm&nbsp; kernel.rpm</code></div>
<p>&nbsp;</p>
<p>我们显示以数字开头的所有文件；</p>
<p>
<div class="codeblock"><code>[root@localhost ~]# ls [0-9]*<br />
123.txt&nbsp; 234.txt&nbsp; 2kexe.txt&nbsp; 6mns.doc</code></div>
<p>&nbsp;</p>
<p>下面是一个?通配符的示例：</p>
<p>
<div class="codeblock"><code>[root@localhost ~]# ls *.t?t<br />
123.txt&nbsp; 234.txt&nbsp; 2kexe.txt&nbsp; 333.tot&nbsp; plinux.txt</code></div>
<p>&nbsp;</p>
<p><font id="1.4" size="3"><strong><br />
1.4 获得ls 的帮助；<br />
</strong></font></p>
<p>ls 的用法比较简单，至于更详细的参考，还是查man和help。遇到不会的，就查手册，我也是这么做的。</p>
<p>
<div class="codeblock"><code>[root@localhost ~]# ls --help<br />
[root@localhost ~]# man ls<br />
[root@localhost ~]# info ls </code></div>
<p>&nbsp;</p>
<p><font id="2" size="4"><strong><br />
2、移动文件或目录的命令 mv ；<br />
</strong></font></p>
<p>mv 命令是用来移动文件或目录的；有以下几种格式；</p>
<p>
<div class="codeblock"><code>#mv file1 file2&nbsp; 注：把file1移动到file2，如果file2不存在，则创建file2文件名；<br />
#mv file1 dir 注：把一个文件移动到一个事实存在的目录；<br />
#mv dir1 dir2&nbsp;&nbsp; 移动目录dir1 到 dir2 ，如果dir2不存在，则创建它；<br />
#mv file1 file2 file3 ... ...&nbsp; dir&nbsp;&nbsp; 移动file1、file2、file3等多个文件到dir目录中；<br />
#mv dir1 dir2 ... ... dirn&nbsp;&nbsp; 注：移动目录dir1和dir2等多个目录到dirn目录中</code></div>
<p>&nbsp;</p>
<p><strong>参数-i ，表示人机交互模式；提示警告信息；</strong></p>
<p><strong>举例：</strong></p>
<p>
<div class="codeblock"><code>[root@localhost ~]# mv -i 123.txt&nbsp; 234.txt<br />
mv：是否覆盖&#8220;234.txt&#8221;? y 注：要在这里输入y，表示允许覆盖234.txt文件；如果是n，请示不允许；</code></div>
<p>&nbsp;</p>
<p><strong>mv 也能和通配符结合一起使用，这样能把相似特征的文件移动到某处；</strong></p>
<p>
<div class="codeblock"><code>* 代表0个或多个字符<br />
[]内部包括任何字符<br />
? 任何单个字符</code></div>
<p>&nbsp;</p>
<p><strong><br />
举例：比如移动以数字开头的文件或目录到 root目录下的tmp目录中；<br />
</strong></p>
<p>
<div class="codeblock"><code>[root@localhost ~]# pwd<br />
/root<br />
[root@localhost ~]# mv [0-9]* tmp/<br />
[root@localhost ~]# ls -lh tmp/<br />
总计 4.0K<br />
-rw-r--r-- 1 root root 21 04-19 15:06 234.txt<br />
-rw-r--r-- 1 root root&nbsp; 0 04-19 22:23 2kexe.txt<br />
-rw-r--r-- 1 root root&nbsp; 0 04-19 22:25 333.tot<br />
-rw-r--r-- 1 root root&nbsp; 0 04-19 22:23 6mns.doc</code></div>
<p>&nbsp;</p>
<p><font id="3" size="4"><strong><br />
3、文件或目录的复制工具cp ；<br />
</strong></font></p>
<p><font id="3.1" size="3"><strong><br />
3.1 cp 的语法和参数<br />
</strong></font></p>
<p>
<div class="codeblock"><code>#cp&nbsp; ［参数选项]&nbsp;&nbsp; 源文件或目录&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 目标文件或目录</code></div>
<p>&nbsp;</p>
<p><strong>注：</strong>参数是可选的，常用参数比如 -r,-R,-p,-i ；</p>
<p><strong>参数说明（部份）</strong></p>
<p>-a 等同于-dpR参数一起使用；在复制过程中尽可能保留源文件或目录的属性；<br />
-b 给被覆盖的文件做备份。比如我们把file1 复制到file2时，如果file2存在，我们把file2覆盖掉，用这个参数就能同时生成一个file2~的文件，注意文件名后有~结尾<br />
-d 不间接引用符号链接，保持源文件和目标文件之间的硬链接关系；<br />
-f 删除已存在的目标文件；<br />
-i 覆盖已存在的目标文件之前给出警告提示，这是人机交互的选项；<br />
-l 建立文件硬链接，而不是复制；<br />
-p 保存源文件或目录的最后修改时间和模式，比如要保持目标目录或文件的属主、组、权限和最后访问（或修改）时间；<br />
-R 复制目录时，包括淅目录下所有的子目录和文件；<br />
-s 建立源文件的符号链接，而不是复制源文件。源文件名必须用绝对路径；<br />
-r 复制目录时，包括淅目录下所有的子目录和文件；-r选项不同于-R之处在于 尝试打开目的地文件前先删除已存在的目的地文件<br />
-i 人机交互模式，显法覆盖已存在的文件或目录的警告信息；<br />
-v 在复制之前，输出每个文件的名字；<br />
--help 查看帮助 ；</p>
<p><font id="3.2" size="3"><strong><br />
3.2 示例说明cp应用；<br />
</strong></font></p>
<p><font id="3.21" size="2"><strong><br />
3.21 参数-i的示例；<br />
</strong></font></p>
<p>
<div class="codeblock"><code>[root@localhost ~]# ls<br />
anaconda-ks.cfg&nbsp; install.log.syslog&nbsp; Kernel.rpm&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; mydir&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Plist&nbsp; upgrade.log&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; youdir<br />
fonts.scale&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; kernel&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; mkuml-2004.07.17-ananas.tar.bz2&nbsp; plinux.txt&nbsp; sun&nbsp;&nbsp;&nbsp; upgrade.log.syslog<br />
[root@localhost ~]# pwd<br />
/root<br />
<br />
[root@localhost ~]# cp&nbsp; -i Kernel.rpm Plist<br />
cp：是否覆盖&#8220;Plist&#8221;? y </code></div>
<p>&nbsp;</p>
<p><strong>注：</strong>人机交互在数-i的运用；如果源文件复制到目标文件，如果目标文件存在，则提示警告；</p>
<p><font id="3.22" size="2"><strong><br />
3.22 参数-a的示例及说明；<br />
</strong></font></p>
<p>把源目录复制到另外的一个目标，相当于克隆了一个目录，源目录和目标目录在用户组、权限及修改或访问时间保持一致；</p>
<p>
<div class="codeblock"><code>[root@localhost ~]# cp -a mydir youdir </code></div>
<p>&nbsp;</p>
<p><strong>注：</strong>复制目录mydir 到youdir ，如果yourdir目录不存在，则创建。并且把mydir中所有的文件下级子目录都复制到 yourdir目录中。也就是说mydir目录的文件和youdir是一样的。-a 参数等同于-dpR，并且源目录和目标目录的属性（用户组、权限、最后访问及修改时间）都一致；</p>
<p><font id="3.23" size="2"><strong><br />
3.23 参数-b的示例应用；<br />
</strong></font></p>
<p>把源文件复制为目标文件；并且尝试-b参数的运用；</p>
<p>
<div class="codeblock"><code>[root@localhost ~]# cp fonts.scale fonts.dir&nbsp; 把一个文件复制为另一个文件；<br />
<br />
[root@localhost ~]# cp -bi fonts.scale fonts.dir <br />
<br />
cp：是否覆盖&#8220;fonts.dir&#8221;? y&nbsp; 注：因为用了-i 参数，如果目标文件存在，则报警提示；<br />
<br />
[root@localhost ~]# ls -lh fonts.*<br />
-rw-r--r-- 1 root root 2 04-20 10:24 fonts.dir<br />
-rw-r--r-- 1 root root 2 04-20 10:24 fonts.dir~&nbsp; 注：-b参数运用的效果就是生成已存在目标文件的覆盖之前备份。<br />
-rw-r--r-- 1 root root 2 03-27 02:00 fonts.scale</code></div>
<p>&nbsp;</p>
<p><font id="3.24" size="2"><strong><br />
3.24 把多个文件复制到目录目录中示例；<br />
</strong></font></p>
<p>比如我们把位于用户当前目录下的fonts.dir、Kernel.rpm和Plist文件，复制到当前用户所处的目录下的sun目录中；</p>
<p>
<div class="codeblock"><code>[root@localhost ~]# pwd&nbsp; 注：判断用户所处的位置，也就是所处的目录；<br />
/root<br />
<br />
[root@localhost ~]# mv fonts.dir Kernel.rpm&nbsp; Plist&nbsp; sun/ <br />
[root@localhost ~]# ls sun/<br />
fonts.dir&nbsp; Kernel.rpm&nbsp; Plist</code></div>
<p>&nbsp;</p>
<p><strong>注：</strong>如果您想把多个目录或文件复制到目标目录时，您得加参数 -R</p>
<p><font id="3.25" size="2"><strong><br />
3.25 复制目录时-R参数的应用；<br />
</strong></font></p>
<p>复制一个目录到另一个目录时，我们要用到 -r或-R 或-a ， 如果目标目录不存在，则创建它，如果目标目录存在，则复制源目录到目标目录之下；看看-a和-R或-r有什么不同？尝试看看；</p>
<p>比如我们在用户当前操作的目录中，有mydir目录，我们想把mydir复制为medir（在复制之前medir是不存在的）。</p>
<p>
<div class="codeblock"><code>[root@localhost ~]# cp -R mydir medir 注：如果medir目录不存在，则创建medir目录，并且medir目录中的内容和mydir中的一样；</code></div>
<p>&nbsp;</p>
<p>如果您把-R参数换成-a参数，会有什么不同？看看前面的例子所说的；</p>
<p><font id="4" size="4"><strong><br />
4、 目录创建工具mkdir和删除空目录工具rmdir；<br />
</strong></font></p>
<p><font id="4.1" size="3"><strong><br />
4.1 mkdir 是目录创建工具；<br />
</strong></font></p>
<p><font id="4.11" size="2"><strong><br />
4.11 mkdir语法格式及参数；<br />
</strong></font></p>
<p><strong>语法格式</strong></p>
<p>
<div class="codeblock"><code>#mkdir [参数选项]&nbsp; 目录</code></div>
<p>&nbsp;</p>
<p><strong>参数常用的如下：</strong></p>
<p>-m 在创建目录时要授其权限，要和chmod的授权格式；<br />
-p 如果中间目录不存在，则创建它</p>
<p><font id="4.12" size="2"><strong><br />
4.12 参数 -p 的应用示例<br />
</strong></font></p>
<p>我们要创建一个目录linuxsir，并且linuxsir目录下包含子目录sirdoc，sirdoc目录下还有 redhat目录；</p>
<p>
<div class="codeblock"><code>[root@localhost ~]# mkdir -p&nbsp; linuxsir/sirdoc/redhat </code></div>
<p>&nbsp;</p>
<p><strong>举例：</strong> -m 参数的应用示例；</p>
<p>我们以不同的权限来创建目录，然后查看我们所创建目录的属性；这要涉及到chown 来改变目录的权限的格式。我们会在以后讲到chown改变目录或文件的权限。在这里不同的是，在目录创建之时就给其授权了；</p>
<p>
<div class="codeblock"><code>[root@localhost ~]# mkdir -m&nbsp; 644 sundir<br />
[root@localhost ~]# mkdir -m 755 moondir<br />
[root@localhost ~]# mkdir -m 000 beinandir<br />
[root@localhost ~]# ls -ld sundir moondir beinandir<br />
d--------- 2 root root 4096 04-20 11:01 beinandir <br />
drwxr-xr-x 2 root root 4096 04-20 11:01 moondir<br />
drw-r--r-- 2 root root 4096 04-20 11:00 sundir</code></div>
<p>&nbsp;</p>
<p><font id="4.2" size="3"><strong><br />
4.2 删除空目录工具 rmdir 和rm ；<br />
</strong></font></p>
<p>rmdir 是用来删除空目录用的，如果目录中有文件或子目录，必须先删除文件或子目录，其语法格式如下：</p>
<p>
<div class="codeblock"><code>#rmdir ［参数]&nbsp; 目录 </code></div>
<p>&nbsp;</p>
<p><strong><br />
rmdir 参数常用的有：<br />
</strong></p>
<p>-p 删除目录时是一级一级的时行的，值得注意的是，首先从最里面的目录开始。下面是一个例子；</p>
<p>
<div class="codeblock"><code>[root@localhost ~]# mkdir -p&nbsp; linuxsir/sirdoc/redhat/&nbsp; <br />
<br />
注：首先在当前目录下创建linuxsir目录，他的子目录是sirdoc，sirdoc内又有一个子目录redhat <br />
<br />
[root@localhost ~]# rmdir -p linuxsir/sirdoc/redhat/&nbsp; 注：删除linuxsir目录，要用到参数-p<br />
[root@localhost ~]# ls linuxsir&nbsp; 注：检查一下是不是还有这个目录？ <br />
ls: linuxsir: 没有那个文件或目录</code></div>
<p>&nbsp;</p>
<p>rmdir 所删除的目录，每级目录中都是空的，没有其它的文件。如果任何一级的目录有文件，也不能删除。这时您要用到rm -rf 命令强制删除。不过用rm -rf 删除时有点不安全，还是用rf -ri 比较好一点，因为在删除的时候，会有警告提示。这对于安全操作来说是很重要的；</p>
<p>
<div class="codeblock"><code>[root@localhost ~]# ls -lh sun/&nbsp; 注：这是sun目录，里面有内容；<br />
总计 28K<br />
-rw------- 1 root root 1.4K 04-19 15:04 anaconda-ks.cfg<br />
-rw-r--r-- 1 root root&nbsp;&nbsp;&nbsp; 2 04-20 10:24 fonts.dir<br />
-rw-r--r-- 1 root root&nbsp;&nbsp;&nbsp; 2 03-27 02:00 fonts.scale<br />
-rw-r--r-- 1 root root 5.3K 03-16 08:52 install.log.syslog<br />
-rw-r--r-- 1 root root&nbsp;&nbsp;&nbsp; 0 04-19 20:44 Kernel.rpm<br />
-rw-r--r-- 1 root root&nbsp;&nbsp;&nbsp; 0 04-20 10:20 Plist<br />
[root@localhost ~]# rmdir sun/&nbsp; 注：我们尝试用rmdir来删除，<br />
rmdir: sun/: 目录非空&nbsp;&nbsp; <br />
<br />
[root@localhost ~]# rm -rf sun/&nbsp; 注：强制用rm -rf 来删除；<br />
<br />
[root@localhost ~]# ls sun&nbsp;&nbsp;&nbsp; 注：检查是否删除，删除成功；<br />
ls: sun: 没有那个文件或目录</code></div>
<p>&nbsp;</p>
<p><font id="5" size="4"><strong><br />
5、创建一个空文件的工具：用 touch、echo、cat等工具；<br />
</strong></font></p>
<p>有时我们为了方便，可能在控制台或终端下创建一个不存在的空文件，然后我们再用编辑器来编辑它；创建空文件有时还有点用。说说也无妨。我们在这里用touch、ech0及cat 工具。其实这些工具，创建文件只是他们的一个小小的功能，我们以后再介绍这些工具，先说他们创建文件的功能。</p>
<p>注意：创建这些文件，在我们操作创建文件之前，这些文件在用户当前操作目录下是不存在的，我们在这里只是创建一个新的文件名，并且它里面没有任何空容的；</p>
<p>
<div class="codeblock"><code>[root@localhost ~]# ls 123456.txt 654321.txt 98765.txt<br />
ls: 123456.txt: 没有那个文件或目录<br />
ls: 654321.txt: 没有那个文件或目录<br />
ls: 98765.txt: 没有那个文件或目录</code></div>
<p>&nbsp;</p>
<p>
<div class="codeblock"><code>[root@localhost ~]# echo &gt; 123456.txt&nbsp; 注：用ech0 来创建，在创建之前在此操作目录下不存不123456.txt文件；<br />
[root@localhost ~]# ls 123456.txt&nbsp;&nbsp;&nbsp;&nbsp; 注：查看一下看有没有生成？<br />
123456.txt </code></div>
<p>&nbsp;</p>
<p>
<div class="codeblock"><code>[root@localhost ~]# touch 654321.txt&nbsp; 注：用 touch 来创建，在创建之前在此操作目录下不存在654321.txt文件；<br />
[root@localhost ~]# ls 654321.txt&nbsp; 注：查看一下看有没有生成？<br />
654321.txt</code></div>
<p>&nbsp;</p>
<p>
<div class="codeblock"><code>[root@localhost ~]# cat &gt; 98765.txt&nbsp; 注：用ech0 来创建，在创建之前在此操作目录下不存在98765.txt 文件；然后按ctrl+c组合键退出；<br />
<br />
[root@localhost ~]# ls 98765.txt&nbsp;&nbsp; 注：查看一下看有没有生成？<br />
98765.txt</code></div>
<p>&nbsp;</p>
<p><font id="6" size="4"><strong><br />
6、删除文件工具rm；<br />
</strong></font></p>
<p>rm 是用来删除一个或多个文件的工具，并且能用于删除非空目录。我们前面提到了可以加参数-rf 就可以强制删除一个非空目录。</p>
<p><strong>rm的语法格式；</strong></p>
<p>
<div class="codeblock"><code>#rm ［参数选项］ file1 file2 ... ... <br />
#rm&nbsp; ［参数选项]&nbsp; dir1 dir2 dir3 ... ...</code></div>
<p>&nbsp;</p>
<p><strong>rm 常用参数：</strong></p>
<p>
<div class="codeblock"><code>-f&nbsp; 不显示警告或提示信息就删除，用的时候需要小心；<br />
-i&nbsp; 删除文件时，显示警告信息，要多用，这样比较安全；根据提示，输入y就表示删除，输入n，请示不删除；<br />
-r或-R&nbsp; 表示可以删除整个目录（包括子目录及所有文件），要小心用；</code></div>
<p>&nbsp;</p>
<p>
<div class="codeblock"><code>[root@localhost ~]# rm -i 123.sh&nbsp; 注：这是删除一个文件，用-i参数的示例，有警告提示；<br />
<br />
rm：是否删除一般空文件&#8220;123.sh&#8221;? y</code></div>
<p>&nbsp;</p>
<p>比如我们想删除mydir目录及所有下级目录和文件，要有提示的警告信息，可以用-r参数和-i参数的组合；如果您想终止rm命令，请按ctrl+c组合健退出rm；</p>
<p>
<div class="codeblock"><code>[root@localhost ~]# rm -ri mydir/<br />
<br />
rm：是否进入目录&#8220;mydir/&#8221;? y<br />
rm：是否进入目录&#8220;mydir//youdir&#8221;? y<br />
rm：是否删除一般文件&#8220;mydir//youdir/enteruml.sh&#8221;?</code></div>
<p>&nbsp;</p>
<p>如果您想没有任何警告信息的删除mydir目录下的所有文件及子目录，可以用-r和-f参数的组合；</p>
<p>
<div class="codeblock"><code>[root@localhost ~]# rm -rf mydir</code></div>
<p>&nbsp;</p>
<p><font id="7" size="4"><strong><br />
7、修改文件名工具 mv<br />
</strong></font></p>
<p>mv 可以移动一个文件（或目录）到另一个文件（或目录），如果文件（或目录）不存在，则创建它。其实mv 这个过程也可以理解为改名过程，所以说mv工具能修改文件名和目录名。</p>
<p>
<div class="codeblock"><code>#mv 原文件名或目录名&nbsp; 新文件或目录名 </code></div>
<p>&nbsp;</p>
<p><strong>注意：</strong>新文件名或目录名应该不能与现有文件名（或目录名）同名。</p>
<p><strong>举例：</strong></p>
<p>
<div class="codeblock"><code>[root@localhost ~]# ls<br />
crondw.sh&nbsp; kernel&nbsp; mkuml-2004.07.17-ananas.tar.bz2&nbsp; mydir&nbsp; openQreadme.txt&nbsp; sun.txt&nbsp; upgrade.log&nbsp; youdir<br />
<br />
[root@localhost ~]# mv crondw.sh 123.sh&nbsp; 注：移动crondw.sh 到123.sh ，其实就是把文件名改为了123.sh<br />
<br />
[root@localhost ~]# ls<br />
123.sh&nbsp; kernel&nbsp; mkuml-2004.07.17-ananas.tar.bz2&nbsp; mydir&nbsp; openQreadme.txt&nbsp; sun.txt&nbsp; upgrade.log&nbsp; youdir<br />
</code></div>
<p>&nbsp;</p>
<p>再看一例mv 修改目录的。当然mv是把文件（或目录）从一个地方移到另一个地方。如果另一地方没有和源文件（或目录）同名的，就创建。这也相当于改名；</p>
<p>
<div class="codeblock"><code>[root@localhost ~]# ls<br />
123.sh&nbsp; kernel&nbsp; mkuml-2004.07.17-ananas.tar.bz2&nbsp; mydir&nbsp; openQreadme.txt&nbsp; sun.txt&nbsp; upgrade.log&nbsp; youdir<br />
<br />
[root@localhost ~]# mv kernel/ kernelBak<br />
<br />
[root@localhost ~]# ls<br />
123.sh&nbsp; kernelBak&nbsp; mkuml-2004.07.17-ananas.tar.bz2&nbsp; mydir&nbsp; openQreadme.txt&nbsp; sun.txt&nbsp; upgrade.log&nbsp; youdir</code></div>
<img src ="http://www.blogjava.net/joan/aggbug/233124.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/joan/" target="_blank">joan</a> 2008-10-08 13:31 <a href="http://www.blogjava.net/joan/articles/233124.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>设置vi/vim实现打开不同字符编码的文件</title><link>http://www.blogjava.net/joan/articles/233066.html</link><dc:creator>joan</dc:creator><author>joan</author><pubDate>Wed, 08 Oct 2008 02:07:00 GMT</pubDate><guid>http://www.blogjava.net/joan/articles/233066.html</guid><wfw:comment>http://www.blogjava.net/joan/comments/233066.html</wfw:comment><comments>http://www.blogjava.net/joan/articles/233066.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/joan/comments/commentRss/233066.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/joan/services/trackbacks/233066.html</trackback:ping><description><![CDATA[<p>1&gt;说明：<br />
默认vi/vim会根据terminal的locale设置，使用相应的字符编码。<br />
如：<br />
# locale<br />
LANG=en_US.UTF-8<br />
LC_CTYPE=zh_CN.UTF-8<br />
LC_NUMERIC="en_US.UTF-8"<br />
LC_TIME="en_US.UTF-8"<br />
LC_COLLATE="en_US.UTF-8"<br />
LC_MONETARY="en_US.UTF-8"<br />
LC_MESSAGES="en_US.UTF-8"<br />
LC_PAPER="en_US.UTF-8"<br />
LC_NAME="en_US.UTF-8"<br />
LC_ADDRESS="en_US.UTF-8"<br />
LC_TELEPHONE="en_US.UTF-8"<br />
LC_MEASUREMENT="en_US.UTF-8"<br />
LC_IDENTIFICATION="en_US.UTF-8"<br />
LC_ALL=<br />
# vim<br />
查看默认的字符编码<br />
:set fileencodings<br />
fileencodings=utf-8,latin1 <br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <br />
2&gt;实现<br />
知道了上面这些，当我们在打开一个其它编码的文件时，只要先设置一下vi/vim的fileencodings值就可以了。<br />
(1)动态设置实现<br />
# vim<br />
:set fileencodings gb2312,utf-8<br />
多个字符编码以&#8220;，&#8221;隔开。<br />
(2)配置文件静态设置实现<br />
配置一下vi/vim的配置文件：<br />
vi ~/.vimrc<br />
set fileencodings=utf-8,gb2312</p>
<img src ="http://www.blogjava.net/joan/aggbug/233066.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/joan/" target="_blank">joan</a> 2008-10-08 10:07 <a href="http://www.blogjava.net/joan/articles/233066.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>ls命令选项详解</title><link>http://www.blogjava.net/joan/articles/232889.html</link><dc:creator>joan</dc:creator><author>joan</author><pubDate>Tue, 07 Oct 2008 04:41:00 GMT</pubDate><guid>http://www.blogjava.net/joan/articles/232889.html</guid><wfw:comment>http://www.blogjava.net/joan/comments/232889.html</wfw:comment><comments>http://www.blogjava.net/joan/articles/232889.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/joan/comments/commentRss/232889.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/joan/services/trackbacks/232889.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ls 命令可以说是Linux下最常用的命令之一。它有众多的选项，其中有很多是很有用的，你是否熟悉呢？下面列出了 ls 命令的绝大多数选项。<br />
<br />
　　-a 列出目录下的所有文件，包括以 . 开头的隐含文件。<br />
<br />
　　-b 把文件名中不可输出的字符用反斜杠加字符编号(就象在C语言里一样)的形式列出。<br />
<br />
　　-c 输出文件的 i 节点的修改时间，并以此排序。<br />
<br />
　　-d 将目录象文件一样显示，而不是显示其下的文件。<br />
<br />
　　-e 输出时间的全部信息，而不是输出简略信息。<br />
<br />
　　-f -U 对输出的文件不排序。<br />
<br />
　　-g 无用。<br />
<br />
　　-i 输出文件的 i 节点的索引信息。<br />
<br />
　　-k 以 k 字节的形式表示文件的大小。<br />
<br />
　　-l 列出文件的详细信息。<br />
<br />
　　-m 横向输出文件名，并以&#8220;，&#8221;作分格符。<br />
<br />
　　-n 用数字的 UID,GID 代替名称。<br />
<br />
　　-o 显示文件的除组信息外的详细信息。<br />
<br />
　　-p -F 在每个文件名后附上一个字符以说明该文件的类型，&#8220;*&#8221;表示可执行的普通<br />
<br />
　　文件；&#8220;/&#8221;表示目录；&#8220;@&#8221;表示符号链接；&#8220;|&#8221;表示FIFOs；&#8220;=&#8221;表示套<br />
<br />
　　接字(sockets)。<br />
<br />
　　-q 用?代替不可输出的字符。<br />
<br />
　　-r 对目录反向排序。<br />
<br />
　　-s 在每个文件名后输出该文件的大小。<br />
<br />
　　-t 以时间排序。<br />
<br />
　　-u 以文件上次被访问的时间排序。<br />
<br />
　　-x 按列输出，横向排序。<br />
<br />
　　-A 显示除 &#8220;.&#8221;和&#8220;..&#8221;外的所有文件。<br />
<br />
　　-B 不输出以 &#8220;~&#8221;结尾的备份文件。<br />
<br />
　　-C 按列输出，纵向排序。<br />
<br />
　　-G 输出文件的组的信息。<br />
<br />
　　-L 列出链接文件名而不是链接到的文件。<br />
<br />
　　-N 不限制文件长度。<br />
<br />
　　-Q 把输出的文件名用双引号括起来。<br />
<br />
　　-R 列出所有子目录下的文件。<br />
<br />
　　-S 以文件大小排序。<br />
<br />
　　-X 以文件的扩展名(最后一个 . 后的字符)排序。<br />
<br />
　　-1 一行只输出一个文件。<br />
<br />
　　--color=no 不显示彩色文件名<br />
<br />
　　--help 在标准输出上显示帮助信息。<br />
<br />
　　--version 在标准输出上输出版本信息并退出。
    <img src ="http://www.blogjava.net/joan/aggbug/232889.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/joan/" target="_blank">joan</a> 2008-10-07 12:41 <a href="http://www.blogjava.net/joan/articles/232889.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Shell 符号(载录)</title><link>http://www.blogjava.net/joan/articles/232856.html</link><dc:creator>joan</dc:creator><author>joan</author><pubDate>Tue, 07 Oct 2008 02:51:00 GMT</pubDate><guid>http://www.blogjava.net/joan/articles/232856.html</guid><wfw:comment>http://www.blogjava.net/joan/comments/232856.html</wfw:comment><comments>http://www.blogjava.net/joan/articles/232856.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/joan/comments/commentRss/232856.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/joan/services/trackbacks/232856.html</trackback:ping><description><![CDATA[<h2>Shell 符号</h2>
<div class="t_msgfont" id="postmessage_69605">　　针对许多频繁使用的<span class="t_tag" onclick="tagshow(event)" href="tag.php?name=%C3%FC%C1%EE">命令</span>行参数，Shell 提供了相应的符号 或记号作为简写。您只需输入这些符号来代替相应的参数。<br />
<br />
　　如上所述，~ 表示您的 home 目录。与之类似的简写形式 ~username 表示 username 的 home 目录。例如，~joe 表示 joe 的 home 目录，所以，要将<span class="t_tag" onclick="tagshow(event)" href="tag.php?name=%CE%C4%BC%FE">文件</span>从 joe 的 doc 目录复制到您的 info 目录，您可以输入下面的命令：
<div class="blockcode">
<h5>代码:</h5>
<code id="code0">$ cp ~joe/doc/report.txt ~/info</code></div>
　　假设 joe 的 home 目录位于 /guests，而您的 home 目录为 /staff/bobr，~joe 将由 /guests/joe 替换，而 ~ 则变成 /staff/bobr，最后产生命令 cp /guests/joe/doc/report.txt /staff/bobr/info。<br />
<br />
　　另一个有用的符号是 ..（两个点号），这是当前目录的父目录的简写。使用 .. 和 .（当前工作目录的简写符号），您可以引用文件<span class="t_tag" onclick="tagshow(event)" href="tag.php?name=%CF%B5%CD%B3">系统</span>中相对于当前工作目录的文件和目录。<br />
<br />
　　例如，如果您的当前工作目录为 ~/jane/projects/lambda，那么简写 ../.. 表示向上两级目录的目录，即 ~/jane。要表示包含 ~/jane 的目录，您可以使用 ../../../（&#8220;向上三级目录&#8221;）或路径 ~jane/../。后面的这个路径表示从 ~jane 开始，然后转到上一级目录。<br />
<br />
　　要将文件复制到您的当前目录，不需要指定目标目录，可以直接使用 .（&#8220;点&#8221;）来表示：
<div class="blockcode">代码:<code id="code1">$ cp -pr /path/to/lots/of/stuff</code></div>
　　前面的命令将 /path/to/lots/of/stuff 目录递归地复制到您的当前目录，并保持其原始的时间和日期戳。引用 .. 和 . 的路径名称为相对路径名。以 /（正斜杠）或 ~（波浪符号）开头的路径名称为绝对路径名，因为您是从文件系统的顶端、或从一个目录层次结构的顶端开始来引用相应的文件。<br />
<br />
<strong>用波浪号快速修改输错的命令 <br />
</strong><br />
假如打错了一个很长的命令，需要重新输入是十分沮丧的事情。例如：<br />
<br />
　　$ find . -naem "*.txt" -print<br />
<br />
　　的例子中，name 被错误的输成了 naem ，我们能够用下面的波浪符号来替换：<br />
<br />
　　$ ^em^me^<br />
<br />
　　find . -name "*.txt" -print<br />
<br />
<br />
<strong>检验您的工作</strong><br />
<br />
　　如果您想要查看命令行符号扩展后的结果，可以使用 echo 命令：
<div class="blockcode">代码:<code id="code2">$ echo ~joe/doc/report.txt ~/info<br />
/guests/joe/doc/report.txt /staff/bobr/info<br />
<br />
$ echo $SHELL<br />
/bin/zsh<br />
<br />
$ ls<br />
architecture.txt&nbsp;&nbsp;Services.pdf<br />
services.txt&nbsp; &nbsp;&nbsp; &nbsp;Schema.pdf<br />
<br />
$ echo *.txt<br />
architecture.txt services.txt</code></div>
　　echo 命令将完整地表达您在命令行中输入的内容。然而，因为 Shell 会在调用任何程序之前，对（大多数）命令行参数进行扩展，所以该命令将打印出所有替换的结果。（Shell 环境变量 $SHELL 包含当前正在运行的 Shell 的名称。）<br />
<br />
<br />
</div>
<img src ="http://www.blogjava.net/joan/aggbug/232856.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/joan/" target="_blank">joan</a> 2008-10-07 10:51 <a href="http://www.blogjava.net/joan/articles/232856.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Linux内核代码构架图</title><link>http://www.blogjava.net/joan/articles/232652.html</link><dc:creator>joan</dc:creator><author>joan</author><pubDate>Mon, 06 Oct 2008 06:07:00 GMT</pubDate><guid>http://www.blogjava.net/joan/articles/232652.html</guid><wfw:comment>http://www.blogjava.net/joan/comments/232652.html</wfw:comment><comments>http://www.blogjava.net/joan/articles/232652.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.blogjava.net/joan/comments/commentRss/232652.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/joan/services/trackbacks/232652.html</trackback:ping><description><![CDATA[<p>&nbsp;</p>
<img height="1536" alt="" src="http://www.testage.net/attachments/2008/04/8_200804251414031acVI.jpg" width="2048" border="0" />
<img src ="http://www.blogjava.net/joan/aggbug/232652.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/joan/" target="_blank">joan</a> 2008-10-06 14:07 <a href="http://www.blogjava.net/joan/articles/232652.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>构建linux下IDE环境--Eclipse篇</title><link>http://www.blogjava.net/joan/articles/232598.html</link><dc:creator>joan</dc:creator><author>joan</author><pubDate>Mon, 06 Oct 2008 01:44:00 GMT</pubDate><guid>http://www.blogjava.net/joan/articles/232598.html</guid><wfw:comment>http://www.blogjava.net/joan/comments/232598.html</wfw:comment><comments>http://www.blogjava.net/joan/articles/232598.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/joan/comments/commentRss/232598.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/joan/services/trackbacks/232598.html</trackback:ping><description><![CDATA[<table cellspacing="0" cellpadding="0" width="90%" align="center" border="0">
    <tbody>
        <tr>
            <th class="f24">
            <h1><span style="color: #000000"><span style="color: #003366">构建linux下IDE环境--Eclipse篇</span></span></h1>
            </th>
        </tr>
        <tr>
            <td align="center" height="20"><span style="color: #000000"></span></td>
        </tr>
        <tr>
            <td><span style="color: #000000"><br />
            </span></td>
        </tr>
        <tr>
            <td class="l17"><font class="f14" id="zoom"><font color="#cccccc"><!-- 正文begin --><!--startfragment --><span style="color: #000000"><span style="color: #003366">&nbsp;<br />
            <!-- message --></span></span>
            <div><span style="color: #000000"><span style="color: #003366">摘要 <br />
            <br />
            Eclipse是一由ibm，borland等资助的开源开发环境；其功能可以通过插件方式进行扩展；本文在linux下构建java、c、c＋＋的IDE。 <br />
            <br />
            我用的环境是 red hat linux 9 （自编译gnome2.4） <br />
            <br />
            一：下载所需软件（所有下载的软件均放在/opt下） <br />
            <br />
            先下载 Eclipse，网址为 </span></span><a href="http://www.eclipse.org/" target="_blank"><span style="color: #000000"><span style="color: #003366">http://www.eclipse.org</span></span></a><span style="color: #000000"><span style="color: #003366"> 目前，Eclipse的最新版本为2.1.1，3.0版也正在测试中。我使用eclipse2.1；下载其gtk版本：eclipse-SDK-2.1.1-linux-gtk.zip <br />
            <br />
            执行 Eclipse是须用到JDK，但Eclipse的安装程序和Red Hat Linux 9 里没有包含JDK，Sun 最新版本的 JDK可到 </span></span><a href="http://java.sun.com%e4%b8%8b%e8%bd%bd%ef%bc%8c%e5%9c%a8%e6%ad%a4%e6%88%91%e4%bb%ac%e4%bd%bf%e7%94%a8%e7%9a%84%e6%98%afsun/" target="_blank"><span style="color: #000000"><span style="color: #003366">http://java.sun.com下载，在此我们使用的是sun</span></span></a><span style="color: #000000"><span style="color: #003366"> jdk (J2SE) 1.4.2_01版（也可使用IBM的jdk）。 <br />
            <br />
            要在Eclipse 上面开发C/C++程序，需要另外安装plug-ins，在此我们使用的是C/C++ Development Tools（CDT）。CDT 整合了gcc、make、gdb等GUN 工具，（CDT 与Eclipse 中内建的JDT（Java 开发环境）比起来，功能还差得远。例如，在JDT 中相当好用的Refactor、Refactoring、Organize Imports等在CDT 中都没有。）CDT 可从</span></span><a href="http://www.eclipse.org/cdt/" target="_blank"><span style="color: #000000"><span style="color: #003366">http://www.eclipse.org/cdt/</span></span></a><span style="color: #000000"><span style="color: #003366"> 下载，目前最新版本为CDT 1.1 GA2 . <br />
            <br />
            二 ：安装 <br />
            <br />
            1.由于cdt需要gcc等工具，所以要先把red hat9的软件开发包装上， <br />
            <br />
            2.安装JDK（需以root身分安装）： <br />
            <br />
            [root@redarmy] chmod ＋x j2sdk-1_4_2_01-linux-i586-rpm.bin<br />
            [root@redarmy] ./j2sdk-1_4_2_01-linux-i586-rpm.bin<br />
            [root@redarmy] rpm &#8211;ivh j2sdk-1_4_2_01-linux-i586-rpm.bin<br />
            <br />
            <br />
            <br />
            安装好的JDK 会存在 /usr/java/j2sdk1.4.2_01 目录中。 <br />
            <br />
            设定JAVA_HOME,CLASSPATH,PATH; 在/etc/profile文件最后加如下四行： <br />
            <br />
            export JAVA_HOME = /usr/java/j2sdk1.4.2_01 <br />
            export PATH = $JAVA_HOME/bin:$PATH<br />
            CLASSPATH=.:/usr/java/j2sdk1.4.2_01/lib/tools.jar:$CLASSPATH<br />
            export CLASSPATH<br />
            <br />
            <br />
            <br />
            3.安裝Eclipse <br />
            <br />
            在此我把Eclipse安装在 /opt 下，安装Eclipse很简单，只要把下载回来的压缩包解压就可以了；解压后得到eclipse目录； <br />
            <br />
            [root@redarmy] unzip &#8211;d /opt eclipse-SDK-2.1.1-linux-gtk.zip <br />
            <br />
            为让每一个帐号都可以执行Eclipse，我写了个小脚本（eclipse.sh）： <br />
            <br />
            #!/bin/bash<br />
            #<br />
            # 执行 eclipse 2.1.1 <br />
            #<br />
            export JAVA_HOME=/usr/java/j2sdk1.4.2_01<br />
            export CLASSPATH=/usr/java/j2sdk1.4.2_01/lib<br />
            /opt/eclipse/eclipse -vm /usr/java/j2sdk1.4.2_01/bin/java -data ~/workspace &amp;<br />
            # -vm 参数用以指定使用哪一个 jvm 来执行Eclipse，<br />
            # -date参数用以指定Eclipse的数据目录。在此指定其存在用户根目录(~)下的workspace目录中<br />
            <br />
            <br />
            <br />
            将eclipse.sh 复制到/usr/local/bin中，并为它加上权限755；现在执行 eclipse.sh 即可启动 Eclipse。 <br />
            <br />
            [root@redarmy] cp eclipse.sh /usr/local/bin<br />
            [root@redarmy] chmod 755 /usr/local/bin/eclipse.sh<br />
            <br />
            <br />
            <br />
            将eclipse添加到桌面。首先，在桌面上按下鼠标右键，在弹出菜单中选择&#8220;新增启动&#8221;，之后分別在&#8220;名称&#8221;中输入Eclipse、&#8220;命令&#8221;中填 /usr/local/bin/eclipse.sh，然后再为它随便找个喜欢的图标（我用的是/opt/eclipse/icon.xpm）;再后按 &#8220;确定&#8221;，桌面上就有eclipse的快捷方式了，以后可以直接双击这个图标启动Eclipse。 <br />
            <br />
            Eclipse 安装好后，已经内建了java开发环境（JDT）就可以直接开发Java 程序。 <br />
            <br />
            4.安装cdt，CDT 1.1 GA 目前只支持Eclipse 2.1 版。 <br />
            <br />
            将下载的包解压，会得到features 和plugins 这两个目录 <br />
            <br />
            [root@redarmy] unzip &#8211;d /opt org.eclipse.cdt-linux.gtk_1.1.0.bin.dist.zip <br />
            <br />
            分别将这两个目录中的所有文件分别剪到/opt/eclipse下的对应目录里，即可。（Eclipse 的插件安裝方法几乎都这样安装： 把文件下载后， 直接解到eclipse所安装的目录中对应的features 和plugins 中即可。） <br />
            <br />
            三：附 <br />
            <br />
            要是不习惯，eclipse英文环境，可以在eclipse.org的主站上下，它的语言包；装了语言包后，不光菜单成中文了，它的帮助文档也成中文了，爽吧^_^ </span></span></div>
            <!-- 正文end --><br />
            <span style="color: #000000"><span style="color: #003366">(http://www.fanqiang.com)<br />
            </span></span></font></font></td>
        </tr>
    </tbody>
</table>
  <img src ="http://www.blogjava.net/joan/aggbug/232598.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/joan/" target="_blank">joan</a> 2008-10-06 09:44 <a href="http://www.blogjava.net/joan/articles/232598.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Linux 2.6 中的文件锁</title><link>http://www.blogjava.net/joan/articles/214335.html</link><dc:creator>joan</dc:creator><author>joan</author><pubDate>Fri, 11 Jul 2008 13:31:00 GMT</pubDate><guid>http://www.blogjava.net/joan/articles/214335.html</guid><wfw:comment>http://www.blogjava.net/joan/comments/214335.html</wfw:comment><comments>http://www.blogjava.net/joan/articles/214335.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/joan/comments/commentRss/214335.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/joan/services/trackbacks/214335.html</trackback:ping><description><![CDATA[<p>&nbsp;&nbsp;&nbsp;&nbsp; 本文的目的是想帮助读者理清 Linux 2.6中文件锁的概念以及 Linux 2.6 都提供了何种数据结构以及关键的系统调用来实现文件锁，从而可以帮助读者更好地使用文件锁来解决多个进程读取同一个文件的互斥问题。本文主要描述了 Linux 中各类文件锁的概念，使用场景，内核中描述文件锁的数据结构以及与文件锁密切相关的系统调用等内容。</p>
<!--start RESERVED FOR FUTURE USE INCLUDE FILES--><!-- include java script once we verify teams wants to use this and it will work on dbcs and cyrillic characters --><!--end RESERVED FOR FUTURE USE INCLUDE FILES-->
<p>在多任务操作系统环境中，如果一个进程尝试对正在被其他进程读取的文件进行写操作，可能会导致正在进行读操作的进程读取到一些被破坏或者不完整的数据；如果两个进程并发对同一个文件进行写操作，可能会导致该文件遭到破坏。因此，为了避免发生这种问题，必须要采用某种机制来解决多个进程并发访问同一个文件时所面临的同步问题，由此而产生了文件加锁方面的技术。</p>
<p>早期的 UNIX 系统只支持对整个文件进行加锁，因此无法运行数据库之类的程序，因为此类程序需要实现记录级的加锁。在 System V Release 3 中，通过 fcntl 提供了记录级的加锁，此后发展成为 POSIX 标准的一部分。本文将基于 2.6.23 版本的内核来探讨 Linux 中文件锁的相关技术。</p>
<p><a name="Linux 中的文件锁"><span class="atitle">Linux 中的文件锁</span></a></p>
<p>Linux 支持的文件锁技术主要包括劝告锁（advisory lock）和强制锁（mandatory lock）这两种。此外，Linux 中还引入了两种强制锁的变种形式：共享模式强制锁（share-mode mandatory lock）和租借锁（lease）。</p>
<p>在 Linux 中，不论进程是在使用劝告锁还是强制锁，它都可以同时使用共享锁和排他锁（又称为读锁和写锁）。多个共享锁之间不会相互干扰，多个进程在同一时刻可以对同一个文件加共享锁。但是，如果一个进程对该文件加了排他锁，那么其他进程则无权再对该文件加共享锁或者排他锁，直到该排他锁被释放。所以，对于同一个文件来说，它可以同时拥有很多读者，但是在某一特定时刻，它只能拥有一个写者，它们之间的兼容关系如表 1 所示。</p>
<br />
<a name="表 1. 锁间的兼容关系"><strong>表 1. 锁间的兼容关系</strong></a><br />
<table class="data-table-1" cellspacing="0" cellpadding="0" border="0">
    <tbody>
        <tr>
            <td style="vertical-align: top">
            <td style="vertical-align: top; text-align: center" colspan="2"><strong>是否满足请求</strong> </td>
        </tr>
        <tr>
            <td style="vertical-align: top; text-align: center"><strong>当前加上的锁</strong> </td>
            <td style="vertical-align: top; text-align: center">共享锁 </td>
            <td style="vertical-align: top; text-align: center">排他锁 </td>
        </tr>
        <tr>
            <td style="vertical-align: top; text-align: center">无 </td>
            <td style="vertical-align: top; text-align: center">是 </td>
            <td style="vertical-align: top; text-align: center">是 </td>
        </tr>
        <tr>
            <td style="vertical-align: top; text-align: center">共享锁 </td>
            <td style="vertical-align: top; text-align: center">是 </td>
            <td style="vertical-align: top; text-align: center">否 </td>
        </tr>
        <tr>
            <td style="vertical-align: top; text-align: center">排他锁 </td>
            <td style="vertical-align: top; text-align: center">否 </td>
            <td style="vertical-align: top; text-align: center">否 </td>
        </tr>
    </tbody>
</table>
<br />
<p><a name="劝告锁"><span class="smalltitle">劝告锁</span></a></p>
<p>劝告锁是一种协同工作的锁。对于这一种锁来说，内核只提供加锁以及检测文件是否已经加锁的手段，但是内核并不参与锁的控制和协调。也就是说，如果有进程不遵守&#8220;游戏规则&#8221;，不检查目标文件是否已经由别的进程加了锁就往其中写入数据，那么内核是不会加以阻拦的。因此，劝告锁并不能阻止进程对文件的访问，而只能依靠各个进程在访问文件之前检查该文件是否已经被其他进程加锁来实现并发控制。进程需要事先对锁的状态做一个约定，并根据锁的当前状态和相互关系来确定其他进程是否能对文件执行指定的操作。从这点上来说，劝告锁的工作方式与使用信号量保护临界区的方式非常类似。</p>
<p>劝告锁可以对文件的任意一个部分进行加锁，也可以对整个文件进行加锁，甚至可以对文件将来增大的部分也进行加锁。由于进程可以选择对文件的某个部分进行加锁，所以一个进程可以获得关于某个文件不同部分的多个锁。</p>
<p><a name="强制锁"><span class="smalltitle">强制锁</span></a></p>
<p>与劝告锁不同，强制锁是一种内核强制采用的文件锁，它是从 System V Release 3 开始引入的。每当有系统调用 open()、read() 以及write() 发生的时候，内核都要检查并确保这些系统调用不会违反在所访问文件上加的强制锁约束。也就是说，如果有进程不遵守游戏规则，硬要往加了锁的文件中写入内容，内核就会加以阻拦：</p>
<p>如果一个文件已经被加上了读锁或者共享锁，那么其他进程再对这个文件进行写操作就会被内核阻止；</p>
<p>如果一个文件已经被加上了写锁或者排他锁，那么其他进程再对这个文件进行读取或者写操作就会被内核阻止。</p>
<p>如果其他进程试图访问一个已经加有强制锁的文件，进程行为取决于所执行的操作模式和文件锁的类型，归纳如表 2 所示：</p>
<br />
<a name="表 2. 进行对已加强制锁的文件进行操作时的行为"><strong>表 2. 进行对已加强制锁的文件进行操作时的行为</strong></a><br />
<table class="data-table-1" cellspacing="0" cellpadding="0" border="0">
    <tbody>
        <tr>
            <td style="vertical-align: top; text-align: center">当前锁类型 </td>
            <td style="vertical-align: top; text-align: center">阻塞读 </td>
            <td style="vertical-align: top; text-align: center">阻塞写 </td>
            <td style="vertical-align: top; text-align: center">非阻塞读 </td>
            <td style="vertical-align: top; text-align: center">非阻塞写 </td>
        </tr>
        <tr>
            <td style="vertical-align: top; text-align: center">读锁 </td>
            <td style="vertical-align: top; text-align: center">正常读取数据 </td>
            <td style="vertical-align: top; text-align: center">阻塞 </td>
            <td style="vertical-align: top; text-align: center">正常读取数据 </td>
            <td style="vertical-align: top; text-align: center">EAGAIN </td>
        </tr>
        <tr>
            <td style="vertical-align: top; text-align: center">写锁 </td>
            <td style="vertical-align: top; text-align: center">阻塞 </td>
            <td style="vertical-align: top; text-align: center">阻塞 </td>
            <td style="vertical-align: top; text-align: center">EAGAIN </td>
            <td style="vertical-align: top; text-align: center">EAGAIN </td>
        </tr>
    </tbody>
</table>
<br />
<p>需要注意的是，如果要访问的文件的锁类型与要执行的操作存在冲突，那么采用阻塞读/写操作的进程会被阻塞，而采用非阻塞读/写操作的进程则不会阻塞，而是立即返回 EAGAIN。</p>
<p>另外，unlink() 系统调用并不会受到强制锁的影响，原因在于一个文件可能存在多个硬链接，此时删除文件时并不会修改文件本身的内容，而是只会改变其父目录中 dentry 的内容。</p>
<p>然而，在有些应用中并不适合使用强制锁，所以索引节点结构中的 i_flags 字段中定义了一个标志位MS_MANDLOCK用于有选择地允许或者不允许对一个文件使用强制锁。在 super_block 结构中，也可以将 s_flags 这个标志为设置为1或者0，用以表示整个设备上的文件是否允许使用强制锁。</p>
<p>要想对一个文件采用强制锁，必须按照以下步骤执行：</p>
<p>使用 -o mand 选项来挂载文件系统。这样在执行 mount() 系统调用时，会传入 MS_MANDLOCK 标记，从而将 super_block 结构中的 s_flags 设置为 1，用来表示在这个文件系统上可以采用强制锁。例如：</p>
<table cellspacing="0" cellpadding="0" width="100%" border="0">
    <tbody>
        <tr>
            <td class="code-outline">
            <pre class="displaycode"># mount -o mand /dev/sdb7 /mnt
            # mount | grep mnt
            /dev/sdb7 on /mnt type ext3 (rw,mand)
            </pre>
            </td>
        </tr>
    </tbody>
</table>
<br />
<p>1.修改要加强制锁的文件的权限：设置 SGID 位，并清除组可执行位。这种组合通常来说是毫无意义的，系统用来表示该文件被加了强制锁。例如：</p>
<table cellspacing="0" cellpadding="0" width="100%" border="0">
    <tbody>
        <tr>
            <td class="code-outline">
            <pre class="displaycode"># touch /mnt/testfile
            # ls -l /mnt/testfile
            -rw-r--r-- 1 root root 0 Jun 22 14:43 /mnt/testfile
            # chmod g+s /mnt/testfile
            # chmod g-x /mnt/testfile
            # ls -l /mnt/testfile
            -rw-r-Sr-- 1 root root 0 Jun 22 14:43 /mnt/testfile
            </pre>
            </td>
        </tr>
    </tbody>
</table>
<br />
<p>2.使用 fcntl() 系统调用对该文件进行加锁或解锁操作。</p>
<p><strong><em>1.3. 共享模式锁</em> </strong></p>
<p>Linux 中还引入了两种特殊的文件锁：共享模式强制锁和租借锁。这两种文件锁可以被看成是强制锁的两种变种形式。共享模式强制锁可以用于某些私有网络文件系统，如果某个文件被加上了共享模式强制锁，那么其他进程打开该文件的时候不能与该文件的共享模式强制锁所设置的访问模式相冲突。但是由于可移植性不好，因此并不建议使用这种锁。</p>
<p><a name="租借锁"><span class="smalltitle">租借锁</span></a></p>
<p>采用强制锁之后，如果一个进程对某个文件拥有写锁，只要它不释放这个锁，就会导致访问该文件的其他进程全部被阻塞或不断失败重试；即使该进程只拥有读锁，也会造成后续更新该文件的进程的阻塞。为了解决这个问题，Linux 中采用了一种新型的租借锁。</p>
<p>当进程尝试打开一个被租借锁保护的文件时，该进程会被阻塞，同时，在一定时间内拥有该文件租借锁的进程会收到一个信号。收到信号之后，拥有该文件租借锁的进程会首先更新文件，从而保证了文件内容的一致性，接着，该进程释放这个租借锁。如果拥有租借锁的进程在一定的时间间隔内没有完成工作，内核就会自动删除这个租借锁或者将该锁进行降级，从而允许被阻塞的进程继续工作。</p>
<p>系统默认的这段间隔时间是 45 秒钟，定义如下：</p>
<table cellspacing="0" cellpadding="0" width="100%" border="0">
    <tbody>
        <tr>
            <td class="code-outline">
            <pre class="displaycode">		137 int lease_break_time = 45;
            </pre>
            </td>
        </tr>
    </tbody>
</table>
<br />
<p>这个参数可以通过修改 /proc/sys/fs/lease-break-time 进行调节（当然，/proc/sys/fs/leases-enable 必须为 1 才行）。</p>
<br />
<table cellspacing="0" cellpadding="0" width="100%" border="0">
    <tbody>
        <tr>
            <td><img height="1" alt="" src="http://www.ibm.com/i/v14/rules/blue_rule.gif" width="100%" /><br />
            <img height="6" alt="" src="http://www.ibm.com/i/c.gif" width="8" border="0" /></td>
        </tr>
    </tbody>
</table>
<br />
<br />
<p><a name="Linux 内核中关于文件锁的实现"><span class="atitle">Linux 内核中关于文件锁的实现</span></a></p>
<p>在 Linux 内核中，所有类型的文件锁都是由数据结构 file_lock 来描述的，file_lock 结构是在 文件中定义的，内容如下所示：</p>
<br />
<a name="清单 1. file_lock 结构"><strong>清单 1. file_lock 结构</strong></a><br />
<table cellspacing="0" cellpadding="0" width="100%" border="0">
    <tbody>
        <tr>
            <td class="code-outline">
            <pre class="displaycode">            811 struct file_lock {
            812         struct file_lock *fl_next;      /* singly linked list for this inode  */
            813         struct list_head fl_link;       /* doubly linked list of all locks */
            814         struct list_head fl_block;      /* circular list of blocked processes */
            815         fl_owner_t fl_owner;
            816         unsigned int fl_pid;
            817         wait_queue_head_t fl_wait;
            818         struct file *fl_file;
            819         unsigned char fl_flags;
            820         unsigned char fl_type;
            821         loff_t fl_start;
            822         loff_t fl_end;
            823
            824         struct fasync_struct *  fl_fasync; /* for lease break notifications */
            825         unsigned long fl_break_time;    /* for nonblocking lease breaks */
            826
            827         struct file_lock_operations *fl_ops;    /* Callbacks for filesystems */
            828      struct lock_manager_operations *fl_lmops;       /* Callbacks for lockmanagers */
            829         union {
            830                 struct nfs_lock_info    nfs_fl;
            831                 struct nfs4_lock_info   nfs4_fl;
            832             struct {
            833                  struct list_head link;  /* link in AFS vnode's pending_locks list */
            834                  int state;              /* state of grant or error if -ve */
            835                 } afs;
            836         } fl_u;
            837 };
            </pre>
            </td>
        </tr>
    </tbody>
</table>
<br />
<p>表 3 简单描述了 file_lock 结构中的各个字段所表示的含义。</p>
<br />
<a name="表 3. file_lock 数据结构的字段"><strong>表 3. file_lock 数据结构的字段</strong></a><br />
<table class="data-table-1" cellspacing="0" cellpadding="0" border="0">
    <tbody>
        <tr>
            <td style="vertical-align: top; text-align: center">类型 </td>
            <td style="vertical-align: top; text-align: center">字段 </td>
            <td style="vertical-align: top; text-align: center">字段描述 </td>
        </tr>
        <tr>
            <td style="vertical-align: top; text-align: center">struct file_lock* </td>
            <td style="vertical-align: top; text-align: center">fl_next </td>
            <td style="vertical-align: top; text-align: center">与索引节点相关的锁列表中下一个元素 </td>
        </tr>
        <tr>
            <td style="vertical-align: top; text-align: center">struct list_head </td>
            <td style="vertical-align: top; text-align: center">fl_link </td>
            <td style="vertical-align: top; text-align: center">指向活跃列表或者被阻塞列表 </td>
        </tr>
        <tr>
            <td style="vertical-align: top; text-align: center">struct list_head </td>
            <td style="vertical-align: top; text-align: center">fl_block </td>
            <td style="vertical-align: top; text-align: center">指向锁等待列表 </td>
        </tr>
        <tr>
            <td style="vertical-align: top; text-align: center">struct files_struct * </td>
            <td style="vertical-align: top; text-align: center">fl_owner </td>
            <td style="vertical-align: top; text-align: center">锁拥有者的 files_struct </td>
        </tr>
        <tr>
            <td style="vertical-align: top; text-align: center">unsigned int </td>
            <td style="vertical-align: top; text-align: center">fl_pid </td>
            <td style="vertical-align: top; text-align: center">进程拥有者的 pid </td>
        </tr>
        <tr>
            <td style="vertical-align: top; text-align: center">wait_queue_head_t </td>
            <td style="vertical-align: top; text-align: center">fl_wait </td>
            <td style="vertical-align: top; text-align: center">被阻塞进程的等待队列 </td>
        </tr>
        <tr>
            <td style="vertical-align: top; text-align: center">struct file * </td>
            <td style="vertical-align: top; text-align: center">fl_file </td>
            <td style="vertical-align: top; text-align: center">指向文件对象 </td>
        </tr>
        <tr>
            <td style="vertical-align: top; text-align: center">unsigned char </td>
            <td style="vertical-align: top; text-align: center">fl_flags </td>
            <td style="vertical-align: top; text-align: center">锁标识 </td>
        </tr>
        <tr>
            <td style="vertical-align: top; text-align: center">unsigned char </td>
            <td style="vertical-align: top; text-align: center">fl_type </td>
            <td style="vertical-align: top; text-align: center">锁类型 </td>
        </tr>
        <tr>
            <td style="vertical-align: top; text-align: center">loff_t </td>
            <td style="vertical-align: top; text-align: center">fl_start </td>
            <td style="vertical-align: top; text-align: center">被锁区域的开始位移 </td>
        </tr>
        <tr>
            <td style="vertical-align: top; text-align: center">loff_t </td>
            <td style="vertical-align: top; text-align: center">fl_end </td>
            <td style="vertical-align: top; text-align: center">被锁区域的结束位移 </td>
        </tr>
        <tr>
            <td style="vertical-align: top; text-align: center">struct fasync_struct * </td>
            <td style="vertical-align: top; text-align: center">fl_fasync </td>
            <td style="vertical-align: top; text-align: center">用于租借暂停通知 </td>
        </tr>
        <tr>
            <td style="vertical-align: top; text-align: center">unsigned long </td>
            <td style="vertical-align: top; text-align: left">fl_break_time </td>
            <td style="vertical-align: top; text-align: center">租借的剩余时间 </td>
        </tr>
        <tr>
            <td style="vertical-align: top; text-align: center">struct file_lock_operations * </td>
            <td style="vertical-align: top; text-align: center">fl_ops </td>
            <td style="vertical-align: top; text-align: center">指向文件锁操作 </td>
        </tr>
        <tr>
            <td style="vertical-align: top; text-align: center">struct lock_manager_operations * </td>
            <td style="vertical-align: top; text-align: center">fl_mops </td>
            <td style="vertical-align: top; text-align: center">指向锁管理操作 </td>
        </tr>
        <tr>
            <td style="vertical-align: top; text-align: center">union </td>
            <td style="vertical-align: top; text-align: center">fl_u </td>
            <td style="vertical-align: top; text-align: center">文件系统特定信息 </td>
        </tr>
    </tbody>
</table>
<br />
<p>一个 file_lock 结构就是一把&#8220;锁&#8221;，结构中的 fl_file 就指向目标文件的 file 结构，而 fl_start 和 fl_end 则确定了该文件要加锁的一个区域。当进程发出系统调用来请求对某个文件加排他锁时，如果这个文件上已经加上了共享锁，那么排他锁请求不能被立即满足，这个进程必须先要被阻塞。这样，这个进程就被放进了等待队列，file_lock 结构中的 fl_wait 字段就指向这个等待队列。指向磁盘上相同文件的所有 file_lock 结构会被链接成一个单链表 file_lock_list，索引节点结构中的 i_flock 字段会指向该单链表结构的首元素，fl_next 用于指向该链表中的下一个元素；当前系统中所有被请求，但是未被允许的锁被串成一个链表：blocked_list。fl_link 字段指向这两个列表其中一个。对于被阻塞列表（blocked_list）上的每一个锁结构来说，fl_next 字段指向与该锁产生冲突的当前正在使用的锁。所有在等待同一个锁的那些锁会被链接起来，这就需要用到字段 fl_block，新来的等待者会被加入到等待列表的尾部。 此外，fl_type 表示锁的性质，如读、写。fl_flags 是一些标志位，在 linux 2.6中，这些标志位的定义如下所示：</p>
<br />
<a name="清单 2. 标志位的定义"><strong>清单 2. 标志位的定义</strong></a><br />
<table cellspacing="0" cellpadding="0" width="100%" border="0">
    <tbody>
        <tr>
            <td class="code-outline">
            <pre class="displaycode">            773 #define FL_POSIX        1
            774 #define FL_FLOCK        2
            775 #define FL_ACCESS       8       /* not trying to lock, just looking */
            776 #define FL_EXISTS       16      /* when unlocking, test for existence */
            777 #define FL_LEASE        32      /* lease held on this file */
            778 #define FL_CLOSE        64      /* unlock on close */
            779 #define FL_SLEEP        128     /* A blocking lock */
            </pre>
            </td>
        </tr>
    </tbody>
</table>
<br />
<p>FL_POSIX 锁是通过系统调用 fcntl() 创建的；而 FL_FLOCK 锁是通过系统调用 flock()创建的（详细内容请参见后文中的介绍）。FL_FLOCK 锁永远都和一个文件对象相关联，打开这个文件的进程拥有该 FL_FLOCK 锁。当一个锁被请求或者允许的时候，内核就会把这个进程在同一个文件上的锁都替换掉。FL_POSIX 锁则一直与一个进程以及一个索引节点相关联。当进程死亡或者文件描述符被关闭的时候，这个锁会被自动释放。</p>
<p>对于强制锁来说，在 Linux 中，内核提供了 inline 函数 locks_verify_locked() 用于检测目标文件或者目标文件所在的设备是否允许使用强制锁，并且检查该设备是否已经加上了锁，相关函数如下所示：</p>
<br />
<a name="清单 3. 与强制锁相关的函数"><strong>清单 3. 与强制锁相关的函数</strong></a><br />
<table cellspacing="0" cellpadding="0" width="100%" border="0">
    <tbody>
        <tr>
            <td class="code-outline">
            <pre class="displaycode">            166 #define __IS_FLG(inode,flg) ((inode)-&gt;i_sb-&gt;s_flags &amp; (flg))
            173 #define IS_MANDLOCK(inode)      __IS_FLG(inode, MS_MANDLOCK)
            1047 /**
            1048  * locks_mandatory_locked - Check for an active lock
            1049  * @inode: the file to check
            1050  *
            1051  * Searches the inode's list of locks to find any POSIX locks which conflict.
            1052  * This function is called from locks_verify_locked() only.
            1053  */
            1054 int locks_mandatory_locked(struct inode *inode)
            1055 {
            1056         fl_owner_t owner = current-&gt;files;
            1057         struct file_lock *fl;
            1058
            1059         /*
            1060          * Search the lock list for this inode for any POSIX locks.
            1061          */
            1062         lock_kernel();
            1063         for (fl = inode-&gt;i_flock; fl != NULL; fl = fl-&gt;fl_next) {
            1064                 if (!IS_POSIX(fl))
            1065                         continue;
            1066                 if (fl-&gt;fl_owner != owner)
            1067                         break;
            1068         }
            1069         unlock_kernel();
            1070         return fl ? -EAGAIN : 0;
            1071 }
            1368 /*
            1369  * Candidates for mandatory locking have the setgid bit set
            1370  * but no group execute bit -  an otherwise meaningless combination.
            1371  */
            1372 #define MANDATORY_LOCK(inode) \
            1373         (IS_MANDLOCK(inode) &amp;&amp; ((inode)-&gt;i_mode &amp; (S_ISGID | S_IXGRP)) == S_ISGID)
            1374
            1375 static inline int locks_verify_locked(struct inode *inode)
            1376 {
            1377         if (MANDATORY_LOCK(inode))
            1378                 return locks_mandatory_locked(inode);
            1379         return 0;
            1380 }
            </pre>
            </td>
        </tr>
    </tbody>
</table>
<br />
<p>这里，函数 locks_verify_locked() 利用宏 MANDATORY_LOCK 来检测目标文件是否允许加锁，条件包括：该文件所在的设备的 super_block 结构中的 s_flags 必须被置为 1，该文件的 SGID 被置为 1 而且同组可执行位被清 0。如果允许，则调用函数locks_mandatory_locked()，该函数从索引节点的锁列表中查找是否存在有与其相冲突的锁，即是否已经加上了锁。</p>
<br />
<table cellspacing="0" cellpadding="0" width="100%" border="0">
    <tbody>
        <tr>
            <td><img height="1" alt="" src="http://www.ibm.com/i/v14/rules/blue_rule.gif" width="100%" /><br />
            <img height="6" alt="" src="http://www.ibm.com/i/c.gif" width="8" border="0" /></td>
        </tr>
    </tbody>
</table>
<br />
<br />
<p><a name="Linux 中关于文件锁的系统调用"><span class="atitle">Linux 中关于文件锁的系统调用</span></a></p>
<p>这里介绍在 Linux 中与文件锁关系密切的两个系统调用：flock() 和 fcntl()。劝告锁既可以通过系统调用 flock() 来实现，也可以通过系统调用 fcntl() 来实现。flock() 系统调用是从 BSD 中衍生出来的，在传统的类 UNIX 操作系统中，系统调用flock() 只适用于劝告锁。但是，Linux 2.6内核利用系统调用 flock() 实现了我们前面提到的特殊的强制锁：共享模式强制锁。另外，flock() 只能实现对整个文件进行加锁，而不能实现记录级的加锁。系统调用fcntl() 符合 POSIX 标准的文件锁实现，它也是非常强大的文件锁，fcntl() 可以实现对纪录进行加锁。</p>
<p><a name="flock()"><span class="smalltitle">flock()</span></a></p>
<p>flock() 的函数原型如下所示：</p>
<table cellspacing="0" cellpadding="0" width="100%" border="0">
    <tbody>
        <tr>
            <td class="code-outline">
            <pre class="displaycode">          int flock(int fd, int operation);
            </pre>
            </td>
        </tr>
    </tbody>
</table>
<br />
<p>其中，参数 fd 表示文件描述符；参数 operation 指定要进行的锁操作，该参数的取值有如下几种：LOCK_SH， LOCK_EX， LOCK_UN 和 LOCK_MANDphost2008-07-03T00:00:00 </p>
<p>man page 里面没有提到，其各自的意思如下所示：</p>
<ul>
    <li>LOCK_SH：表示要创建一个共享锁，在任意时间内，一个文件的共享锁可以被多个进程拥有
    <li>LOCK_EX：表示创建一个排他锁，在任意时间内，一个文件的排他锁只能被一个进程拥有
    <li>LOCK_UN：表示删除该进程创建的锁
    <li>LOCK_MAND：它主要是用于共享模式强制锁，它可以与 LOCK_READ 或者 LOCK_WRITE 联合起来使用，从而表示是否允许并发的读操作或者并发的写操作（尽管在 flock() 的手册页中没有介绍 LOCK_MAND，但是阅读内核源代码就会发现，这在内核中已经实现了） </li>
</ul>
<p>通常情况下，如果加锁请求不能被立即满足，那么系统调用 flock() 会阻塞当前进程。比如，进程想要请求一个排他锁，但此时，已经由其他进程获取了这个锁，那么该进程将会被阻塞。如果想要在没有获得这个排他锁的情况下不阻塞该进程，可以将 LOCK_NB 和 LOCK_SH 或者 LOCK_EX 联合使用，那么系统就不会阻塞该进程。flock() 所加的锁会对整个文件起作用。</p>
<p><a name="fcntl()"><span class="smalltitle">fcntl()</span></a></p>
<p>fcntl() 函数的功能很多，可以改变已打开的文件的性质，本文中只是介绍其与获取/设置文件锁有关的功能。fcntl() 的函数原型如下所示：</p>
<table cellspacing="0" cellpadding="0" width="100%" border="0">
    <tbody>
        <tr>
            <td class="code-outline">
            <pre class="displaycode">       int fcntl (int fd, int cmd, struct flock *lock);
            </pre>
            </td>
        </tr>
    </tbody>
</table>
<br />
<p>其中，参数 fd 表示文件描述符；参数 cmd 指定要进行的锁操作，由于 fcntl() 函数功能比较多，这里先介绍与文件锁相关的三个取值 F_GETLK、F_SETLK 以及 F_SETLKW。这三个值均与 flock 结构有关。flock 结构如下所示：</p>
<br />
<a name="清单 4. flock 结构"><strong>清单 4. flock 结构</strong></a><br />
<table cellspacing="0" cellpadding="0" width="100%" border="0">
    <tbody>
        <tr>
            <td class="code-outline">
            <pre class="displaycode">            struct flock {
            ...
            short l_type;    /* Type of lock: F_RDLCK,
            F_WRLCK, F_UNLCK */
            short l_whence;  /* How to interpret l_start:
            SEEK_SET, SEEK_CUR, SEEK_END */
            off_t l_start;   /* Starting offset for lock */
            off_t l_len;     /* Number of bytes to lock */
            pid_t l_pid;     /* PID of process blocking our lock
            (F_GETLK only) */
            ...
            };
            </pre>
            </td>
        </tr>
    </tbody>
</table>
<br />
<p>在 flock 结构中，l_type 用来指明创建的是共享锁还是排他锁，其取值有三种：F_RDLCK（共享锁）、F_WRLCK（排他锁）和F_UNLCK（删除之前建立的锁）；l_pid 指明了该锁的拥有者；l_whence、l_start 和l_end 这些字段指明了进程需要对文件的哪个区域进行加锁，这个区域是一个连续的字节集合。因此，进程可以对同一个文件的不同部分加不同的锁。l_whence 必须是 SEEK_SET、SEEK_CUR 或 SEEK_END 这几个值中的一个，它们分别对应着文件头、当前位置和文件尾。l_whence 定义了相对于 l_start 的偏移量，l_start 是从文件开始计算的。</p>
<p>可以执行的操作包括：</p>
<ul>
    <li>F_GETLK：进程可以通过它来获取通过 fd 打开的那个文件的加锁信息。执行该操作时，lock 指向的结构中就保存了希望对文件加的锁（或者说要查询的锁）。如果确实存在这样一把锁，它阻止 lock 指向的 flock 结构所给出的锁描述符，则把现存的锁的信息写到 lock 指向的 flock 结构中，并将该锁拥有者的 PID 写入 l_pid 字段中，然后返回；否则，就将 lock 指向的 flock 结构中的 l_type 设置为 F_UNLCK，并保持 flock 结构中其他信息不变返回，而不会对该文件真正加锁。
    <li>F_SETLK：进程用它来对文件的某个区域进行加锁（l_type的值为 F_RDLCK 或 F_WRLCK）或者删除锁（l_type 的值为F_UNLCK），如果有其他锁阻止该锁被建立，那么 fcntl() 就出错返回
    <li>F_SETLKW：与 F_SETLK 类似，唯一不同的是，如果有其他锁阻止该锁被建立，则调用进程进入睡眠状态，等待该锁释放。一旦这个调用开始了等待，就只有在能够进行加锁或者收到信号时才会返回 </li>
</ul>
<p>需要注意的是，F_GETLK 用于测试是否可以加锁，在 F_GETLK 测试可以加锁之后，F_SETLK 和 F_SETLKW 就会企图建立一把锁，但是这两者之间并不是一个原子操作，也就是说，在 F_SETLK 或者 F_SETLKW 还没有成功加锁之前，另外一个进程就有可能已经插进来加上了一把锁。而且，F_SETLKW 有可能导致程序长时间睡眠。还有，程序对某个文件拥有的各种锁会在相应的文件描述符被关闭时自动清除，程序运行结束后，其所加的各种锁也会自动清除。</p>
<p>fcntl() 既可以用于劝告锁，也可以用于强制锁，在默认情况下，它用于劝告锁。如果它用于强制锁，当进程对某个文件进行了读或写这样的系统调用时，系统则会检查该文件的锁的 O_NONBLOCK 标识，该标识是文件状态标识的一种，如果设置文件状态标识的时候设置了 O_NONBLOCK，则该进程会出错返回；否则，该进程被阻塞。cmd 参数的值 F_SETFL 可以用于设置文件状态标识。</p>
<p>此外，系统调用 fcntl() 还可以用于租借锁，此时采用的函数原型如下：</p>
<table cellspacing="0" cellpadding="0" width="100%" border="0">
    <tbody>
        <tr>
            <td class="code-outline">
            <pre class="displaycode">	       int fcntl(int fd, int cmd, long arg);
            </pre>
            </td>
        </tr>
    </tbody>
</table>
<br />
<p>与租借锁相关的 cmd 参数的取值有两种：F_SETLEASE 和 F_GETLEASE。其含义如下所示：</p>
<ul>
    <li>F_SETLEASE：根据下面所描述的 arg 参数指定的值来建立或者删除租约：
    <ul>
        <li>F_RDLCK：设置读租约。当文件被另一个进程以写的方式打开时，拥有该租约的当前进程会收到通知
        <li>F_WRLCK：设置写租约。当文件被另一个进程以读或者写的方式打开时，拥有该租约的当前进程会收到通知
        <li>F_UNLCK：删除以前建立的租约 </li>
    </ul>
    <li>F_GETLEASE：表明调用进程拥有文件上哪种类型的锁，这需要通过返回值来确定，返回值有三种：F_RDLCK、F_WRLCK和F_UNLCK，分别表明调用进程对文件拥有读租借、写租借或者根本没有租借 </li>
</ul>
<p>某个进程可能会对文件执行其他一些系统调用（比如 OPEN() 或者 TRUNCATE()），如果这些系统调用与该文件上由 F_SETLEASE 所设置的租借锁相冲突，内核就会阻塞这个系统调用；同时，内核会给拥有这个租借锁的进程发信号，告知此事。拥有此租借锁的进程会对该信号进行反馈，它可能会删除这个租借锁，也可能会减短这个租借锁的租约，从而可以使得该文件可以被其他进程所访问。如果拥有租借锁的进程不能在给定时间内完成上述操作，那么系统会强制帮它完成。通过 F_SETLEASE 命令将 arg 参数指定为 F_UNLCK 就可以删除这个租借锁。不管对该租借锁减短租约或者干脆删除的操作是进程自愿的还是内核强迫的，只要被阻塞的系统调用还没有被发出该调用的进程解除阻塞，那么系统就会允许这个系统调用执行。即使被阻塞的系统调用因为某些原因被解除阻塞，但是上面对租借锁减短租约或者删除这个过程还是会执行的。</p>
<p>需要注意的是，租借锁也只能对整个文件生效，而无法实现记录级的加锁。</p>
<br />
<table cellspacing="0" cellpadding="0" width="100%" border="0">
    <tbody>
        <tr>
            <td><img height="1" alt="" src="http://www.ibm.com/i/v14/rules/blue_rule.gif" width="100%" /><br />
            <img height="6" alt="" src="http://www.ibm.com/i/c.gif" width="8" border="0" /></td>
        </tr>
    </tbody>
</table>
<table class="no-print" cellspacing="0" cellpadding="0" align="right">
    <tbody>
        <tr align="right">
            <td><img height="4" alt="" src="http://www.ibm.com/i/c.gif" width="100%" /><br />
            </td>
        </tr>
    </tbody>
</table>
<br />
<br />
<p><a name="文件锁的使用样例"><span class="atitle">文件锁的使用样例</span></a></p>
<p>为了使读者更深入理解本文中介绍的内容，下面我们给出了一个例子来详细介绍文件锁的具体用法。这个例子可以用来检测所使用的文件是否支持强制锁，其源代码如下所示：</p>
<br />
<a name="清单 5. 锁的使用方法具体示例"><strong>清单 5. 锁的使用方法具体示例</strong></a><br />
<table cellspacing="0" cellpadding="0" width="100%" border="0">
    <tbody>
        <tr>
            <td class="code-outline">
            <pre class="displaycode">            # cat -n mandlock.c
            1  #include &lt;errno.h&gt;
            2  #include &lt;stdio.h&gt;
            3  #include &lt;fcntl.h&gt;
            4  #include &lt;sys/wait.h&gt;
            5  #include &lt;sys/stat.h&gt;
            6
            7  int lock_reg(int fd, int cmd, int type, off_t offset, int whence, off_t len)
            8  {
            9          struct flock    lock;
            10
            11          lock.l_type = type;     /* F_RDLCK, F_WRLCK, F_UNLCK */
            12          lock.l_start = offset;  /* byte offset, relative to l_whence */
            13          lock.l_whence = whence; /* SEEK_SET, SEEK_CUR, SEEK_END */
            14          lock.l_len = len;       /* #bytes (0 means to EOF) */
            15
            16          return( fcntl(fd, cmd, &amp;lock) );
            17  }
            18
            19  #define read_lock(fd, offset, whence, len) \
            20                          lock_reg(fd, F_SETLK, F_RDLCK, offset, whence, len)
            21  #define write_lock(fd, offset, whence, len) \
            22                          lock_reg(fd, F_SETLK, F_WRLCK, offset, whence, len)
            23
            24  #define err_sys(x) { perror(x); exit(1); }
            25
            26  int main(int argc, char *argv[])
            27  {
            28      int             fd, val;
            29      pid_t           pid;
            30      char            buf[5];
            31      struct stat     statbuf;
            32      if (argc != 2) {
            33          fprintf(stderr, "usage: %s filename\n", argv[0]);
            34          exit(1);
            35      }
            36      if ((fd = open(argv[1], O_RDWR | O_CREAT | O_TRUNC )) &lt; 0)
            37          err_sys("open error");
            38      if (write(fd, "hello world", 11) != 11)
            39          err_sys("write error");
            40
            41      /* turn on set-group-ID and turn off group-execute */
            42      if (fstat(fd, &amp;statbuf) &lt; 0)
            43          err_sys("fstat error");
            44      if (fchmod(fd, (statbuf.st_mode &amp; ~S_IXGRP) | S_ISGID) &lt; 0)
            45          err_sys("fchmod error");
            46
            47      sleep(2);
            48
            49      if ((pid = fork()) &lt; 0) {
            50          err_sys("fork error");
            51      } else if (pid &gt; 0) {   /* parent */
            52          /* write lock entire file */
            53          if (write_lock(fd, 0, SEEK_SET, 0) &lt; 0)
            54              err_sys("write_lock error");
            55
            56          sleep(20);      /* wait for child to set lock and read data */
            57
            58          if (waitpid(pid, NULL, 0) &lt; 0)
            59              err_sys("waitpid error");
            60
            61      } else {            /* child */
            62          sleep(10);      /* wait for parent to set lock */
            63
            64          if ( (val = fcntl(fd, F_GETFL, 0)) &lt; 0)
            65                  err_sys("fcntl F_GETFL error");
            66
            67          val |= O_NONBLOCK;           /* turn on O_NONBLOCK flag */
            68
            69          if (fcntl(fd, F_SETFL, val) &lt; 0)
            70                  err_sys("fcntl F_SETFL error");
            71
            72         /* first let's see what error we get if region is locked */
            73         if (read_lock(fd, 0, SEEK_SET, 0) != -1)    /* no wait */
            74             err_sys("child: read_lock succeeded");
            75
            76 printf("read_lock of already-locked region returns %d: %s\n", errno, strerror(errno));
            77
            78         /* now try to read the mandatory locked file */
            79         if (lseek(fd, 0, SEEK_SET) == -1)
            80             err_sys("lseek error");
            81         if (read(fd, buf, 5) &lt; 0)
            82             printf("read failed (mandatory locking works)\n");
            83         else
            84             printf("read OK (no mandatory locking), buf = %5.5s\n", buf);
            85      }
            86      exit(0);
            87  }
            88
            </pre>
            </td>
        </tr>
    </tbody>
</table>
<br />
<p>样例代码中所采用的技术在前文中大都已经介绍过了，其基本思想是在首先在父进程中对文件加上写锁；然后在子进程中将文件描述符设置为非阻塞模式（第 69 行），然后对文件加读锁，并尝试读取该文件中的内容。如果系统支持强制锁，则子进程中的 read() 系统调用（代码中的第 81 行）会立即返回 EAGAIN；否则，等父进程完成写文件操作之后，子进程中的 read() 系统调用就会返回父进程刚刚写入的前 5 个字节的数据。代码中的几个 sleep() 是为了协调父进程与子进程之间的同步而使用的。</p>
<p>该程序在测试系统的执行结果如下所示：</p>
<table cellspacing="0" cellpadding="0" width="100%" border="0">
    <tbody>
        <tr>
            <td class="code-outline">
            <pre class="displaycode"># mount | grep mnt
            /dev/sdb7 on /mnt type ext3 (rw,mand)
            /dev/sdb6 on /tmp/mnt type ext3 (rw)
            # ./mandlock /mnt/testfile
            read_lock of already-locked region returns 11: Resource temporarily unavailable
            read failed (mandatory locking works)
            # ./mandlock /tmp/mnt/testfile
            read_lock of already-locked region returns 11: Resource temporarily unavailable
            read OK (no mandatory locking), buf = hello
            </pre>
            </td>
        </tr>
    </tbody>
</table>
<br />
<p>我们可以看到，/dev/sdb7 使用 &#8211;o mand 选项挂载到了 /mnt 目录中，而 /dev/sdb6 则么有使用这个选项挂载到了 /tmp/mnt 目录中。由于在程序中我们完成了对测试文件 SGID 和同组可执行位的设置（第 44 行），因此 /mnt/testfile 可以支持强制锁，而 /tmp/mnt/testfile 则不能。这也正是为什么前者的 read() 系统调用会失败返回而后者则可以成功读取到 hello 的原因。</p>
<br />
<table cellspacing="0" cellpadding="0" width="100%" border="0">
    <tbody>
        <tr>
            <td><img height="1" alt="" src="http://www.ibm.com/i/v14/rules/blue_rule.gif" width="100%" /><br />
            <img height="6" alt="" src="http://www.ibm.com/i/c.gif" width="8" border="0" /></td>
        </tr>
    </tbody>
</table>
<table class="no-print" cellspacing="0" cellpadding="0" align="right">
    <tbody>
        <tr align="right">
            <td><img height="4" alt="" src="http://www.ibm.com/i/c.gif" width="100%" /><br />
            </td>
        </tr>
    </tbody>
</table>
<br />
<p><a name="outline"><span class="atitle">总结</span></a></p>
<p>Linux 的文件锁在以共享索引节点共享文件的情况下设计的，文件锁的实现可以使得不同用户同时读写同一文件的并发问题得以解决。本文描述了 Linux 中各类文件锁的概念，使用场景，内核中描述文件锁的数据结构以及与文件锁密切相关的系统调用等内容，至于与文件锁相关的索引节点数据结构，以及在对文件进行加锁时遇到的死锁问题等其他知识，这里没有做详尽介绍，感兴趣的读者可以自行参考内核源代码。</p>
<p>本文的目的是想帮助读者理清 Linux 2.6中文件锁的概念以及 Linux 2.6 都提供了何种数据结构以及关键的系统调用来实现文件锁，从而可以帮助读者更好地使用文件锁来解决多个进程读取同一个文件的互斥问题。</p>
<br />
<table cellspacing="0" cellpadding="0" width="100%" border="0">
    <tbody>
        <tr>
            <td><img height="1" alt="" src="http://www.ibm.com/i/v14/rules/blue_rule.gif" width="100%" /><br />
            <img height="6" alt="" src="http://www.ibm.com/i/c.gif" width="8" border="0" /></td>
        </tr>
    </tbody>
</table>
<table class="no-print" cellspacing="0" cellpadding="0" align="right">
    <tbody>
        <tr align="right">
            <td><img height="4" alt="" src="http://www.ibm.com/i/c.gif" width="100%" /><br />
            </td>
        </tr>
    </tbody>
</table>
<br />
<br />
<p><a name="resources"><span class="atitle">参考资料 </span></a></p>
<ul>
    <li><a href="http://kernel.org/pub/linux/kernel/v2.6/linux-2.6.23.tar.bz2" cmimpressionsent="1">Linux 内核源代码</a>中包含了文件锁的具体实现，本文中引用的内核代码来自于 Linux &nbsp;2.6.23 版本的内核。 <br />
    <br />
    <li><a href="http://www.infradead.org/~willy/locking_manifesto.html" cmimpressionsent="1">File Locking in Linux 2.5</a>一文中介绍了在 Linux 2.5 开发时对文件锁的一些设计考虑。 <br />
    <br />
    <li><a href="http://www.unix.org/single_unix_specification/" cmimpressionsent="1">The Single UNIX&#174; Specification, Version 3 规范</a>中对 fcntl 系统调用进行了详细的规定。 <br />
    <br />
    <li><a>Linux 内核情景分析(上)一书的文件系统一章详细描述了 Linux 内核对各种不同类锁的管理和控制，讲述了 Linux 文件锁的关键的数据结构及其实现，以及文件锁对其他的文件模式和操作的影响</a> <br />
    <br />
    <li><a>在 Understanding the Linux Kernel(3<sup>rd</sup> Edition) 中，有关于 Linux 中不同种类文件锁详细的实现过程</a> <br />
    <br />
    <li>更多的关于 Linux 开发的资源，参见 developerWorks 上 <a href="http://www.ibm.com/developerworks/cn/linux/" cmimpressionsent="1">Linux 专区</a>。 </li>
</ul>
<p><span style="color: #800080"><a title="mandlock.c" href="/Files/joan/mandlock.rar"><em>mandlock.c</em></a><a title="mandlock.c" style="color: #ccffff" href="/Files/joan/mandlock.rar"></span></a></p>
<p>&nbsp;</p>
&nbsp; 
   <img src ="http://www.blogjava.net/joan/aggbug/214335.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/joan/" target="_blank">joan</a> 2008-07-11 21:31 <a href="http://www.blogjava.net/joan/articles/214335.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>