Linux 版 (精华区)
发信人: netiscpu (说不如做), 信区: Linux
标 题: 仅仅列出连接:只能如此
发信站: 哈工大紫丁香 (Tue May 18 08:35:17 1999), 转信
《Linux公报》……让Linux更富魅力!
---------------------------------------------------------------------------
-----
The Answer Guy
By James T. Dennis, answerguy@ssc.com
Starshine Technical Services, http://www.starshine.org/
翻译: gaia
---------------------------------------------------------------------------
-----
仅仅列出连接:只能如此
From Jerry Giles on Thu, 05 Nov 1998
很抱歉打搅你,但我在浏览Linux信息时碰巧看到了你的名字.我现在参加本地学校
的一个CIS项目,最近的一次测验中的一道题我始终想不出答案.教授问我们什么命
令能只列出一个目录里"被连接的文件".我猜他是期望我们用ls命令的某些选项,但
我找遍ls所有的选项也没发现能有这种功能的.你能帮我吗?
谢谢,jerry giles
要么是你理解错了,要么是你的教授说的很不严谨.'ls'命令就是用来"列出连接"的
---所有的目录项都是连接!其中一些是符号连接,另一些是"硬"连接(就是通常被认
为是"普通"目录项的).'ls'命令所做的只能是列出连接.我能列出的其它信息是它从
每个连接所指向的inode中取出来的(用stat()函数).
所以,照你这么问这个问题根本没有意义.
那么,如果问题是想列出符号连接,倒是有几个能说的通的简单回答.
ls -l | grep ^l
...这样把所有连接(硬的和"符号的")的"长"列表过滤一遍,只显示那些以字母
"l"开头的.在一个"长"目录列表中,第一段字符(或者叫域)是用来表示目录连接所
指向的那个文件的类型和权限.(l即符号连接,d是目录,s为socket,p是"FIFO/有名
FIFO管道",b和c分别是"块"和"字符"特殊设备节点---通常只在/dev/目录下---而
"-"为"普通"文件).
长列表的第二个域是"连接数".它告诉你有多少硬连接指向了同一个inode.
以下例子是我自己的根目录
drwxr-xr-x 14 root root 1024 Sep 27 17:19 .
drwxr-xr-x 14 root root 1024 Sep 27 17:19 ..
-rw-r--r-- 2 root root 219254 Sep 27 17:19 System.map
drwxr-xr-x 2 root root 2048 Sep 12 03:25 bin
drwxr-xr-x 2 root root 1024 Sep 27 17:20 boot
drwxr-xr-x 2 root root 1024 Aug 31 06:40 cdrom
drwxr-xr-x 21 root root 4096 Nov 4 03:12 etc
lrwxrwxrwx 1 root root 15 Apr 20 1998 home -> /usr/local/h
ome drwxr-xr-x 5 root root 2048 Sep 16 23:48 lib
drwxr-xr-x 2 root root 12288 Mar 10 1998 lost+found
drwxr-xr-x 9 root root 1024 Aug 31 06:40 mnt
lrwxrwxrwx 1 root root 14 Mar 31 1998 opt -> /usr/local/op
t dr-xr-xr-x 63 root root 0 Oct 13 02:25 proc
drwx--x--x 13 root root 2048 Oct 31 17:47 root
drwxr-xr-x 5 root root 2048 Sep 16 23:48 sbin
drwxrwxrwt 8 temp root 3072 Nov 5 09:33 tmp
drwxr-xr-x 30 root root 1024 Aug 31 13:32 usr
lrwxrwxrwx 1 root root 13 Aug 31 06:40 var -> usr/local/var
-rw-r--r-- 1 root root 732668 Sep 27 17:19 vmlinuz
这是用'ls -al /'产生的
第二个域的数字(每行第一个数字)就是"连接数".这是指向同一个inode的硬连接
的数目.这样我的根目录有14个指向它的连接.每个子目录的".."项都指向它.就是
说,/usr/..指向/ ,同样/ect/.. ,/dev/..和所有在/下面一级的目录都是如此
./usr/local/..指向/usr/,照此类推.
我们可以看到'System.map'的连接计数为2.这意味着这个文件还有另一个名字.在
这个文件系统内还有一个硬连接指向它.
多数Unix新手都认为'ls'命令用来列出文件.这不对.'ls'命令列出的是到文件的连
接.当你给'ls'加上像'-l'这样的参数时,你除了列出连接,还有它们指向的文件的
一些信息.(在幕后,'ls'命令为每个目录项调用stat()函数).Unix/Linux的目录由
文件名和inode的列表组成.所有与文件相关的其它信息都储存在inode里(如文件的类
型,所有者,权限,连接数,三个时间/日期戳,大小---和最重要的---储存着文件内容
的块(block)的清单)
为了更好地理解这种不同,创建一个子目录(~/tmp/experiment).在里面随意放几个
连接(用'ln'产生"硬连接",用'ln -s'做符号连接,并可以用'cp'命令拷贝一些文件
进去).再用'chmod'命令除去你自己的对目录的执行权限.
('chmod a-x ~/tmp/experiment').
*(从技术上说这只是一个"演示"而非"实验".不过这么说有点过分严谨了,只是顺便
提一句而已. )
你应该能使用'ls'命令(确认用的是真正的'ls'命令---不是别名(alias),shell函数或
shell脚本).这个命令应该正常发挥作用(如果不行---你可能把'ls'变成了'ls
--color'或其它什么的别名---那就使用命令/bin/ls,或者在实验期间用'unalias
ls'命令去掉'ls'的别名意义.一旦你可以使用'ls'命令了,不加任何参数可以得到
"~/tmp/experiment"目录下文件名的列表,接着试试'ls -l'和'ls -i'.
你会得到一长串"Permission denied"信息(当然你不是以root登录).并且注意你只
能在目录外面使用这些命令.用'cd'命令进入目录要求你拥有目录的"执行"权限.
之所以你会得到这些"Permission denied"信息是因为,为了得到关于文件的任何信
息(除了连接名以外),'ls'命令必须访问inode(这需要对目录的执行权).对这个目
录你可以使用'ls'或'ls -a'命令,因为它们只提供了连接名的列表.这类命令不需
要访问储存在inode里的文件信息.
所以,既然你已经理解了连接是什么(希望如此)---你就能理解有关'rm'命令的一些
知识.
'rm'并不删除文件.'rm'删除到文件的连接.文件系统会检查连接数.如果它是
"0",(并且没有打开的文件描述符,即没有进程打开这个文件),这个文件将被真正地
删除.
注意这里重要的一点:文件删除操作是间接完成的,是作为文件系统日常运行的一部
分.'rm'和类似命令只不过调用"unlink()"(一个系统调用).
这里还有一种可能.如果我打开一个文件(比如,用编辑器),然后用'rm'删除了这个
文件,那会发生什么?(假设到文件只有一个硬连接)
没什么特别的.连接计数为0但文件被打开了.只要文件被打开着,文件系统的维护例
程就不去管这个文件的inode和数据块.一旦文件关闭了,这些例程将检测到连接数
为0,然后删除这个文件.如果好多进程打开这个文件---那么只有在所有进程关闭文
件后它才会被真正删除.
实际上删除包括好几步.先是所有分配给这个文件的数据块(block)被重新分配给
"free list".你可以把空闲链表(free list)想成是拥有磁盘上所有空闲空间的
"特殊文件".具体的实现随文件系统的不同而不同.然后文件的inode被标记为"已删
除"或被"清零".(这是随文件系统和版本而异的)
现在,回到你原来的问题:
找出一个目录下所有符号连接的更正规的办法是用'find'命令.试试以下命令:
find / -type l -maxdepth 1 -print
...GNU版本的'find'缺省使用-print操作所以在Linux下可以把它省略.
"maxdepth 1"这部分是为了防止'find'查找整个文件树(注意:我倾向于使用"文件
树"(file tree)或"文件层次系统"(file hiearchy)来指某个搜索起始点下所有文
件*及所有mount上的文件系统*,而用"文件系统"来指单个被mount上的文件系统内所有
文件.这是一个容易混淆之处).
现在,如果问题是"找出所有连接数大于1的普通文件"你可以用:
find ... -type f -maxdepth 1 -links +1
其中省略号部分为一个或多个目录名/文件名,其他参数检查各种条件是否满足(当
然要防止查找整个文件树).在GNU find里,许多数字条件可以用+x,x,-x来指定,---这
里+x表示"大于'x'",而-x表示"小于'x'",x表示"等于x."这是find命令的妙处
之一.
我能想到的对这个问题的最后一种理解是:找到指向某一指定文件(inode)的所有连
接.要做到这一点你要从inode着手.如果它不是一个目录,(*)并且其连接数大于一
,那么搜索整个文件系统找出匹配其inode的所有其它连接.这对于刚接触Unix的学
生可不是个简单问题.这需要写一个脚本.
*(我们没必要搜索目录的其它硬连接,因为它们应该都在./*/..--就是说这些硬连
接都是当前目录及下一级目录中的"."或".." .如果你想用自己写的代码强制建立
指向一个目录的另外的硬连接---fsck可能会修正目录结构中的这种反常.一些版本
的Unix历史上允许root(超级用户)创建到目录的硬连接---但Linux下的GNU工具不
允许---所以你不得不自己写代码,或者不得不用一个hex编辑器直接修改文件系统
.)
我只通过讲解一个例子让大家初步了解一下.
在上面提到的我的根目录的例子中,我们发现 System.map的连接数为2.它是普通文
件.所以我想找到它的另一个连接.
先要找到inode.
'ls -ail'告诉我们:
2 drwxr-xr-x 14 root root 1024 Sep 27 17:19 .
2 drwxr-xr-x 14 root root 1024 Sep 27 17:19 ..
13 -rw-r--r-- 2 root root 219254 Sep 27 17:19 System.map
4019 drwxr-xr-x 2 root root 2048 Sep 12 03:25 bin
56241 drwxr-xr-x 2 root root 1024 Sep 27 17:20 boot
14 lrwxrwxrwx 1 root root 13 Aug 31 06:40 var
(等等)
...这里第一个域的数字是inode---即这些连接所指向的文件系统数据结构.我们注意
到根目录下'.'和'..'(当前目录及父目录)都指向同一个inode,这个inode是分配给
根目录的.(任何其它目录并不是这样.)
...所以我想找到这个文件系统中所有指向13号inode的连接.
*(不能在其它被mount上的文件系统中找---它们每个都有自己的13号inode)
下面的命令完成这项工作:
find / -mount -inum 13
...哇!这么简单."-mount"选项告诉find命令仅仅局限于本文件系统而不要越过任
何mount点(它和-xdev选项一样).
要想对某一目录下每个连接都使用这套步骤,其困难之处就在于如何找到每个文件
所在的文件系统的根.在我的例子中做到这一点很简单,但靠不住,因为我想找的连
接就在根目录里(而很明显,根目录就是其文件系统的根).
如果我有一个脚本或程序能够"找到指定文件所在的文件系统的根"(叫它
"fsrootof")---那么我就能写出脚本的其余部分:
find ... -type f -links +1 -printf "%i %p\n" | while read i f; do
find $(fsrootof $f) -mount -inum $i
done
用这一段shell脚本,可以产生一个清单,列出连接数大于1的"普通文件"的inode和
文件名/路径(这是由第一个'find'的-printf选项实现的).这个清单被输入一个简
单的shell循环,以一个"inode"和一个"path"的形式读入每一行(随后分别以$i和
$f引用它们).循环体调用我那个神秘的脚本或程序来"发现文件所在的文件系统的
根"---然后把这些文件系统的根作为第二个find命令的搜索起始点.
一时半会儿我还想不出用简单的shell脚本怎么实现"fsrootof".可能最好是用C或
perl脚本(直接使用一些系统调用取得文件状态信息,并需要些技巧回溯到上级目录
(沿着..连接)直到遇到mount点).我不得不研读find的源代码看看它到底是怎么实
现的.
所以,也许我应该把它留作"Linux公报读者挑战赛"(实现上述'fsrootof').
---------------------------------------------------------------------------
-----
版权所有 (C) 1998 NJLUG
出版于第35期《Linux公报》1998年12月 中文版第二期
---------------------------------------------------------------------------
-----
rpm passwd links ipscript magickeys
---------------------------------------------------------------------------
-----
--
☆ 来源:.哈工大紫丁香 bbs.hit.edu.cn.[FROM: bin@mtlab.hit.edu.cn]
Powered by KBS BBS 2.0 (http://dev.kcn.cn)
页面执行时间:2.645毫秒