- 第7章 Linux文件与目录管理
- 最重要的就是目录的绝对路径与相对路径,还有一些特殊目录的符号。
- 代表去到 vbird 这个用户的主文件夹,即 /home/vbird。
- 表示回到自己的主文件夹,即是 /root 这个目录。
- 没有加上任何路径,也还是代表回到自己主文件夹的意思。
- 表示去到目前的上层目录,即是 /root 的上层目录的意思。
- 表示回到刚才的那个目录,也就是 /root 。
- 这个就是绝对路径的写法,直接指定要去的完整路径名称。
- 这个是相对路径的写法,我们由/var/spool/mail 到/var/spool/mqueue 就这样写。
- 看到这里应该知道为啥了吧?因为 /var/mail 是连接文件,连接到 /var/spool/mail。
- 所以,加上 pwd -P 的参数后,会不以连接文件的数据显示,而是显示正确的完整路径。
- 加了这个 -p 的参数,可以自行创建多层目录。
- 仔细看上面的权限部分,如果没有加上 -m 来强制设置属性,系统会使用默认属性。
- 那么你的默认属性为何?这要通过下面介绍的 umask 才能了解。
- 利用 -p 这个参数,立刻就可以将 test1/test2/test3/test4 一次删除。
- 不过要注意的是,这个 rmdir 仅能“删除空的目录”。
- 仔细看,一般用户vbird的PATH中,并不包含任何“sbin”的目录存在喔!
- mv 为移动,可将文件在不同的目录间进行移动作业
- 这个时候你会看到以“.”为开头的几个文件,以及目录文件 (.)、(..)、.gconf 等
- 不过,目录文件文件名都是以深蓝色显示,有点不容易看清楚就是了。
- 注意看到显示结果的第一行,知道为何我们会执行类似 ./command
- 之类的命令了吧?因为 ./ 代表的是“目前目录下”的意思。至于什么是 FIFO/Socket
- 请参考前一章节的介绍。另外,那个.bashrc 时间仅写2007,能否知道详细时间?
- 请仔细看,上面的“时间”字段变了。变成较为完整的格式。
- 一般来说,ls -al 仅列出目前短格式的时间,有时不会列出年份,
- 通过 —full-time 可以查阅到比较正确的完整时间格式。
- 重复做两次操作,由于 /tmp 下面已经存在 bashrc 了,加上 -i 参数后,
- 则在覆盖前会询问用户是否确定,可以按下 n 或者 y 来二次确认呢!
- 注意上面的特殊字体,在不加任何参数的情况下,文件的某些属性/权限会改变;
- 这是个很重要的特性,连文件建立的时间也不一样了。
- 那如果你想要将文件的所有特性都一起复制过来该怎办?可以加上 –a,如下所示:
- 整个数据特性完全一模一样。这就是 -a 的特性。
- 还是要再次强调。-r 是可以复制目录,但是,文件与目录的权限可能会被改变
- 所以,也可以利用“ cp -a /etc /tmp ”来执行命令。尤其是在备份的情况下。
- 这个 -u 的特性是在目标文件与源文件有差异时才会复制的。
- 所以,比较常被用于“备份”的工作当中。
- 这个例子也是很有趣。原本复制的是连接文件,但是却将连接文件的实际文件复制过来了
- 也就是说,如果没有加上任何参数时,cp复制的是源文件,而非连接文件的属性!
- 若要复制连接文件的属性,就得要使用 -d 的参数了!如 bashrc_slink_2 所示。
- 可以将多个数据一次复制到同一个目录去,最后面一定是目录。
- 如果加上 -i 的参数就会主动询问,避免你删除错误的文件名!
- 注意那个星号,代表的是 0 到无穷多个任意字符。
- 因为身份是 root ,默认已经加入了 -i 的参数,所以你要一直按 y 才会删除!
- 如果不想要继续按 y ,可以按下[ctrl]-c 来结束 rm 的工作。
- 这是一种保护的操作,如果确定要删除掉此目录而不要询问,可以这样做:
- 在命令前加上反斜杠,可以忽略掉 alias 的指定参数。至于 alias 我们在bash章节中再谈。
- 将某个文件移动到某个目录去,就是这样做!
- 其实在 Linux 下面还有个有趣的命令,名称为 rename ,
- 该命令专门进行多个文件名的同时重命名,并非针对单一文件名的更改,与mv不同。请man rename。
- 注意这边,如果有多个源文件或目录,则最后一个目标文件一定是“目录”
- 意思是说,将所有的数据移动到该目录的意思。
- 7.3 文件内容查阅
- 看到了吧!可以印出行号呢!这对于大文件要找某个特定的行时,有点用处!
- 如果不想要编排空白行的行号,可以使用“cat -b /etc/issue”,自己测试看看:
- $
- The next two items are intended to be a quick access place to$
- 上面的结果限于篇幅,鸟哥删除掉很多数据了。另外,输出的结果并不会有特殊字体,
- 鸟哥上面的特殊字体是要让你发现差异点在哪里就是了。基本上,在一般的环境中,
- 使用 [Tab] 与空格键的效果差不多,都是一堆空白。我们无法知道两者的差别。
- 此时使用 cat -A 就能够发现那些空白的地方是什么东西了。[Tab]会以 ^I 表示,
- 断行字符则是以 $ 表示,所以你可以发现每一行后面都是 $ 啊!不过断行字符
- 在Windows、Linux中则不太相同,Windows的断行字符是 ^M$。
- 这部分我们会在第10章 vim 软件的介绍时,再次说明到。
- 与刚才上面的范例一比较,是由最后一行先显示。
- 注意看,这个文件其实有三行,第三行为空白(没有任何字符),
- 因为它是空白行,所以 nl 不会加上行号。如果确定要加上行号,可以这样做:
- 行号加上来,那么如果要让行号前面自动补上 0 呢?可这样:
- 自动在自己字段的地方补上 0 了。默认字段是6位数,如果想要改成 3 位数呢?
- 变成仅有 3 位数。
- Generated automatically from man.conf.in by the
- configure script.
- man.conf from man-1.6d
- Generated automatically from man.conf.in by the
- configure script.
- man.conf from man-1.6d
- Generated automatically from man.conf.in by the
- configure script.
- man.conf from man-1.6d
- 默认的情况中,显示前10行!若要显示前 20 行,就得要这样:
- 默认的情况中,显示最后的10行。若要显示最后的 20 行,就得要这样:
- 最左边第一列是以进制来表示bytes数。以上面范例来说,第二列0000020代表开头是
- 第 16 个 byes 8(2 8)的内容之意。
- 如上所示,可以发现每个字符可以对应到的数值。
- 例如e对应的记录数值为145,转成十进制:1x8^2+4x8+5=101。
- 注意到,这个文件的大小是 0 呢!在默认的状态下,如果 touch 后面有接文件,
- 则该文件的三个时间 (atime、ctime、mtime) 都会更新为目前的时间。若该文件不存在,
- 则会主动创建一个新的空的文件。例如上面这个例子。
- 跟上个范例比较看看,本来是 25 日的变成了 23 日了 (atime/mtime)~
- 不过,ctime 并没有跟着改变。
- 注意看看,日期在 atime 与 mtime 中都改变了,但是 ctime 则是记录目前的时间!
- 看到了吗?连 root 也没有办法将这个文件删除呢!赶紧解除设置!
- 设置权限成为 -rws—x—x 的模样:
- 承上,在上述的文件权限中加上 SGID 与 SBIT!
- 执行文件的数据可就多得不得了!包括这个文件的 suid 权限兼容于 Intel 386
- 等级的硬件平台、使用的是 Linux 核心 2.6.9 的动态函数库链接等。
- 因为 which 是根据用户所设置的 PATH 变量内的目录去查找可执行文件的,所以,
- 不同的 PATH 设置内容所找到的命令当然不一样了。因为 /sbin 不在 vbird 的
- PATH 中,找不到也是理所当然的。
- 竟然会有两个 which,其中一个是 alias,那是啥?
- 那就是所谓的“命令别名”,意思是输入 which 会等于后面接的那串命令。
- 更多的数据我们会在 bash 章节中再来谈的。
- 怎么可能没有 cd,我明明就能够用 root 执行 cd 的。
- 注意看,明明 which 一般用户找不到的 ifconfig 却可以让 whereis 找到。
- 这是因为系统真的有 ifconfig 这个“文件”,但是用户的 PATH 并没有加入 /sbin。
- 所以,未来你找不到某些命令时,先用文件查找命令找找看再说。
- 那个 0 是重点!0 代表目前的时间,所以,从现在开始到 24 小时前,
- 有改动过内容的文件都会被列出来!那如果是3天前的 24 小时内?
- find / -mtime 3 有改动过的文件都被列出的意思。
- -newer 用在分辨两个文件之间的新旧关系是很有用的!
- 这个东西也很有用的,当我们要找出任何一个用户在系统当中的所有文件时,
- 就可以利用这个命令将属于某个用户的所有文件都找出来。
- 通过这个命令,可以轻易就找出那些不太正常的文件。
- 如果有找到不属于系统任何人的文件时,不要太紧张,
- 那有时候是正常的,尤其是你曾经以源码自行编译软件时。
- 利用这个 -name 可以查找文件名。
- 这个 -type 的属性也很有帮助。尤其是要找出那些怪异的文件,
- 例如 socket 与 FIFO 文件,可以用 find /var -type p 或 -type s 来找!
- 所谓的 7000 就是 —-s—s—t,那么只要含有 s 或 t 的就列出,
- 所以当然要使用 +7000,使用 -7000 表示要含有 —-s—s—t 的所有三个权限,
- 因此,就是 +7000 。
- 注意到,那个 -exec 后面的 ls -l 就是额外的命令,命令不支持命令别名,
- 所以仅能使用 ls –l,不可以使用 ll ,特别注意。
- 虽然在 man page中提到可以使用 M 与 G 分别代表 MB 与 GB,
- 不过,我却试不出来这个功能。所以,目前应该是仅支持到 c 与 k 。
- 从上面的权限结果来看,由于 alex/arod 均支持 project,因此似乎没问题了!
- 仔细看一下上面的文件,由于用户组是 alex,
- 因此对于 abcd 这个文件来说,arod 应该只是其他人,只有 r 的权限而已啊!
- 这才是我们要的样子。现在 alex、arod 创建的新文件所属用户组都是 project,
- 由于两人均属于此用户组,加上 umask 都是 002,这样两人才可以互相修改对方的文件!
第7章 Linux文件与目录管理
在第6章我们认识了Linux系统下的文件权限概念以及目录的配置说明。在这章当中,我们就直接来进一步地操作与管理文件与目录。包括在不同的目录间切换、创建与删除目录、创建与删除文件,还有查找文件、查看文件内容等,都会在这章作个简单的介绍。
7.1 目录与路径
由第6章Linux的文件权限与目录配置中通过FHS了解了Linux的树状目录概念之后,接下来就得要实际来搞定一些基本的路径问题了!这些目录的问题当中,最重要的莫过于第6章也谈过的“绝对路径”与“相对路径”的意义。绝对路径与相对路径的写法并不相同,要特别注意。此外,当你执行命令时,该命令是通过什么功能来取得的?这与路径这个变量有关。下面就让我们来谈谈。
7.1.1 相对路径与绝对路径
在开始目录的切换之前,你必须要先了解一下所谓的“路径”(PATH),有趣的是:什么是“相对路径”与“绝对路径”?虽然前一章已经稍微针对这个问题提过一次,不过,这里不厌其烦地再次强调一下。
绝对路径:路径的写法一定由根目录/写起,例如/usr/share/doc这个目录。
相对路径:路径的写法不是由/写起,例如由/usr/share/doc 要到/usr/share/man 下面时,可以写成“cd ../man”,这就是相对路径的写法。相对路径意指相对于目前工作目录的路径。
相对路径的用途
那么相对路径与绝对路径有什么用处呢?假设你写了一个软件,这个软件共需要三个目录,分别是 etc、bin、man 这三个目录,然而由于不同的人喜欢安装在不同的目录下,假设甲安装的目录是/usr/local/packages/etc、/usr/local/packages/bin 及/usr/local/packages/man,不过乙却喜欢安装在/home/packages/etc、/home/packages/bin,/home/packages/man这三个目录中,请问如果需要用到绝对路径的话,那么是否很麻烦呢?如此一来每个目录下的东西就很难对应起来。这个时候相对路径的写法就显得特别的重要了。
此外,如果你跟鸟哥一样,喜欢将路径的名字写得很长,好让自己知道那个目录是在干什么的 , 例 如 /cluster/raid/output/taiwan2006/smoke 这 个 目 录 , 而 另 一 个 目 录 在/cluster/raid/output/taiwan2006/cctm,那么我要从第一个目录到第二个目录去的话,怎么写比较方便?当然是“cd ../cctm”比较方便了。
绝对路径的用途
但是对于文件名的正确性来说,绝对路径的正确度要比较好。一般来说,鸟哥会建议你,如果是在写程序(shell scripts)来管理系统的条件下,务必使用绝对路径的写法。怎么说呢?因为绝对路径的写法虽然比较麻烦,但是可以肯定这个写法绝对不会有问题。如果使用相对路径在程序当中,则可能由于你执行的工作环境不同,导致一些问题的发生。这个问题在工作调度(at, cron,第 16 章)当中尤其重要。这个现象我们在 13 章讲到 shell scrip时会再次提醒你。
7.1.2 目录的相关操作
我们之前稍微提到切换目录的命令是 cd,还有哪些可以进行目录操作的命令呢?例如创建目录啊、删除目录之类的,还有,得要先知道的,就是有哪些比较特殊的目录呢?举例来说,下面这些就是比较特殊的目录,要记下来:
. 代表此层目录
.. 代表上一层目录
- 代表前一个工作目录
~ 代表“目前用户身份”所在的主文件夹
~account 代表 account 这个用户的主文件夹(account是个账号名称)
需要特别注意的是在所有目录下面都会存在的两个目录,分别是“.”与“..”,分别代表此层与上层目录的意思。那么来思考一下下面这个例题。
请问在Linux下面,根目录下有没有上层目录(..)存在?
答:若使用“ls-al/”去查询,可以看到根目录下确实存在“.”与“..”两个目录,再仔细查阅,可发现这两个目录的属性与权限完全一致,这代表根目录的上一层(..)与根目录自己(.)是同一个目录。
下面我们就来谈一谈几个常见的处理目录的命令吧:
cd:切换目录
pwd:显示当前目录
mkdir:新建一个新的目录
rmdir:删除一个空的目录
cd(切换目录)
我们知道vbird这个用户的主文件夹是/home/vbird/,而root主文件夹则是/root/,假设我以root身份在Linux系统中,那么简单说明一下这几个特殊的目录的意义:
[root@www ~]# cd [相对路径或绝对路径]
最重要的就是目录的绝对路径与相对路径,还有一些特殊目录的符号。
[root@www ~]# cd ~vbird
代表去到 vbird 这个用户的主文件夹,即 /home/vbird。
[root@www vbird]# cd ~
表示回到自己的主文件夹,即是 /root 这个目录。
[root@www ~]# cd
没有加上任何路径,也还是代表回到自己主文件夹的意思。
[root@www ~]# cd ..
表示去到目前的上层目录,即是 /root 的上层目录的意思。
[root@www /]# cd -
表示回到刚才的那个目录,也就是 /root 。
[root@www ~]# cd /var/spool/mail
这个就是绝对路径的写法,直接指定要去的完整路径名称。
[root@www mail]# cd ../mqueue
这个是相对路径的写法,我们由/var/spool/mail 到/var/spool/mqueue 就这样写。
cd 是 Change Directory 的缩写,这是用来切换工作目录的命令。注意,目录名称与 cd 命令之间存在一个空格。一旦登录Linux系统后,root会在root的主文件夹中。那回到上一层目录可以用“cd..”。利用相对路径的写法必须要确认你目前的路径才能正确去到想要去的目录。例如上文中最后一个例子,你必须要确认你是在/var/spool/mail 当中,并且知道在/var/spool当中有个mqueue的目录才行。这样才能使用cd../mqueue到达正确的目录,否则就要直接输入cd/var/spool/mqueue。
其实,我们的提示符,即那个[root@www ~]#当中,就已经有指出当前目录了,刚登录时会回到自己的主文件夹,而主文件夹还有一个代码,那就是“~”符号。例如通过上面的例子可以发现,使用“cd ~”可以回到个人的主文件夹里去。另外,针对 cd 的使用方法,如果仅输入 cd 时,代表的就是“cd ~”的意思,即是会回到自己的主文件夹。而那个“cd– ”比较难以理解,请自行多做几次练习,就会比较明白了。
还是要一再地提醒,我们的Linux的默认命令行模式(bash shell)具有文件补齐功能,你要经常利用[Tab]按键快速完整地输入目录。这是一种好习惯。可以避免你按错键盘输入错字。
pwd(显示目前所在的目录)
[root@www ~]# pwd [-P]
参数:
-P :显示出当前的路径,而非使用连接 (link) 路径。
范例:单纯显示出当前的工作目录:
[root@www ~]# pwd
/root <== 显示出目录
范例:显示出实际的工作目录,而非连接文件本身的目录名而已
[root@www ~]# cd /var/mail <==注意,/var/mail是一个连接文件
[root@www mail]# pwd
/var/mail <==列出目前的工作目录
[root@www mail]# pwd -P
/var/spool/mail <==怎么回事?有没有加 -P 差很多~
[root@www mail]# ls -ld /var/mail
lrwxrwxrwx 1 root root 10 Sep 4 17:54 /var/mail -> spool/mail
看到这里应该知道为啥了吧?因为 /var/mail 是连接文件,连接到 /var/spool/mail。
所以,加上 pwd -P 的参数后,会不以连接文件的数据显示,而是显示正确的完整路径。
pwd 是 Print Working Directory 的缩写,也就是显示目前所在目录的命令,例如上文中最后的目录是/var/mail 这个目录,但是提示符仅显示 mail,如果你想要知道目前所在的目录,可以输入pwd即可。此外,由于很多的套件所使用的目录名称都相同,例如/usr/local/etc,还有/etc,但是通常Linux仅列出最后面那一个目录而已,这个时候你就可以使用pwd来取得你的所在目录,免得搞错目录。
其实有趣的是那个-p的参数。它可以让我们取得正确的目录名称,而不是以连接文件的路径来显示的。如果你使用的是 CentOS 5.x 的话,刚好/var/mail 是/var/spool/mail 的连接文件,所以,通过到/var/mail 执行 pwd -p 就能够知道这个参数的意义了。
mkdir(新建新目录)
[root@www ~]# mkdir [-mp] 目录名称
参数:
-m :配置文件案的权限。直接设置,不需要看默认权限 (umask)
-p :帮助你直接将所需要的目录(包含上层目录)递归创建起来。
范例:请到/tmp下面尝试创建数个新目录看看:
[root@www ~]# cd /tmp
[root@www tmp]# mkdir test <==创建一个名为 test 的新目录
[root@www tmp]# mkdir test1/test2/test3/test4
mkdir: cannot create directory `test1/test2/test3/test4':
No such file or directory <== 没办法直接创建此目录。
[root@www tmp]# mkdir -p test1/test2/test3/test4
加了这个 -p 的参数,可以自行创建多层目录。
范例:新建权限为rwx—x—x的目录
[root@www tmp]# mkdir -m 711 test2
[root@www tmp]# ls -l
drwxr-xr-x 3 root root 4096 Jul 18 12:50 test
drwxr-xr-x 3 root root 4096 Jul 18 12:53 test1
drwx—x—x 2 root root 4096 Jul 18 12:54 test2
仔细看上面的权限部分,如果没有加上 -m 来强制设置属性,系统会使用默认属性。
那么你的默认属性为何?这要通过下面介绍的 umask 才能了解。
如果想要创建新的目录的话,那么就使用 mkdir(make directory)。不过,在默认的情况下,你所需要的目录得一层一层地创建才行!例如:假如你要创建一个目录为/home/bird/testing/test1,那么首先必须要有/home,然后/home/bird、/home/bird/testing都必须要存在,才可以创建/home/bird/testing/test1这个目录。假如没有/home/bird/testing时,就没有办法创建test1的目录。
不过,现在有个更简单有效的方法。那就是加上-p这个参数。你可以直接执行“mkdir-p/home/bird/testing/test1,“则系统会自动帮你将/home、/home/bird、/home/bird/testing依序创建起来,并且如果该目录本来就已经存在时,系统也不会显示错误信息。不过鸟哥不建议常用-p这个参数,因为担心如果你打错字,那么目录名称就会变得乱七八糟的。
另外,有个地方你必须要先有概念,那就是“默认权限“的地方。我们可以利用-m来强制给予一个新的目录相关的权限,例如上文中,我们使用-m 711 来给予新的目录 drwx—x—x的权限。不过,如果没有给予-m参数时,那么默认的新建目录权限又是什么呢?这个跟umask有关,我们在本章后头会加以介绍的。
rmdir(删除“空”的目录)
[root@www ~]# rmdir [-p] 目录名称
参数:
-p :连同上层“空的”目录也一起删除
范例:将mkdir范例中创建的目录(/tmp下面)删除掉。
[root@www tmp]# ls -l <==看看有多少目录存在
drwxr-xr-x 3 root root 4096 Jul 18 12:50 test
drwxr-xr-x 3 root root 4096 Jul 18 12:53 test1
drwx—x—x 2 root root 4096 Jul 18 12:54 test2
[root@www tmp]# rmdir test <==可直接删除掉,没问题
[root@www tmp]# rmdir test1 <==因为尚有内容,所以无法删除。
rmdir: `test1': Directory not empty
[root@www tmp]# rmdir -p test1/test2/test3/test4
[root@www tmp]# ls -l <==你看看,下面的输出中test与test1不见了。
drwx—x—x 2 root root 4096 Jul 18 12:54 test2
利用 -p 这个参数,立刻就可以将 test1/test2/test3/test4 一次删除。
不过要注意的是,这个 rmdir 仅能“删除空的目录”。
如果想要删除旧有的目录时,就使用 rmdir 吧!例如将刚才创建的 test 删掉,使用“rmdir test”即可。目录需要一层一层地删除才行,而且被删除的目录里面必定不能存在其他的目录或文件。这也是所谓的空的目录(empty directory)的意思。那如果要将所有目录下的东西都删掉呢?这个时候就必须使用“rm -r test”了。不过,还是使用 rmdir 比较安全。你也可以尝试以-p的参数加入,来删除上层的目录。
7.1.3 关于执行文件路径的变量:$PATH
经过第6章FHS的说明后,我们知道查看文件属性的命令ls的完整文件名为:/bin/ls(这是绝对路径),那你会不会觉得很奇怪:“为什么我可以在任何地方执行/bin/ls 这个命令呢?为什么我在任何目录下输入ls就一定可以显示出一些信息而不会说找不到该/bin/ls命令呢?”这是因为环境变量PATH的帮助。
当我们在执行一个命令的时候,举例来说“ls”好了,系统会依照PATH的设置去每个PATH定义的目录下查询文件名为ls的可执行文件,如果在PATH定义的目录中含有多个文件名为ls的可执行文件,那么先查询到的同名命令先被执行。
现在,请执行“echo $PATH”来看看到底有哪些目录被定义出来了 echo 有“显示、打印出”的意思,而PATH前面加的$表示后面接的是变量,所以会显示出目前的路径!
范例:先用root的身份列出查询的路径
[root@www ~]# echo $PATH
/usr/kerberos/sbin:/usr/kerberos/bin:/usr/local/sbin:/usr/local/bin:/sbin
:/bin:/usr/sbin:/usr/bin:/root/bin <==这是同一行!
范例:用vbird的身份列出查询的路径
[root@www ~]# su - vbird
[vbird@www ~]# echo $PATH
/usr/kerberos/bin:/usr/local/bin:/bin:/usr/bin:/home/vbird/bin
仔细看,一般用户vbird的PATH中,并不包含任何“sbin”的目录存在喔!
PATH(一定是大写)这个变量的内容是由一堆目录所组成的,每个目录中间用冒号(:)来隔开,每个目录是有“顺序”之分的。仔细看一下上面的输出,你可以发现无论是 root 还是 vbird 都有/bin 这个目录在PATH变量内,所以当然就能够在任何地方执行ls来找到/bin/ls执行文件。
我们用几个范例来让你了解一下为什么PATH是那么重要的项目。
请问你能不能使用一般身份用户执行 ifconfig eth0 这个命令呢?
答:如上面的范例所示,当你使用 vbird 这个账号执行 ifconfig 时,会出现“-bash: ifconfig: command not found”的字样,因为ifconfig是放置到/sbin下面,而由上面的结果中我们可以发现vbird的PATH并没有设置/sbin,所以默认无法执行。
但是你可以使用“/sbin/ifconfig eth0”来执行这个命令。因为一般用户还是可以使用 ifconfig 来查询系统IP的参数,既然PATH没有规范到/sbin,那么我们使用“绝对路径”也可以执行该命令。
假设你是 root,如果你将 ls 由/bin/ls 移动成为/root/ls(可用“mv /bin/ls /root”命令实现),然后你自己本身也在/root目录下,请问(1)你能不能直接输入ls来执行?(2)若不能,你该如何执行ls这个命令?(3)若要直接输入ls即可执行,又该如何进行?
答:由于这个例题的重点是将某个执行文件移动到非正规目录去,所以我们先要进行下面的操作才行(务必使用root的身份):
[root@www ~]# mv /bin/ls /root
mv 为移动,可将文件在不同的目录间进行移动作业
(1)接下来不论你在哪个目录下面输入任何与ls相关的命令,都没有办法顺利执行ls了!也就是说,你不能直接输入ls来执行,因为/root这个目录并不在PATH指定的目录中,所以,即使你在/root目录下,也不能够查询到ls这个命令。
(2)因为这个ls确实存在于/root下面,并不是被删除了。所以我们可以通过使用绝对路径或者是相对路径直接指定这个执行文件,下面的两个方法都能够执行ls这个命令:
[root@www ~]# /root/ls <==直接用绝对路径指定该文件名
[root@www ~]# ./ls <==因为在 /root 目录下,就用./ls来指定
(3)如果想要让root在任何目录均可执行/root下面的ls,那么就将/root加入PATH当中即可。加入的方法很简单,就像下面这样:
[root@www ~]# PATH="$PATH":/root
上面这个做法就能够将/root加入到执行文件查询路径PATH中。不相信的话请你自行使用“echo $PATH”去查看。如果确定这个例题进行没有问题了,请将ls放到/bin下面,不然系统会挂点的。
[root@www ~]# mv /root/ls /bin
如果我有两个ls命令在不同的目录中,例如/usr/local/bin/ls与/bin/ls,那么当我执行ls的时候,哪个ls会被执行?
答:那还用说?就找出PATH里面哪个目录先被查询,则那个目录下的命令就会被先执行了。
为什么PATH查询的目录不加入本目录(.)?加入本目录的查询不是也不错?
答:如果在PATH中加入本目录(.)后,确实我们就能够在命令所在目录进行命令的执行了。但是由于你的工作目录并非固定(经常会使用cd来切换到不同的目录),因此能够执行的命令会有变动(因为每个目录下面的可执行文件都不相同。),这对用户来说并非好事。
另外,如果有个坏心用户在/tmp下面做了一个命令,因为/tmp是大家都能够写入的环境,所以他当然可以这样做。假设该命令可能会窃取用户的一些数据,如果你使用root的身份来执行这个命令,那不是很糟糕?如果这个命令的名称又是经常会被用到的ls时,那“中标”的几率就更高了。
所以,为了安全起见,不建议将“.”加入PATH的查询目录中。
而由上面的几个例题我们也可以知道几件事情:
不同身份用户默认的PATH不同,默认能够随意执行的命令也不同(如root与vbird);
PATH是可以修改的,所以一般用户还是可以通过修改PATH来执行某些位于/sbin或/usr/sbin下的命令来查询;
使用绝对路径或相对路径直接指定某个命令的文件名来执行,会比查询PATH来得正确;
命令应该要放置到正确的目录下,执行才会比较方便;
本目录(.)最好不要放到PATH当中。
对于 PATH 更详细的“变量”说明,我们会在第三篇的 bash shell 中详细说明。
7.2 文件与目录管理
谈了谈目录与路径之后,再来讨论一下关于文件的一些基本管理吧。在文件与目录的管理上,不外乎“显示属性”、“复制”、“删除文件”及“移动文件或目录”等,由于文件与目录的管理在 Linux当中是很重要的,尤其是每个人自己主文件夹的数据也都需要注意管理。所以我们来谈一谈有关文件与目录的一些基础管理部分。
7.2.1 查看文件与目录:ls
[root@www ~]# ls [-aAdfFhilnrRSt]目录名称
[root@www ~]# ls [—color={never,auto,always}]目录名称
[root@www ~]# ls [—full-time]目录名称
参数:
-a :全部的文件,连同隐藏文件( 开头为 . 的文件) 一起列出来(常用)
-A :列出全部的文件(连同隐藏文件,但不包括 . 与 .. 这两个目录)
-d :仅列出目录本身,而不是列出目录内的文件数据(常用)
-f :直接列出结果,而不进行排序 (ls 默认会以文件名排序)
-F :根据文件、目录等信息给予附加数据结构,例如:
*:代表可执行文件; /:代表目录; =:代表 socket 文件; |:代表 FIFO 文件
-h :将文件容量以人类较易读的方式(例如 GB, KB 等)列出来
-i :列出 inode 号码,inode 的意义下一章将会介绍
-l :列出长数据串,包含文件的属性与权限等数据(常用)
-n :列出 UID 与 GID,而非用户与用户组的名称 (UID与GID会在账号管理提到)
-r :将排序结果反向输出,例如:原本文件名由小到大,反向则为由大到小
-R :连同子目录内容一起列出来,等于该目录下的所有文件都会显示出来
-S :以文件容量大小排序,而不是用文件名排序
-t :依时间排序,而不是用文件名
—color=never :不要依据文件特性给予颜色显示
—color=always :显示颜色
—color=auto :让系统自行依据设置来判断是否给予颜色
—full-time :以完整时间模式 (包含年、月、日、时、分) 输出
—time={atime,ctime} :输出访问时间或改变权限属性时间 (ctime)
而非内容更改时间 (modification time)
在Linux系统当中,这个ls命令可能是最常被执行的。因为我们随时都要知道文件或者是目录的相关信息。不过,我们Linux的文件所记录的信息实在是太多了,ls没有需要全部都列出来。所以,当你只有执行ls时,默认显示的只有非隐藏文件的文件名、以文件名进行排序及文件名代表的颜色显示。举例来说,你执行“ls/etc”之后,只有经过排序的文件名以及以蓝色显示目录和白色显示一般文件,如此而已。
那如果我还想要加入其他的显示信息时,可以加入上头提到的那些有用的参数呢。 举例来说,我们之前一直用到的-l 这个长串显示数据内容,以及将隐藏文件也一起列示出来的-a 参数等。下面则是一些常用的范例,实际试做看看:
范例一:将主文件夹下的所有文件列出来(含属性与隐藏文件)
[root@www ~]# ls -al ~
total 156
drwxr-x—- 4 root root 4096 Sep 24 00:07 .
drwxr-xr-x 23 root root 4096 Sep 22 12:09 ..
-rw———- 1 root root 1474 Sep 4 18:27 anaconda-ks.cfg
-rw———- 1 root root 955 Sep 24 00:08 .bash_history
-rw-r—r— 1 root root 24 Jan 6 2007 .bash_logout
-rw-r—r— 1 root root 191 Jan 6 2007 .bash_profile
-rw-r—r— 1 root root 176 Jan 6 2007 .bashrc
drwx——— 3 root root 4096 Sep 5 10:37 .gconf
-rw-r—r— 1 root root 42304 Sep 4 18:26 install.log
-rw-r—r— 1 root root 5661 Sep 4 18:25 install.log.syslog
这个时候你会看到以“.”为开头的几个文件,以及目录文件 (.)、(..)、.gconf 等
不过,目录文件文件名都是以深蓝色显示,有点不容易看清楚就是了。
范例二:承上题,不显示颜色,但在文件名末显示出该文件名代表的类型(type)
[root@www ~]# ls -alF —color=never ~
total 156
drwxr-x—- 4 root root 4096 Sep 24 00:07 ./
drwxr-xr-x 23 root root 4096 Sep 22 12:09 ../
-rw———- 1 root root 1474 Sep 4 18:27 anaconda-ks.cfg
-rw———- 1 root root 955 Sep 24 00:08 .bash_history
-rw-r—r— 1 root root 24 Jan 6 2007 .bash_logout
-rw-r—r— 1 root root 191 Jan 6 2007 .bash_profile
-rw-r—r— 1 root root 176 Jan 6 2007 .bashrc
drwx——— 3 root root 4096 Sep 5 10:37 .gconf/
-rw-r—r— 1 root root 42304 Sep 4 18:26 install.log
-rw-r—r— 1 root root 5661 Sep 4 18:25 install.log.syslog
注意看到显示结果的第一行,知道为何我们会执行类似 ./command
之类的命令了吧?因为 ./ 代表的是“目前目录下”的意思。至于什么是 FIFO/Socket
请参考前一章节的介绍。另外,那个.bashrc 时间仅写2007,能否知道详细时间?
范例三:完整呈现文件的修改时间 *(modification time)
[root@www ~]# ls -al —full-time ~
total 156
drwxr-x—- 4 root root 4096 2008-09-24 00:07:00.000000 +0800 .
drwxr-xr-x 23 root root 4096 2008-09-22 12:09:32.000000 +0800 ..
-rw———- 1 root root 1474 2008-09-04 18:27:10.000000 +0800 anaconda-ks.cfg
-rw———- 1 root root 955 2008-09-24 00:08:14.000000 +0800 .bash_history
-rw-r—r— 1 root root 24 2007-01-06 17:05:04.000000 +0800 .bash_logout
-rw-r—r— 1 root root 191 2007-01-06 17:05:04.000000 +0800 .bash_profile
-rw-r—r— 1 root root 176 2007-01-06 17:05:04.000000 +0800 .bashrc
drwx——— 3 root root 4096 2008-09-05 10:37:49.000000 +0800 .gconf
-rw-r—r— 1 root root 42304 2008-09-04 18:26:57.000000 +0800 install.log
-rw-r—r— 1 root root 5661 2008-09-04 18:25:55.000000 +0800 install.log.syslog
请仔细看,上面的“时间”字段变了。变成较为完整的格式。
一般来说,ls -al 仅列出目前短格式的时间,有时不会列出年份,
通过 —full-time 可以查阅到比较正确的完整时间格式。
其实ls的用法还有很多,包括查看文件所在i-node号码的ls-i参数,以及用来进行文件排序的-s参数,还有用来查看不同时间的操作的—time=atime等参数(更多时间说明请参考本章后面touch的说明)。而这些参数的存在都是因为Linux文件系统记录了很多有用的信息的缘故。那么Linux的文件系统中,这些与权限、属性有关的数据放在哪里呢?放在 i-node 里面。关于这部分,我们会在下一章继续为你作比较深入的介绍。
无论如何,ls 最常被使用到的功能还是那个-l 的参数,为此,很多 distribution 在默认的情况中,已经将 ll(L 的小写)设置成为 ls-l 的意思了。其实,那个功能是 bash shell 的 alias 功能。也就是说,我们直接输入 ll 就等于是输入 ls-l 是一样的。关于这部分,我们会在后续的 bash shell 再次强调。
7.2.2 复制、删除与移动:cp, rm, mv
要复制文件,请使用cp(copy)这个命令即可。不过,cp这个命令的用途可多了。除了单纯复制之外,还可以创建连接文件(就是快捷方式),对比两文件的新旧而予以更新,以及复制整个目录等的功能呢。至于移动目录与文件,则使用mv(move),这个命令也可以直接拿来作重命名(rename)的操作。至于删除,那就是rm(remove)这个命令了。下面我们就来看一看。
cp(复制文件或目录)
[root@www ~]# cp [-adfilprsu] 源文件(source) 目标文件(destination)
[root@www ~]# cp [options] source1 source2 source3 …. directory
参数:
-a :相当于 -pdr 的意思,至于 pdr 请参考后文(常用) ;
-d :若源文件为连接文件的属性(link file),则复制连接文件属性而非文件本身;
-f :为强制(force)的意思,若目标文件已经存在且无法开启,则删除后再尝试一次;
-i :若目标文件(destination)已经存在时,在覆盖时会先询问操作的进行(常用);
-l :进行硬连接(hard link)的连接文件创建,而非复制文件本身;
-p :连同文件的属性一起复制过去,而非使用默认属性(备份常用);
-r :递归持续复制,用于目录的复制行为(常用);
-s :复制成为符号链接文件 (symbolic link),即“快捷方式”文件;
-u :若 destination 比 source 旧才更新 destination。
最后需要注意的,如果源文件有两个以上,则最后一个目的文件一定要是“目录”才行!
复制(cp)这个命令是非常重要的,不同身份者执行这个命令会有不同的结果产生,尤其是那个-a、-p的参数,对于不同身份来说,区别非常大。下面的练习中,有的身份为root,有的身份为一般账号(在我这里用vbird这个账号),练习时请特别注意身份的区别。开始来做复制的练习与查看:
范例一:用root身份将主文件夹下的 .bashrc 复制到 /tmp 下,并更名为 bashrc
[root@www ~]# cp ~/.bashrc /tmp/bashrc
[root@www ~]# cp -i ~/.bashrc /tmp/bashrc
cp: overwrite `/tmp/bashrc'? n <==n不覆盖,y为覆盖
重复做两次操作,由于 /tmp 下面已经存在 bashrc 了,加上 -i 参数后,
则在覆盖前会询问用户是否确定,可以按下 n 或者 y 来二次确认呢!
范例二:切换目录到/tmp,并将/var/log/wtmp复制到/tmp且查看属性:
[root@www ~]# cd /tmp
[root@www tmp]# cp /var/log/wtmp . <==想要复制到当前目录,最后的“.”不要忘
[root@www tmp]# ls -l /var/log/wtmp wtmp
-rw-rw-r— 1 root utmp 96384 Sep 24 11:54 /var/log/wtmp
-rw-r—r— 1 root root 96384 Sep 24 14:06 wtmp
注意上面的特殊字体,在不加任何参数的情况下,文件的某些属性/权限会改变;
这是个很重要的特性,连文件建立的时间也不一样了。
那如果你想要将文件的所有特性都一起复制过来该怎办?可以加上 –a,如下所示:
[root@www tmp]# cp -a /var/log/wtmp wtmp_2
[root@www tmp]# ls -l /var/log/wtmp wtmp_2
-rw-rw-r— 1 root utmp 96384 Sep 24 11:54 /var/log/wtmp
-rw-rw-r— 1 root utmp 96384 Sep 24 11:54 wtmp_2
整个数据特性完全一模一样。这就是 -a 的特性。
这个cp的功能很多,由于我们经常会进行一些数据的复制,所以也会经常用到这个命令的。一般来说,我们如果去复制别人的数据(当然,该文件你必须要有read的权限才行.)时,总是希望复制到的数据最后是我们自己的,所以,在默认的条件中,cp 的源文件与目的文件的权限是不同的,目的文件的所有者通常会是命令操作者本身。举例来说,上面的范例二中,由于我是root的身份,因此复制过来的文件所有者与用户组就改变成为root所有了。
由于具有这个特性,因此当我们在进行备份的时候,某些需要特别注意的特殊权限文件,例如密码文件(/etc/shadow)以及一些配置文件,就不能直接以cp来复制,而必须要加上-a或者是-p等可以完整复制文件权限的参数才行。另外,如果你想要复制文件给其他的用户,也必须要注意到文件的权限(包含读、写、执行以及文件所有者等),否则,其他人还是无法针对你给予的文件进行修订的操作。
范例三:复制 /etc/ 这个目录下的所有内容到 /tmp 下面
[root@www tmp]# cp /etc/ /tmp
cp: omitting directory `/etc' <== 如果是目录则不能直接复制,要加上 -r 的参数
[root@www tmp]# cp -r /etc/ /tmp
还是要再次强调。-r 是可以复制目录,但是,文件与目录的权限可能会被改变
所以,也可以利用“ cp -a /etc /tmp ”来执行命令。尤其是在备份的情况下。
范例四:将范例一复制的 bashrc 创建一个连接文件 (symbolic link)
[root@www tmp]# ls -l bashrc
-rw-r—r— 1 root root 176 Sep 24 14:02 bashrc <==先查看一下文件情况
[root@www tmp]# cp -s bashrc bashrc_slink
[root@www tmp]# cp -l bashrc bashrc_hlink
[root@www tmp]# ls -l bashrc*
-rw-r—r— 2 root root 176 Sep 24 14:02 bashrc <==与源文件不太一样了!
-rw-r—r— 2 root root 176 Sep 24 14:02 bashrc_hlink
lrwxrwxrwx 1 root root 6 Sep 24 14:20 bashrc_slink -> bashrc
范例四可有趣了。使用-l 及-s 都会创建所谓的连接文件(link file),但是这两种连接文件却有不一样的情况。这是怎么一回事啊?那个-l 就是所谓的硬连接(hard link),至于-s 则是软连接(symbolic link),简单来说,bashrc_slink 是一个“快捷方式”,这个快捷方式会连接到bashrc,所以你会看到文件名右侧会有个指向(->)的符号。
至于bashrc_hlink文件与bashrc的属性与权限完全一模一样,与尚未进行连接前的差异则是第二列的link数由1变成2了。这里先不介绍硬连接,因为硬连接涉及i-node的相关知识,我们下一章谈到文件系统(file system)时再来讨论这个问题。
范例五:若 ~/.bashrc 比 /tmp/bashrc 新才复制过来
[root@www tmp]# cp -u ~/.bashrc /tmp/bashrc
这个 -u 的特性是在目标文件与源文件有差异时才会复制的。
所以,比较常被用于“备份”的工作当中。
范例六:将范例四生成的 bashrc_slink 复制成为 bashrc_slink_1 与bashrc_slink_2
[root@www tmp]# cp bashrc_slink bashrc_slink_1
[root@www tmp]# cp -d bashrc_slink bashrc_slink_2
[root@www tmp]# ls -l bashrc bashrc_slink*
-rw-r—r— 2 root root 176 Sep 24 14:02 bashrc
lrwxrwxrwx 1 root root 6 Sep 24 14:20 bashrc_slink -> bashrc
-rw-r—r— 1 root root 176 Sep 24 14:32 bashrc_slink_1 <==与源文件相同
lrwxrwxrwx 1 root root 6 Sep 24 14:33 bashrc_slink_2 -> bashrc <==是连接文件!
这个例子也是很有趣。原本复制的是连接文件,但是却将连接文件的实际文件复制过来了
也就是说,如果没有加上任何参数时,cp复制的是源文件,而非连接文件的属性!
若要复制连接文件的属性,就得要使用 -d 的参数了!如 bashrc_slink_2 所示。
范例七:将主文件夹的 .bashrc 及 .bash_history 复制到 /tmp 下面
[root@www tmp]# cp ~/.bashrc ~/.bash_history /tmp
可以将多个数据一次复制到同一个目录去,最后面一定是目录。
你能否使用vbird的身份,完整复制/var/log/wtmp文件到/tmp下面,并更名为vbird_wtmp呢?答:实际做看看的结果如下:
[vbird@www ~]$ cp -a /var/log/wtmp /tmp/vbird_wtmp
[vbird@www ~]$ ls -l /var/log/wtmp /tmp/vbird_wtmp
-rw-rw-r— 1 vbird vbird 96384 9月 24 11:54 /tmp/vbird_wtmp
-rw-rw-r— 1 root utmp 96384 9月 24 11:54 /var/log/wtmp
由于vbird的身份并不能随意修改文件的所有者与用户组,因此虽然能够复制wtmp的相关权限与时间等属性,但是与所有者、用户组相关的,原本vbird身份无法进行的操作,即使加上-a参数,也是无法达成完整复制权限的!
总之,由于cp有种种的文件属性与权限的特性,所以,在复制时,你必须要清楚了解到:
是否需要完整保留来源文件的信息?
源文件是否为软连接文件(symbolic link file)?
源文件是否为特殊的文件,例如 FIFO、socket 等?
源文件是否为目录?
rm(移除文件或目录)
[root@www ~]# rm [-fir]文件或目录
参数:
-f :就是 force 的意思,忽略不存在的文件,不会出现警告信息;
-i :互动模式,在删除前会询问用户是否操作;
-r :递归删除。最常用在目录的删除了。这是非常危险的参数!!!
范例一:将刚才在 cp 的范例中创建的 bashrc 删除掉!
[root@www ~]# cd /tmp
[root@www tmp]# rm -i bashrc
rm: remove regular file `bashrc'? y
如果加上 -i 的参数就会主动询问,避免你删除错误的文件名!
范例二:通过通配符*的帮忙,将/tmp下面开头为bashrc的文件名全部删除:
[root@www tmp]# rm -i bashrc*
注意那个星号,代表的是 0 到无穷多个任意字符。
范例三:将 cp 范例中所创建的 /tmp/etc/ 这个目录删除掉。
[root@www tmp]# rmdir /tmp/etc
rmdir: etc: Directory not empty <== 删不掉,因为这不是空的目录!
[root@www tmp]# rm -r /tmp/etc
rm: descend into directory `/tmp/etc'? y
….(中间省略)….
因为身份是 root ,默认已经加入了 -i 的参数,所以你要一直按 y 才会删除!
如果不想要继续按 y ,可以按下[ctrl]-c 来结束 rm 的工作。
这是一种保护的操作,如果确定要删除掉此目录而不要询问,可以这样做:
[root@www tmp]# \rm -r /tmp/etc
在命令前加上反斜杠,可以忽略掉 alias 的指定参数。至于 alias 我们在bash章节中再谈。
范例四:删除一个带有 - 开头的文件
[root@www tmp]# touch ./-aaa- <==touch这个命令可以创建空文件。
[root@www tmp]# ls -l
-rw-r—r— 1 root root 0 Sep 24 15:03 -aaa- <==文件大小为0,所以是空文件
[root@www tmp]# rm -aaa-
Try `rm —help' for more information. <== 因为 "-" 是参数。所以系统误判了。
[root@www tmp]# rm ./-aaa-
这是删除(remove)的命令,要注意的是,通常在 Linux 系统下,为了怕文件被误杀,所以很多distributions都已经默认加入-i这个参数了。而如果要连目录下的东西都一起删掉的话,例如子目录里面还有子目录时,那就要使用-r 这个参数了。不过,使用“rm -r”这个命令之前,请千万注意了,因为该目录或文件“肯定”会被 root 删掉,因为系统不会再次询问你是否要删除,所以那是个超级严重的命令执行,得特别注意。不过,如果你确定该目录不要了,那么使用 rm -r 来循环杀掉是不错的方式。
另外,范例四也是很有趣的例子,我们在之前就谈过,文件名最好不要使用"-"号开头,因为"-"后面接的是参数,因此,单纯使用“rm -aaa-”系统的命令就会被误判。那如果使用后面会谈到的正则表达式时,还是会出问题的。所以,只能用避过首位字符是"-"的方法,就是加上本目录“./”即可。如果 man rm 的话,其实还有一种方法,那就是“rm — -aaa- ”也可以。
mv(移动文件与目录,或更名)
[root@www ~]# mv [-fiu] source destination
[root@www ~]# mv [options] source1 source2 source3 …. directory
参数:
-f :force 强制的意思,如果目标文件已经存在,不会询问而直接覆盖;
-i :若目标文件 (destination) 已经存在时,就会询问是否覆盖;
-u :若目标文件已经存在,且 source 比较新,才会更新 (update)。
范例一:复制一个文件,创建一个目录,将文件移动到目录中
[root@www ~]# cd /tmp
[root@www tmp]# cp ~/.bashrc bashrc
[root@www tmp]# mkdir mvtest
[root@www tmp]# mv bashrc mvtest
将某个文件移动到某个目录去,就是这样做!
范例二:将刚才的目录名称重命名为 mvtest2
[root@www tmp]# mv mvtest mvtest2 <== 这样就重命名了。
其实在 Linux 下面还有个有趣的命令,名称为 rename ,
该命令专门进行多个文件名的同时重命名,并非针对单一文件名的更改,与mv不同。请man rename。
范例三:再创建两个文件,再全部移动到 /tmp/mvtest2 当中
[root@www tmp]# cp ~/.bashrc bashrc1
[root@www tmp]# cp ~/.bashrc bashrc2
[root@www tmp]# mv bashrc1 bashrc2 mvtest2
注意这边,如果有多个源文件或目录,则最后一个目标文件一定是“目录”
意思是说,将所有的数据移动到该目录的意思。
这是移动(move)的意思。当你要移动文件或目录的时后,这个命令就很重要。同样,你也可以使用-u(update)来测试新旧文件,看看是否需要移动。另外一个用途就是“更改文件名”,我们可以很轻易地使用mv来更改一个文件的文件名。不过,在Linux才有的命令当中,有个rename可以用来更改大量文件的文件名,你可以利用 man rename 来查阅一下,也是挺有趣的命令。
7.2.3 取得路径的文件名与目录名称
我们前面介绍的完整文件名(包含目录名称与文件名)当中提到,完整文件名最长可以到达 4096个字符。那么你怎么知道哪个是文件名?哪个是目录名?就是利用斜线(/)来分辨。其实,取得文件名或者是目录名称,一般的用途应该是在写程序的时候用来判断使用的。所以,这部分的命令可以用在第三篇内的shell里头。下面我们简单地以几个范例来谈一谈basename与dirname的用途!
[root@www ~]# basename /etc/sysconfig/network
network <== 很简单!就取得最后的文件名。
[root@www ~]# dirname /etc/sysconfig/network
/etc/sysconfig <== 取得目录名。
7.3 文件内容查阅
如果我们要查阅一个文件的内容时,该如何是好呢?这里有相当多有趣的命令可以来分享一下:最常使用的显示文件内容的命令可以说是cat与more及less了。此外,如果我们要查看一个很大型的文件(好几百MB时),但是我们只需要后端的几行字而已,那么该如何是好?用tail呀!此外,tac这个命令也可以达到。先介绍各个命令的用途吧!
cat:由第一行开始显示文件内容。
tac:从最后一行开始显示,可以看出tac是cat的倒写形式。
nl:显示的时候,顺便输出行号。
more:一页一页地显示文件内容。
less:与more类似,但是比more更好的是,它可以往前翻页!
head:只看头几行。
tail:只看结尾几行。
od:以二进制的方式读取文件内容!
7.3.1 直接查看文件内容
直接查看一个文件的内容可以使用cat、tac、nl这几个命令。
cat(concatenate)
[root@www ~]# cat [-AbEnTv]
参数:
-A :相当于 -vET 的整合参数,可列出一些特殊字符,而不是空白而已;
-b :列出行号,仅针对非空白行做行号显示,空白行不标行号;
-E :将结尾的断行字符 $ 显示出来;
-n :打印出行号,连同空白行也会有行号,与 -b 的参数不同;
-T :将 [Tab] 按键以 ^I 显示出来;
-v :列出一些看不出来的特殊字符。
范例一:查看/etc/issue 这个文件的内容
[root@www ~]# cat /etc/issue
CentOS release 5.3 (Final)
Kernel \r on an \m
范例二:承上题,如果还要加印行号呢?
[root@www ~]# cat -n /etc/issue
1 CentOS release 5.3 (Final)
2 Kernel \r on an \m
3
看到了吧!可以印出行号呢!这对于大文件要找某个特定的行时,有点用处!
如果不想要编排空白行的行号,可以使用“cat -b /etc/issue”,自己测试看看:
范例三:将 /etc/xinetd.conf 的内容完整显示出来(包含特殊字符)
[root@www ~]# cat -A /etc/xinetd.conf
$
….(中间省略)….
$
defaults$
{$
The next two items are intended to be a quick access place to$
….(中间省略)….
^Ilog_type^I= SYSLOG daemon info $
^Ilog_on_failure^I= HOST$
^Ilog_on_success^I= PID HOST DURATION EXIT$
….(中间省略)….
includedir /etc/xinetd.d$
$
上面的结果限于篇幅,鸟哥删除掉很多数据了。另外,输出的结果并不会有特殊字体,
鸟哥上面的特殊字体是要让你发现差异点在哪里就是了。基本上,在一般的环境中,
使用 [Tab] 与空格键的效果差不多,都是一堆空白。我们无法知道两者的差别。
此时使用 cat -A 就能够发现那些空白的地方是什么东西了。[Tab]会以 ^I 表示,
断行字符则是以 $ 表示,所以你可以发现每一行后面都是 $ 啊!不过断行字符
在Windows、Linux中则不太相同,Windows的断行字符是 ^M$。
这部分我们会在第10章 vim 软件的介绍时,再次说明到。
Linux里面有“猫”命令?不是的,cat是Concatenate(连续)的简写,主要的功能是将一个文件的内容连续显示在屏幕上面。例如上面的例子中,我们将/etc/issue打印出来。如果加上-n或-b的话,则每一行前面还会加上行号。
鸟哥个人是比较少用cat。毕竟当你的文件内容的行数超过40行以上,根本来不及在屏幕上看到结果。所以,配合等一下要介绍的 more 或者是less来执行比较好,此外,如果是一般的 DOS 文件时,就需要特别留意一些奇怪的符号了,例如断行与[Tab]等,要显示出来,就得加入-a之类的参数了。
tac(反向列示)
[root@www ~]# tac /etc/issue
Kernel \r on an \m
CentOS release 5.3 (Final)
与刚才上面的范例一比较,是由最后一行先显示。
tac这个好玩了。怎么说呢?详细看一下cat与tac,有没有发现什么呀?tac刚好是将cat反写过来,所以它的功能就跟 cat 相反,cat 是由“第一行到最后一行连续显示在屏幕上”,而tac则是“由最后一行到第一行反向在屏幕上显示出来”,很好玩吧!
nl(添加行号打印)
[root@www ~]# nl [-bnw] 文件
参数:
-b :指定行号指定的方式,主要有两种:
-b a :表示不论是否为空行,也同样列出行号(类似 cat -n);
-b t :如果有空行,空的那一行不要列出行号(默认值)。
-n :列出行号表示的方法,主要有三种:
-n ln :行号在屏幕的最左方显示;
-n rn :行号在自己字段的最右方显示,且不加 0 ;
-n rz :行号在自己字段的最右方显示,且加 0。
-w :行号字段占用的位数。
范例一:用 nl 列出 /etc/issue 的内容
[root@www ~]# nl /etc/issue
1 CentOS release 5.3 (Final)
2 Kernel \r on an \m
注意看,这个文件其实有三行,第三行为空白(没有任何字符),
因为它是空白行,所以 nl 不会加上行号。如果确定要加上行号,可以这样做:
[root@www ~]# nl -b a /etc/issue
1 CentOS release 5.3 (Final)
2 Kernel \r on an \m
3
行号加上来,那么如果要让行号前面自动补上 0 呢?可这样:
[root@www ~]# nl -b a -n rz /etc/issue
000001 CentOS release 5.3 (Final)
000002 Kernel \r on an \m
000003
自动在自己字段的地方补上 0 了。默认字段是6位数,如果想要改成 3 位数呢?
[root@www ~]# nl -b a -n rz -w 3 /etc/issue
001 CentOS release 5.3 (Final)
002 Kernel \r on an \m
003
变成仅有 3 位数。
nl 可以将输出的文件内容自动加上行号!其默认的结果与 cat -n 有点不太一样,nl 可以将行号做比较多的显示设计,包括位数与是否自动补0等的功能呢。
7.3.2 可翻页查看
前面提到的nl 与cat、tac 等等,都是一次性将数据一口气显示到屏幕上面,那有没有可以进行一页一页翻动的命令啊?让我们可以一页一页查看,才不会让前面的数据看不到。那就是more与less了。
more(一页一页翻动)
[root@www ~]# more /etc/man.config
#
Generated automatically from man.conf.in by the
configure script.
#
man.conf from man-1.6d
….(中间省略)….
—More—(28%) <== 重点在这一行。你的光标也会在这里等待你的命令。
仔细看看上面的范例,如果more后面接的文件内容行数大于屏幕输出的行数时,就会出现类似上面的图示。重点在最后一行,最后一行会显示出目前显示的百分比,而且还可以在最后一行输入一些有用的命令。在more这个程序的运行过程中,你有几个按键可以按的:
空格键(Space):代表向下翻一页;
Enter :代表向下滚动一行;
/字符串 :代表在这个显示的内容当中,向下查询“字符串”这个关键字;
:f :立刻显示出文件名以及目前显示的行数;
q :代表立刻离开more,不再显示该文件内容。
b或[ctrl]-b :代表往回翻页,不过这操作只对文件有用,对管道无用。
要离开more这个命令的显示工作,可以按下q就能够离开了。而要向下翻页,就使用空格键即可。比较有用的是搜寻字符串的功能,举例来说,我们使用“more /etc/man.config”来查看该文件,若想要在该文件内搜寻MANPATH这个字符串时,可以这样做:
[root@www ~]# more /etc/man.config
#
Generated automatically from man.conf.in by the
configure script.
#
man.conf from man-1.6d
….(中间省略)….
/MANPATH <== 输入了 / 之后,光标就会自动跑到最下面一行等待输入。
如同上面的说明,输入了/之后,光标就会跑到最下面一行,并且等待你的输入,你输入了字符串并按下[Enter]之后,more就会开始向下查询该字符串,而重复查询同一个字符串,可以直接按下 n 即可。最后,不想要看了,就按下 q 即可离开 more 。
less(一页一页翻动)
[root@www ~]# less /etc/man.config
#
Generated automatically from man.conf.in by the
configure script.
#
man.conf from man-1.6d
….(中间省略)….
: <== 这里可以等待你输入命令!
less的用法比起more又更加有弹性,怎么说呢?在使用more的时候,我们并没有办法向前面翻,只能往后面看,但若使用了less时,就可以使用下、下等按键的功能来往前往后翻看文件,你瞧,是不是更容易使用来查看一个文件的内容了呢!
除此之外,在less里头可以拥有更多的查询功能。不只可以向下查询,也可以向上查询,实在是很不错,基本上,可以输入的命令有:
空格键 :向下翻动一页;
[PageDown] :向下翻动一页;
[PageUp] :向上翻动一页;
/字符串 :向下查询“字符串”的功能;
?字符串 :向上查询“字符串”的功能;
n :重复前一个查询(与 / 或 ? 有关);
N :反向重复前一个查询(与 / 或 ? 有关);
q :离开 less这个程序;
查阅文件内容还可以进行查询的操作,瞧!less 是否很不错啊?其实 less 还有很多的功能,详细的使用方式请使用 man less 查询一下。
你是否会觉得 less 使用的界面与环境与 man page 非常的类似呢?没错啦,因为 man 这个命令就是调用less来显示说明文件的内容的。现在你是否觉得less很重要呢?
7.3.3 数据选取
我们可以将输出的数据做一个最简单的选取,那就是取出前面(head)与取出后面(tail)文字的功能。不过,要注意的是,head与tail都是以“行”为单位来进行数据选取的。
head(取出前面几行)
[root@www ~]# head [-n number] 文件
参数:
-n :后面接数字,代表显示几行的意思
[root@www ~]# head /etc/man.config
默认的情况中,显示前10行!若要显示前 20 行,就得要这样:
[root@www ~]# head -n 20 /etc/man.config
范例:如果后面100行的数据都不打印,只打印/etc/man.config的前面几行,该如何是好?
[root@www ~]# head -n -100 /etc/man.config
head的英文意思就是“头”,那么用法自然就是显示出一个文件的前几行。若没有加上-n这个参数时,默认只显示十行,若只要一行呢?那就加入“head -n 1 filename ”即可!
另外那个-n 参数后面的参数较有趣,如果接的是负数,例如上面范例的-n-100 时,代表列出前面的所有行数,但不包括后面100行。举例来说,/etc/man.config共有141行,则上述的命令“head -n -100 /etc/man.config”就会列出前面 41 行,后面 100 行不会打印出来了。
tail (取出后面几行)
[root@www ~]# tail [-n number] 文件
参数:
-n :后面接数字,代表显示几行的意思
-f :表示持续检测后面所接的文件名,要等到按下[ctrl]-c才会结束tail的检测
[root@www ~]# tail /etc/man.config
默认的情况中,显示最后的10行。若要显示最后的 20 行,就得要这样:
[root@www ~]# tail -n 20 /etc/man.config
范例一:如果不知道/etc/man.config有几行,却只想列出100行以后的数据时呢?
[root@www ~]# tail -n +100 /etc/man.config
范例二:持续检测/var/log/messages的内容
[root@www ~]# tail -f /var/log/messages
<==要等到输入[crtl]-c之后才会离开tail这个命令的检测。
有head自然就有tail(尾)。这个tail的用法跟head的用法差不多类似,只是显示的是后面几行就是了。默认也是显示 10 行,若要显示非 10 行,就加-n number 的参数即可。
范 例 一 的 内 容 就 有 趣 了 。 其 实 与 head-n-xx 有 异 曲 同 工 之 妙 。 当 执 行“tail-n+100/etc/man.config,“代表该文件从100行以后都会被列出来,同样,在man.config中共有141行,因此第100~141行就会被列出来,前面的99行都不会被显示出来。
至于范例二中,由于/var/log/messages随时会有数据写入,你想要让该文件有数据写入时就立刻显示到屏幕上,就利用-f这个参数,它可以一直检测/var/log/messages这个文件,新加入的数据都会被显示到屏幕上。直到你按下[crtl]-c才会离开tail的检测。
假如我想要显示/etc/man.config的第11到第20行呢?
答:这个应该不算难,想一想,在第11到第20行,那么我取前20行,再取后10行,所以结果就是“head -n 20 /etc/man.config | tail -n 10”,这样就可以得到第 11 到第 20 行之间的内容了。但是里面涉及到管道命令,第三篇的时候才介绍。
7.3.4 非纯文本文件:od
我们上面提到的都是在查阅纯文本文件的内容。那么万一我们想要查阅非文本文件,举例来说,例如 /usr/bin/passwd 这个执行文件的内容时,又该如何去读出信息呢?事实上,由于执行文件通常是二进制文件(binary file),使用上头提到的命令来读取它的内容时,确实会产生类似乱码的数据。那怎么办?没关系,我们可以利用od这个命令来读取。
[root@www ~]# od [-t TYPE] 文件
参数:
-t :后面可以接各种“类型 (TYPE)”的输出,例如:
a :利用默认的字符来输出;
c :使用 ASCII 字符来输出;
d[size] :利用十进制(decimal)来输出数据,每个整数占用 size bytes ;
f[size] :利用浮点数(floating)来输出数据,每个数占用 size bytes ;
o[size] :利用八进制(octal)来输出数据,每个整数占用 size bytes ;
x[size] :利用十六进制(hexadecimal)来输出数据,每个整数占用 size bytes。
范例一:请将/usr/bin/passwd的内容使用ASCII方式来输出
[root@www ~]# od -t c /usr/bin/passwd
0000000 177 E L F 001 001 001 \0 \0 \0 \0 \0 \0 \0 \0 \0
0000020 002 \0 003 \0 001 \0 \0 \0 260 225 004 \b 4 \0 \0 \0
0000040 020 E \0 \0 \0 \0 \0 \0 4 \0 \0 \a \0 ( \0
0000060 035 \0 034 \0 006 \0 \0 \0 4 \0 \0 \0 4 200 004 \b
0000100 4 200 004 \b 340 \0 \0 \0 340 \0 \0 \0 005 \0 \0 \0
…..(后面省略)….
最左边第一列是以进制来表示bytes数。以上面范例来说,第二列0000020代表开头是
第 16 个 byes 8(2 8)的内容之意。
范例二:请将/etc/issue这个文件的内容以八进制列出存储值与ASCII的对照表
[root@www ~]# od -t oCc /etc/issue
0000000 103 145 156 164 117 123 040 162 145 154 145 141 163 145 040 065
C e n t O S r e l e a s e 5
0000020 056 062 040 050 106 151 156 141 154 051 012 113 145 162 156 145
. 2 ( F i n a l ) \n K e r n e
0000040 154 040 134 162 040 157 156 040 141 156 040 134 155 012 012
l \ r o n a n \ m \n \n
0000057
如上所示,可以发现每个字符可以对应到的数值。
例如e对应的记录数值为145,转成十进制:1x8^2+4x8+5=101。
利用这个命令,可以将数据文件或者是二进制文件的内容数据读出来。虽然读出来的数值默认是使用非文本文件,即是十六进制的数值来显示的,不过,我们还是可以通过-t c 的参数来将数据内的字符以ASCII类型的字符来显示,虽然对于一般用户来说,这个命令的用处可能不大,但是对于工程师来说,这个命令可以将二进制文件的内容作一个大致的输出,他们可以看出其中的含义。
如果对纯文本文件使用这个命令,你甚至可以发现到ASCII与字符的对照表。例如上述的范例二,你可以发现到每个英文字e对照到的数字都是145,转成十进制你就能够发现那是101了。如果你有任何程序语言的书,拿出来对照一下ASCII的对照表,就能够发现真是正确的。
7.3.5 修改文件时间或创建新文件:touch
我们在ls这个命令的介绍时,有稍微提到每个文件在linux下面都会记录许多的时间参数,其实是有三个主要的变动时间,那么三个时间的意义是什么呢?
modification time(mtime)
当该文件的“内容数据”更改时,就会更新这个时间。内容数据指的是文件的内容,而不是文件的属性或权限。
status time(ctime)
当该文件的“状态”(status)改变时,就会更新这个时间,举例来说,像是权限与属性被更改了,都会更新这个时间。
access time(atime)
当“该文件的内容被取用”时,就会更新这个读取时间(access)。举例来说,我们使用cat去读取/etc/man.config,就会更新该文件的atime了。
这是个挺有趣的现象,举例来说,我们来看一看你自己的/etc/man.config这个文件的时间。
[root@www ~]# ls -l /etc/man.config
-rw-r—r— 1 root root 4617 Jan 6 2007 /etc/man.config
[root@www ~]# ls -l —time=atime /etc/man.config
-rw-r—r— 1 root root 4617 Sep 25 17:54 /etc/man.config
[root@www ~]# ls -l —time=ctime /etc/man.config
-rw-r—r— 1 root root 4617 Sep 4 18:03 /etc/man.config
看到了吗?在默认的情况下,ls显示出来的是该文件的mtime,也就是这个文件的内容上次被更改的时间。至于鸟哥的系统是在9月4号的时候安装的,因此,这个文件被产生导致状态被更动的时间就回溯到那个时间点(ctime)了。而还记得刚才我们使用的范例当中,有使用到man.config这个文件,所以,它的atime就会变成刚才使用的时间了。
文件的时间是很重要的,因为,如果文件的时间误判的话,可能会造成某些程序无法顺利运行。那么万一我发现了一个文件来自未来的时间,该如何让该文件的时间变成“现在”的时刻呢?就用“touch”这个命令即可。
不要怀疑系统时间会“来自未来”。很多时候会有这个问题的。举例来说,在安装过后系统时间可能会被改变。因为中国时区在国际标准时间“格林威治时间, GMT”的右边,所以会比较早看到阳光,也就是说,中国时间比GMT时间快了8小时。如果安装不正确,我们的系统可能会有8小时快转,你的文件就有可能来自8小时后了。
至于某些情况下,由于BIOS的设置错误,导致系统时间跑到未来时间,并且你又创建了某些文件。等你将时间改回正确的时间时,该文件不就变成来自未来了?
[root@www ~]# touch [-acdmt] 文件
参数:
-a :仅修改访问时间;
-c :仅修改文件的时间,若该文件不存在则不创建新文件;
-d :后面可以接欲修改的日期而不用目前的日期,也可以使用 —date="日期或时间";
-m :仅修改 mtime ;
-t :后面可以接欲修改的时间而不用目前的时间,格式为[YYMMDDhhmm]。
范例一:新建一个空的文件并查看时间
[root@www ~]# cd /tmp
[root@www tmp]# touch testtouch
[root@www tmp]# ls -l testtouch
-rw-r—r— 1 root root 0 Sep 25 21:09 testtouch
注意到,这个文件的大小是 0 呢!在默认的状态下,如果 touch 后面有接文件,
则该文件的三个时间 (atime、ctime、mtime) 都会更新为目前的时间。若该文件不存在,
则会主动创建一个新的空的文件。例如上面这个例子。
范例二:将 ~/.bashrc 复制成为 bashrc,假设复制完全的属性,检查其日期
[root@www tmp]# cp -a ~/.bashrc bashrc
[root@www tmp]# ll bashrc; ll —time=atime bashrc; ll —time=ctime bashrc
-rw-r—r— 1 root root 176 Jan 6 2007 bashrc <==这是 mtime
-rw-r—r— 1 root root 176 Sep 25 21:11 bashrc <==这是 atime
-rw-r—r— 1 root root 176 Sep 25 21:12 bashrc <==这是 ctime
在上面这个案例当中我们使用了“ll”这个命令(两个英文 L 的小写),这个命令其实就是“ls-l”的意思,ll本身不存在,是被“做出来”的一个命令别名。相关的命令别名我们会在bash章节当中详谈的,这里先知道 ll="ls-l"即可。至于分号“;”则代表连续命令的执行。你可以在一行命令当中写入多条命令,这些命令可以“依序”执行。由上面的命令我们会知道ll那一行有三个命令被执行在同一行中。
至于执行的结果当中,我们可以发现数据的内容与属性是被复制过来的,因此文件内容时间(mtime)与原本文件相同。但是由于这个文件是刚才被创建的,因此状态(ctime)与读取时间便呈现现在的时间。那如果你想要更改这个文件的时间呢?可以这样做:
范例三:修改案例二的 bashrc 文件,将日期调整为两天前
[root@www tmp]# touch -d "2 days ago" bashrc
[root@www tmp]# ll bashrc; ll —time=atime bashrc; ll —time=ctime bashrc
-rw-r—r— 1 root root 176 Sep 23 21:23 bashrc
-rw-r—r— 1 root root 176 Sep 23 21:23 bashrc
-rw-r—r— 1 root root 176 Sep 25 21:23 bashrc
跟上个范例比较看看,本来是 25 日的变成了 23 日了 (atime/mtime)~
不过,ctime 并没有跟着改变。
范例四:将上个范例的 bashrc 日期改为 2007/09/15 2:02
[root@www tmp]# touch -t 0709150202 bashrc
[root@www tmp]# ll bashrc; ll —time=atime bashrc; ll —time=ctime bashrc
-rw-r—r— 1 root root 176 Sep 15 2007 bashrc
-rw-r—r— 1 root root 176 Sep 15 2007 bashrc
-rw-r—r— 1 root root 176 Sep 25 21:25 bashrc
注意看看,日期在 atime 与 mtime 中都改变了,但是 ctime 则是记录目前的时间!
通过touch这个命令,我们可以轻易修改文件的日期与时间,并且也可以创建一个空的文件。不过,要注意的是,即使我们复制一个文件时,复制了所有的属性,但也没有办法复制ctime这个属性的。ctime可以记录这个文件最近的状态(status)被改变的时间。无论如何,还是要告知大家,我们平时看的文件属性中,比较重要的还是属于那个mtime。我们经常关心的是这个文件的“内容”是什么时候被改动过的。
无论如何,touch这个命令最常被使用的情况是:
创建一个空的文件;
将某个文件日期修改为目前日期(mtime与atime)。
7.4 文件与目录的默认权限与隐藏权限
由第6章Linux文件权限的内容我们可以知道一个文件有若干个属性,包括读写执行(r,w,x)等基本权限,以及是否为目录(d)与文件(-)或者是连接文件(l)等的属性。要修改属性的方法在前面也约略提过了(chgrp,chown,chmod),本小节会再加强补充一下。
除了基本r,w,x权限外,在Linux的Ext2/Ext3文件系统下,我们还可以设置其他的系统隐藏属性,这部分可使用chattr来设置,而以lsattr来查看,最重要的属性就是可以设置其不可修改的特性。让连文件的所有者都不能进行修改。这个属性可是相当重要的,尤其是在安全机制方面(security)。
首先,先来复习一下上一章谈到的权限概念,将下面的例题看一看先。
你的系统有个一般身份用户dmtsai,他的用户组属于users,他的主文件夹在/home/dmtsai,你是root,你想将你的~/.bashrc复制给他,可以怎么做?
答:由上一章的权限概念我们可以知道,root 虽然可以将这个文件复制给 dmtsai,不过这个文件在dmtsai的主文件夹中,却可能让dmtsai没有办法读写(因为该文件属于root而dmtsai又不能使用chown之故)。此外,我们又担心覆盖掉dmtsai自己的.bashrc配置文件,因此,我们可以进行如下的操作:
复制文件:cp~/.bashrc~dmtsai/bashrc
修改属性:chowndmtsai:users~dmtsai/bashrc
我想在/tmp下面新建一个目录,这个目录名称为chapter7_1,并且这个目录所有者为dmtsai,用户组为users,此外,任何人都可以进入该目录浏览文件,不过除了dmtsai之外,其他人都不能修改该目录下的文件。
答:因为除了 dmtsai 之外,其他人不能修改该目录下的文件,所以整个目录的权限应该是drwxr-xr-x才对。因此你应该这样做:
新建目录:mkdir/tmp/chapter7_1
修改属性:chown-Rdmtsai:users/tmp/chapter7_1
修改权限:chmod-R755/tmp/chapter7_1
在上面这个例题当中,如果你知道755那个分数是怎么计算出来的,那么你应该对于权限有一定程度的概念了。如果你不知道755怎么来的?赶快回去前一章看看chmod那个命令的介绍部分。这部分很重要。你得要先清楚了解到才行,否则就进行不下去。假设你对于权限都认识得差不多了,那么下面我们就要来谈一谈“新增一个文件或目录时默认的权限是什么”这个话题。
7.4.1 文件默认权限:umask
现在我们知道如何新建或者是改变一个目录或文件的属性了,不过,你知道当你新建一个新的文件或目录时,它的默认权限会是什么吗?那就与umask这个玩意儿有关了。那么umask是在搞什么呢?基本上,umask 就是指定“目前用户在新建文件或目录时候的权限默认值”,那么如何得知或设置umask呢?它的指定条件以下面的方式来指定:
[root@www ~]# umask
0022 <==与一般权限有关的是后面三个数字。
[root@www ~]# umask -S
u=rwx,g=rx,o=rx
查看的方式有两种,一种可以直接输入umask,就可以看到数字形态的权限设置分数,一种则是加入-S(Symbolic)这个参数,就会以符号类型的方式来显示出权限了。奇怪的是,怎么umask会有四组数字啊?不是只有三组吗?是没错。第一组是特殊权限用的,我们先不要理他,所以先看后面三组即可。
在默认权限的属性上,目录与文件是不一样的。从第6章我们知道x权限对于目录是非常重要的。但是一般文件的创建则不应该有执行的权限,因为一般文件通常是用于数据的记录。当然不需要执行的权限了。因此,默认的情况如下:
若用户创建“文件”则默认没有可执行(x)权限,即只有r、w这两个选项,也就是最大为666,默认权限如下:
-rw-rw-rw-
若用户新建“目录”,则由于 x 与是否可以进入此目录有关,因此默认为所有权限均开放,即为777分,默认权限如下:
drwxrwxrwx
要注意的是,umask的分数指的是“该默认值需要减掉的权限”。因为r、w、x分别是4、2、1,也就是说,当要拿掉能写的权限,就是输入 2,而如果要拿掉能读的权限,也就是 4,那么要拿掉读与写的权限,也就是6,而要拿掉执行与写入的权限,也就是3,这样了解吗?请问你,5是什么?就是读与执行的权限。
如果以上面的例子来说明的话,因为umask为022,所以user并没有被拿掉任何权限,不过group与others的权限被拿掉了2(也就是w这个权限),那么当用户:
新建文件时:(-rw-rw-rw-)-(——-w—w-)==>-rw-r—r—
新建目录时:(drwxrwxrwx)-(d——w—w-)==>drwxr-xr-x
不相信吗?我们就来测试看看吧。
[root@www ~]# umask
0022
[root@www ~]# touch test1
[root@www ~]# mkdir test2
[root@www ~]# ll
-rw-r—r— 1 root root 0 Sep 27 00:25 test1
drwxr-xr-x 2 root root 4096 Sep 27 00:25 test2
看见了吧?确定新建文件的权限是没有错的。
umask的利用与重要性:专题制作
想象一个情况,如果你跟你的同学在同一台主机上工作时,因为你们两个正在进行同一个专题,老师也帮你们两个的账号创建好了相同用户组的状态,并且将/home/class/目录作为你们两个人的专题目录。想象一下,有没有可能你所制作的文件你的同学无法编辑?果真如此的话,那就伤脑筋了。
这个问题很常发生啊!举上面的案例来看就好了,你看一下test1的权限是几?644。意思是如果umask设定为022,那新建的数据只有用户自己具有w的权限,同用户组的人只有r这个可读的权限而已,并无法修改。这样要怎么共同制作专题?你说是吧。
所以,当我们需要新建文件给同用户组的用户共同编辑时,那么 umask 的用户组就不能拿掉2这个w的权限。umask就得要是002之类的才可以。这样新建的文件才能够是-rw-rw-r—的权限模样。那么如何设置umask呢?直接在umask后面输入002就好了。
[root@www ~]# umask 002
[root@www ~]# touch test3
[root@www ~]# mkdir test4
[root@www ~]# ll
-rw-rw-r— 1 root root 0 Sep 27 00:36 test3
drwxrwxr-x 2 root root 4096 Sep 27 00:36 test4
所以说,这个umask对于新建文件与目录的默认权限是很有关系的。这个概念可以用在任何服务器上面,尤其是未来在你架设文件服务器,如 SAMBA Server 或者是 FTP Server时,都是很重要的观念。这牵涉到你的用户是否能够将文件进一步利用的问题,不可小看了。
假设你的umask为003,请问该umask情况下,新建的文件与目录权限是什么?
答:umask为003,所以去掉的权限为————wx,因此:
文件:(-rw-rw-rw-)-(————wx)=-rw-rw-r—
目录:(drwxrwxrwx)-(————wx)=drwxrwxr—
关于umask与权限的计算方式中,教科书喜欢使用二进制的方式来进行 AND与NOT的计算,不过,鸟哥还是比较喜欢使用符号方式来计算,联想上面比较容易一点。
但是,有的作者或者是BBS上面的朋友喜欢使用文件默认属性666与目录默认属性777来与umask进行相减的计算,这是不好的。以上面例题来看,如果使用默认属性相加减,则文件变成:666-003=663,即是-rw-rw—wx,这可是完全不对的喔!想想看,原本文件就已经去除x的默认属性了,怎么可能突然间冒出来了?所以,这个地方得要特别小心。
在默认的情况中,root的umask会拿掉比较多的属性,root的umask默认是022,这是基于安全的考虑,至于一般身份用户,通常他们的umask为002,即保留同用户组的写入权利。其实,关于默认umask的设置可以参考/etc/bashrc这个文件的内容,不过,不建议修改该文件,你可以参考第11章bashshell提到的环境参数配置文件(~/.bashrc)的说明。
7.4.2 文件隐藏属性chattr, lsattr
什么?文件还有隐藏属性?光是那9个权限就快要疯掉了,竟然还有隐藏属性,真是要命,但是没办法,就是有文件的隐藏属性存在。不过,这些隐藏的属性确实对于系统有很大的帮助的,尤其是在系统安全(Security)上面,很关键。不过要先强调的是,下面的chattr命令只能在Ext2/Ext3的文件系统上面生效,其他的文件系统可能就无法支持这个命令了。下面我们就来谈一谈如何设置与检查这些隐藏的属性。
chattr(设置文件的隐藏属性)
[root@www ~]# chattr [+-=][ASacdistu] 文件或目录名称
参数:
- :增加某一个特殊参数,其他原本存在参数则不动。
- :删除某一个特殊参数,其他原本存在参数则不动。
= :仅有后面接的参数。
A :当设置了 A 这个属性时,若你有访问此文件(或目录)时,他的访问时间 atime将不会被修改,可避免I/O较慢的机器过度访问磁盘。这对速度较慢的计算机有帮助。
S :一般文件是异步写入磁盘的(原理请参考第5章sync的说明),如果加上 S 这个属性时,当你进行任何文件的修改,该改动会“同步”写入磁盘中。
a :当设置 a 之后,这个文件将只能增加数据,而不能删除也不能修改数据,只有root才能设置这个属性。
c :这个属性设置之后,将会自动将此文件压缩,在读取的时候将会自动解压缩,但是在存储的时候,将会先进行压缩后再存储(看来对于大文件似乎蛮有用的)。
d :当 dump 程序被执行的时候,设置 d 属性将可使该文件(或目录)不会被 dump 备份。
i :这个 i 可就很厉害了。它可以让一个文件“不能被删除、改名,设置连接也无法写入或添加数据。“对于系统安全性有相当大的帮助。只有 root 能设置此属性。
s :当文件设置了 s 属性时,如果这个文件被删除,它将会被完全从这个硬盘空间中删除。
u :与 s 相反,当使用 u 来配置文件时,如果该文件被删除了,则数据内容其实还存在磁盘中,可以使用来找回该文件。
注意:属性设置常见的是 a 与 i 的设置值,而且很多设置值必须要身为 root 才能设置
范例:请尝试到/tmp下面创建文件,并加入 i 的参数,尝试删除看看。
[root@www ~]# cd /tmp
[root@www tmp]# touch attrtest <==创建一个空文件
[root@www tmp]# chattr +i attrtest <==给予 i 的属性
[root@www tmp]# rm attrtest <==尝试删除看看
rm: remove write-protected regular empty file `attrtest'? y
rm: cannot remove `attrtest': Operation not permitted <==操作不许可
看到了吗?连 root 也没有办法将这个文件删除呢!赶紧解除设置!
范例:请将该文件的 i 属性取消。
[root@www tmp]# chattr -i attrtest
这个命令是很重要的,尤其是在系统的数据安全上面!由于这些属性是隐藏的性质,所以需要以lsattr才能看到该属性。其中,个人认为最重要的当属+i与+a这个属性了。+i可以让一个文件无法被更动,对于需要强烈的系统安全的人来说,真是相当重要的。里头还有相当多的属性是需要root才能设置的。
此外,如果是 log file 这种的登录文件,就更需要+a 这个可以增加但是不能修改旧有的数据与删除的参数了。未来提到登录文件(第19章)时,我们再来聊一聊如何设置它。
lsattr(显示文件隐藏属性)
[root@www ~]# lsattr [-adR] 文件或目录
参数:
-a :将隐藏文件的属性也秀出来;
-d :如果接的是目录,仅列出目录本身的属性而非目录内的文件名;
-R :连同子目录的数据也一并列出来!
[root@www tmp]# chattr +aij attrtest
[root@www tmp]# lsattr attrtest
——ia—-j—- attrtest
使用chattr设置后,可以利用lsattr来查看隐藏的属性。不过,这两个命令在使用上必须要特别小心,否则会造成很大的困扰。例如:某天你心情好,突然将/etc/shadow这个重要的密码记录文件设置成为具有i的属性,那么过了若干天之后,你突然要新增用户,却一直无法添加。赶快去将i的属性去掉。
7.4.3 文件特殊权限:SUID, SGID, SBIT
我们前面一直提到关于文件的重要权限,那就是r、w、x这三个读、写、执行的权限。但是,眼尖的朋友们在第6章的目录树章节中,一定注意到了一件事,那就是,怎么我们的/tmp权限有些奇怪?还有,那个/usr/bin/passwd也有些奇怪?怎么回事呢?
[root@www ~]# ls -ld /tmp ; ls -l /usr/bin/passwd
drwxrwxrwt 7 root root 4096 Sep 27 18:23 /tmp
-rwsr-xr-x 1 root root 22984 Jan 7 2007 /usr/bin/passwd
不是应该只有r、w、x吗?还有其他的特殊权限(s跟t)?因为s与t这两个权限的意义与系统的账号(第14章)及系统的进程(process,第17章)较为相关,所以等到后面的章节谈完后你才会比较有概念。下面的说明先看看就好,如果看不懂也没有关系,先知道s放在哪里称为SUID/SGID以及如何设置即可,等系统程序章节读完后,再回来看看。
SetUID
当s这个标志出现在文件所有者的x权限上时,例如刚才提到的/usr/bin/passwd这个文件的权限状态“-rwsr-xr-x”,此时就被称为 Set UID,简称为 SUID 的特殊权限。那么 SUID 的权限对于一个文件的特殊功能是什么呢?基本上SUID有这样的限制与功能:
SUID 权限仅对二进制程序(binary program)有效;
执行者对于该程序需要具有x的可执行权限;
本权限仅在执行该程序的过程中(run-time)有效;
执行者将具有该程序所有者(owner)的权限。
讲这么生硬的东西你可能对于SUID还是没有概念,没关系,我们举个例子来说明好了。我们的 Linux 系统中,所有账号的密码都记录在/etc/shadow 这个文件里面,这个文件的权限为“-r————1 root root”,意思是这个文件仅有 root 可读且仅有 root 可以强制写入而已。既然这个文件仅有root可以修改,那么鸟哥的vbird这个一般账号用户能否自行修改自己的密码呢?你可以使用你自己的账号输入“passwd”这个命令来看看,一般用户当然可以修改自己的密码了!
有没有冲突?明明/etc/shadow就不能让vbird这个一般账户去访问的,为什么vbird还能够修改这个文件内的密码呢?这就是SUID的功能啦!通过上述的功能说明,我们可以知道:
1.vbird对于/usr/bin/passwd这个程序来说是具有x权限的,表示vbird能执行passwd;
2.passwd的拥有者是root这个账号;
3.vbird执行passwd的过程中,会“暂时”获得root的权限;
4./etc/shadow可以被vbird所执行的passwd所修改。
但如果vbird使用cat去读取/etc/shadow时,能够读取吗?因为cat不具有SUID的权限,所以 vbird 执行“cat /etc/shadow”时,是不能读取/etc/shadow 的。我们用一张示意图(图7-1)来说明如下:
图7-1 SUID 程序执行的过程示意图
另外,SUID 仅可用在二进制程序上,不能够用在shell script 上面。这是因为 shell script 只是将很多的二进制执行文件调进来执行而已。所以 SUID 的权限部分,还是得要看 shell script调用进来的程序的设置,而不是 shell script 本身。当然,SUID 对于目录也是无效的,这点要特别留意。
Set GID
当 s 标志在文件所有者的 x 项目为 SUID,那 s 在用户组的 x 时则称为 Set GID, SGID。是这样没错。举例来说,你可以用下面的命令来查看具有SGID权限的文件:
[root@www ~]# ls -l /usr/bin/locate
-rwx—s—x 1 root slocate 23856 Mar 15 2007 /usr/bin/locate
与SUID不同的是,SGID可以针对文件或目录来设置。如果是对文件来说,SGID有如下的功能:
SGID对二进制程序有用;
程序执行者对于该程序来说,需具备x的权限;
执行者在执行的过程中将会获得该程序用户组的支持。
举例来说,上面的/usr/bin/locate 这个程序可以去查询/var/lib/mlocate/mlocate.db 这个文件的内容(详细说明会在下节讲述),mlocate.db的权限如下:
[root@www ~]# ll /usr/bin/locate /var/lib/mlocate/mlocate.db
-rwx—s—x 1 root slocate 23856 Mar 15 2007 /usr/bin/locate
-rw-r——- 1 root slocate 3175776 Sep 28 04:02 /var/lib/mlocate/mlocate.db
与SUID非常类似,若我使用vbird这个账号去执行locate时,那vbird将会取得slocate用户组的支持,因此就能够去读取mlocate.db。
除了二进制程序之外,事实上SGID也能够用在目录上,这也是常见的一种用途。当一个目录设置了SGID的权限后,它将具有如下的功能:
用户若对于此目录具有r与x的权限时,该用户能够进入此目录;
用户在此目录下的有效用户组(effective group)将会变成该目录的用户组;
若用户在此目录下具有w的权限(可以新建文件),则用户所创建的新文件的用户组与此目录的用户组相同。
SGID对于项目开发来说是非常重要的。因为这涉及用户组权限的问题,你可以参考一下本章后续情境模拟的案例,应该就能够对于SGID有一些了解的。
Sticky Bit
这个 Sticky Bit(SBIT)目前只针对目录有效,对于文件已经没有效果了。SBIT 对于目录的作用是:
当用户对于此目录具有w, x 权限,即具有写入的权限时;
当用户在该目录下创建文件或目录时,仅有自己与root才有权利删除该文件。
换句话说:当甲这个用户于A目录是具有用户组或其他人的身份,并且拥有该目录w的权限,这表示甲用户对该目录内任何人新建的目录或文件均可进行删除、重名名/、移动等操作。不过,如果将A目录加上了SBIT的权限项目时,则甲只能够针对自己创建的文件或目录进行删除、重命名、移动等操作,而无法删除他人的文件。
举例来说,我们的/tmp本身的权限是“drwxrwxrwt”,在这样的权限内容下,任何人都可以在/tmp内添加、修改文件,但仅有该文件/目录创建者与root能够删除自己的目录或文件。这个特性也是挺重要的,你可以这样做个简单的测试:
1.以root登录系统,并且进入/tmp当中;
2.touch test,并且更改 test 权限成为 777 ;
3.以一般用户登录,并进入/tmp;
4.尝试删除test这个文件!
由于SUID/SGID/SBIT牵涉到程序的概念,因此再次强调,这部分的数据在你读完第17章关于程序方面的知识后,要再次回来复习一下。目前,你先有个简单的基础概念就好了,文末的参考数据也建议阅读一番。
SUID/SGID/SBIT权限设置
前面介绍过SUID与SGID的功能,那么如何配置文件使其成为具有SUID与SGID的权限呢?这就需要第 6 章的数字更改权限的方法了。现在你应该已经知道数字形态更改权限的方式为“三个数字”的组合,那么如果在这三个数字之前再加上一个数字的话,最前面的那个数字就代表这几个权限了!
4为SUID
2为SGID
1为SBIT
假设要将一个文件权限改为“-rwsr-xr-x”时,由于s在用户权利中,所以是SUID,因此,在原先的 755 之前还要加上 4,也就是用“chmod 4755 filename”来设置。此外,还有大 S与大T的产生,参考下面的范例。
注意:下面的范例只是练习而已,所以鸟哥使用同一个文件来设置,你必须了解 SUID不是用在目录上,而 SBIT 不是用在文件上的。
[root@www ~]# cd /tmp
[root@www tmp]# touch test <==创建一个测试用的空文件
[root@www tmp]# chmod 4755 test; ls -l test <==加入具有 SUID 的权限
-rwsr-xr-x 1 root root 0 Sep 29 03:06 test
[root@www tmp]# chmod 6755 test; ls -l test <==加入具有 SUID/SGID 的权限
-rwsr-sr-x 1 root root 0 Sep 29 03:06 test
[root@www tmp]# chmod 1755 test; ls -l test <==加入 SBIT 的功能
-rwxr-xr-t 1 root root 0 Sep 29 03:06 test
[root@www tmp]# chmod 7666 test; ls -l test <==具有空的 SUID/SGID 权限
-rwSrwSrwT 1 root root 0 Sep 29 03:06 test
最后一个例子就要特别小心,怎么会出现大写的S与T呢?不都是小写的吗?因为s与t都是替代x这个权限的,但是你有没有发现啊?我们是执行7666。也就是说,user,group以及others都没有x这个可执行的标志(因为666),所以,这个S,T代表的就是“空的”。怎么说?SUID是表示该文件在执行的时候具有文件拥有者的权限,但是文件拥有者都无法执行了,哪里来的权限给其他人使用?当然就是空的。
而除了数字法之外,你也可以通过符号法来处理。其中SUID为u+s,而SGID为g+s,SBIT则是o+t,来看看如下的范例:
设置权限成为 -rws—x—x 的模样:
[root@www tmp]# chmod u=rwxs,go=x test; ls -l test
-rws—x—x 1 root root 0 Aug 18 23:47 test
承上,在上述的文件权限中加上 SGID 与 SBIT!
[root@www tmp]# chmod g+s,o+t test; ls -l test
-rws—s—t 1 root root 0 Aug 18 23:47 test
7.4.4 查看文件类型:file
如果你想要知道某个文件的基本数据,例如是属于ASCII或者是data文件,或者是binary,且其中有没有使用到动态函数库(share library)等等的信息,就可以利用file这个命令来查看,举例来说:
[root@www ~]# file ~/.bashrc
/root/.bashrc: ASCII text <==告诉我们是 ASCII 的纯文本文件。
[root@www ~]# file /usr/bin/passwd
/usr/bin/passwd: setuid ELF 32-bit LSB executable, Intel 80386, version 1
(SYSV), for GNU/Linux 2.6.9, dynamically linked (uses shared libs), for
GNU/Linux 2.6.9, stripped
执行文件的数据可就多得不得了!包括这个文件的 suid 权限兼容于 Intel 386
等级的硬件平台、使用的是 Linux 核心 2.6.9 的动态函数库链接等。
[root@www ~]# file /var/lib/mlocate/mlocate.db
/var/lib/mlocate/mlocate.db: data <== 这是 data 文件。
通过这个命令,我们可以简单地先判断这个文件的格式为何。
7.5 命令与文件的查询
文件的查询可就厉害了,因为我们经常需要知道哪个文件放在哪里,才能够对该文件进行一些修改或维护等操作。有些时候某些软件配置文件的文件名是不变的,但是各distribution放置的目录则不同。此时就得要利用一些查询命令将该配置文件的完整文件名找出来,这样才能修改。
7.5.1 脚本文件名的查询
我们知道在终端机模式当中,连续输入两次[Tab]按键就能够知道用户有多少命令可以执行。那你知不知道这些命令的完整文件名放在哪里?举例来说,ls 这个常用的命令放在哪里呢?就通过 which或type来找寻。
which(寻找“执行文件”)
[root@www ~]# which [-a] command
参数:
-a :将所有由 PATH 目录中可以找到的命令均列出,而不只第一个被找到的命令名称
范例一:分别用root与一般账号查询 ifconfig 这个命令的完整文件名
[root@www ~]# which ifconfig
/sbin/ifconfig <==用 root 可以找到正确的执行文件名
[root@www ~]# su - vbird <==切换身份成为 vbird 去!
[vbird@www ~]$ which ifconfig
/usr/bin/which: no ifconfig in (/usr/kerberos/bin:/usr/local/bin:/bin:/usr/bin
:/home/vbird/bin) <==见鬼了!竟然一般身份账号找不到!
因为 which 是根据用户所设置的 PATH 变量内的目录去查找可执行文件的,所以,
不同的 PATH 设置内容所找到的命令当然不一样了。因为 /sbin 不在 vbird 的
PATH 中,找不到也是理所当然的。
[vbird@www ~]$ exit <==记得将身份切换回原本的 root
范例二:用 which 去找出 which 的文件名
[root@www ~]# which which
alias which='alias | /usr/bin/which —tty-only —read-alias —show-dot '/usr/bin/which
竟然会有两个 which,其中一个是 alias,那是啥?
那就是所谓的“命令别名”,意思是输入 which 会等于后面接的那串命令。
更多的数据我们会在 bash 章节中再来谈的。
范例三:请找出 cd 这个命令的完整文件名
[root@www ~]# which cd
/usr/bin/which: no cd in (/usr/kerberos/sbin:/usr/kerberos/bin:/usr/local/sbin
:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin:/root/bin)
怎么可能没有 cd,我明明就能够用 root 执行 cd 的。
这个命令是根据 PATH 这个环境变量所规范的路径去查询“执行文件”的文件名。所以,重点是找出执行文件而已!且which后面接的是完整文件名。若加上-a参数,则可以列出所有的可以找到的同名执行文件,而非仅显示第一个而已。
最后一个范例最有趣,怎么cd这个常用的命令竟然找不到,为什么呢?这是因为cd是bash内置的命令。但是which默认是查找PATH内所规范的目录,所以当然一定找不到的。我们可以通过type这个命令,关于type的用法我们将在第11章的bash再来谈。
7.5.2 文件名的查找
再来谈一谈怎么查找文件。在Linux下面也有相当优异的查找命令。通常find不很常用的,因为速度慢!通常我们都是先使用whereis或者是locate来检查,如果真的找不到了,才以find来查找。为什么呢?因为whereis与locate是利用数据库来查找数据,所以相当快速,而且并没有实际查询硬盘,比较节省时间。
whereis(寻找特定文件)
[root@www ~]# whereis [-bmsu] 文件或目录名
参数:
-b :只找二进制格式的文件
-m :只找在说明文件 manual 路径下的文件
-s :只找 source 源文件
-u :查找不在上述三个选项当中的其他特殊文件
范例一:请用不同的身份找出 ifconfig 这个文件名
[root@www ~]# whereis ifconfig
ifconfig: /sbin/ifconfig /usr/share/man/man8/ifconfig.8.gz
[root@www ~]# su - vbird <==切换身份成为 vbird。
[vbird@www ~]$ whereis ifconfig <==找到同样的结果。
ifconfig: /sbin/ifconfig /usr/share/man/man8/ifconfig.8.gz
[vbird@www ~]$ exit <==切换身份成为 root 。
注意看,明明 which 一般用户找不到的 ifconfig 却可以让 whereis 找到。
这是因为系统真的有 ifconfig 这个“文件”,但是用户的 PATH 并没有加入 /sbin。
所以,未来你找不到某些命令时,先用文件查找命令找找看再说。
范例二:只找出跟 passwd 有关的“说明文件”文件名(man page)
[root@www ~]# whereis -m passwd
passwd: /usr/share/man/man1/passwd.1.gz /usr/share/man/man5/passwd.5.gz
等一下我们会提到find这个查找命令,find是很强大的查找命令,但时间花费的很多。(因为find是直接查找硬盘,如果你的硬盘比较老旧的话,就得等很久了)这个时候whereis就相当好用了。另外,whereis 可以加入参数来找寻相关的数据,例如如果你是要找可执行文件(binary)那么加上-b就可以啦!如果不加任何参数的话,那么就将所有的数据列出来。
那么whereis到底是使用什么呢?为何查找的速度会比find快这么多?其实那也没有什么。这是因为Linux系统会将系统内的所有文件都记录在一个数据库文件里面,而当使用whereis或者是下面要说的 locate 时,都会以此数据库文件的内容为准,因此,有时你还会发现使用这两个执行文件时,会找到已经被删掉的文件!而且也找不到最新的刚才创建的文件呢!这就是因为这两个命令是由数据库当中的结果去查找文件的所在。更多与这个数据库有关的说明,请参考下列的locate命令。
locate
[root@www ~]# locate [-ir] keyword
参数:
-i :忽略大小写的差异;
-r :后面可接正则表达式的显示方式。
范例一:找出系统中所有与 passwd 相关的文件名
[root@www ~]# locate passwd
/etc/passwd
/etc/passwd-
/etc/news/passwd.nntp
/etc/pam.d/passwd
….(下面省略)….
这个 locate 的使用更简单,直接在后面输入“文件的部分名称”后就能够得到结果。举上面的例子来说,我输入 locate passwd,那么在完整文件名(包含路径名称)当中,只要有 passwd在其中,就会被显示出来的!这也是个很方便好用的命令,如果你忘记某个文件的完整文件名时。
但是,这个东西还是有使用上的限制。为什么呢?你会发现使用 locate 来寻找数据的时候特别,这是因为locate寻找的数据是由已创建的数据库/var/lib/mlocate/里面的数据所查找到的,所以不用直接在去硬盘当中访问数据,当然是很快速。
那么有什么限制呢?就是因为它是经由数据库来查找的,而数据库的创建默认是每天执行一次(每个 distribution 都不同,CentOS 5.x 是每天更新数据库一次),所以当你新建文件后查找该文件,那么locate会告诉你“找不到”!因为必须要更新数据库。
那能否手动更新数据库吗?当然可以,更新 locate 数据库的方法非常简单,直接输入“updatedb”就可以了!updatedb命令会去读取/etc/updatedb.conf这个配置文件的设置,嗌然后再去硬盘里面进行查找文件名的操作,最后就更新整个数据库文件 !因为 updatedb会去查找硬盘,所以当你执行updatedb时,可能会等待数分钟的时间。
updatedb:根据/etc/updatedb.conf的设置去查找系统硬盘内的文件名,并更新/var/lib/mlocate内的数据库文件。
locate:依据/var/lib/mlocate内的数据库记载,找出用户输入的关键字文件名。
find
[root@www ~]# find [PATH] [option] [action]
参数:
- 与时间有关的参数:共有 –atime、-ctime 与 -mtime,下面以 -mtime 说明。
-mtime n :n 为数字,意义为在 n 天之前的“一天之内”被更改过的文件;
-mtime +n :列出在 n 天之前(不含 n 天本身)被更改过的文件名;
-mtime -n :列出在 n 天之内(含 n 天本身)被更改过的文件名;
-newer file :file 为一个存在的文件,列出比 file 还要新的文件名。
范例一:将过去系统上面 24 小时内有改动(mtime)的文件列出
[root@www ~]# find / -mtime 0
那个 0 是重点!0 代表目前的时间,所以,从现在开始到 24 小时前,
有改动过内容的文件都会被列出来!那如果是3天前的 24 小时内?
find / -mtime 3 有改动过的文件都被列出的意思。
范例二:寻找 /etc 下面的文件,如果文件日期比 /etc/passwd 新就列出
[root@www ~]# find /etc -newer /etc/passwd
-newer 用在分辨两个文件之间的新旧关系是很有用的!
时间参数真是挺有意思的!我们现在知道atime、ctime与mtime的意义,如果你想要找出一天内被改动过的文件名,可以使用上述范例一的做法。但如果我想要找出“4天内被改动过的文件名”呢?那可以使用“find /var -mtime -4”。那如果是“4 天前的那一天”,就用“find/var -mtime 4”。有没有加上“+, -”差别很大。我们可以用简单的图 7-2 来说明一下。
图7-2 find相关的时间参数意义
图中最右边为目前的时间,越往左边则代表越早之前的时间轴。由图7-2所示我们可以清楚地知道:
+4 代表大于等于5 天前的文件名:ex> find /var -mtime +4
-4 代表小于等于4 天内的文件名:ex> find /var -mtime -4
4 则是代表4~5 那一天的文件名:ex> find /var -mtime 4
非常有趣吧!你可以在/var/目录下查找一下,感受一下输出文件的差异。再来看其他 find 的用法。
参数:
- 与用户或用户组名有关的参数:
-uid n :n 为数字,这个数字是用户的账号 ID,即 UID,这个 UID 是记录在/etc/passwd 里面与账号名称对应的数字。这方面我们会在第四篇介绍。
-gid n :n 为数字,这个数字是用户组名的 ID,即 GID,这个 GID 记录在/etc/group中,相关的介绍我们会第四篇说明~
-user name :name 为用户账号名称。例如 dmtsai。
-group name:name 为用户组名,例如 users。
-nouser :寻找文件的所有者不存在 /etc/passwd 的人。
-nogroup :寻找文件的所有用户组不存在于 /etc/group中的文件。当你自行安装软件时,很可能该软件的属性当中并没有文件所有者,这是可能的,在这个时候,就可以使用 -nouser 与 -nogroup 查找。
范例三:查找 /home 下面属于 vbird 的文件
[root@www ~]# find /home -user vbird
这个东西也很有用的,当我们要找出任何一个用户在系统当中的所有文件时,
就可以利用这个命令将属于某个用户的所有文件都找出来。
范例四:查找系统中不属于任何人的文件
[root@www ~]# find / -nouser
通过这个命令,可以轻易就找出那些不太正常的文件。
如果有找到不属于系统任何人的文件时,不要太紧张,
那有时候是正常的,尤其是你曾经以源码自行编译软件时。
如果你想知道某个用户在系统下面创建了什么,使用上述的参数就能够找出来。至于那个-nouser或-nogroup的参数功能中,除了你自行由网络上面下载文件时会发生之外,如果你将系统里面某个账号删除了,但是该账号已经在系统内创建很多文件时,就可能会发生无主孤魂的文件存在!此时你就得使用这个-nouser来找出该类型的文件。
参数:
- 与文件权限及名称有关的参数:
-name filename:查找文件名为 filename 的文件。
-size [+-]SIZE:查找比 SIZE 还要大(+)或小(-)的文件。这个 SIZE 的规格有:c: 代表 byte,k: 代表 1024bytes。所以,要找比 50KB还要大的文件,就是“ -size +50k ”。
-type TYPE :查找文件的类型为 TYPE 的,类型主要有:一般正规文件 (f)、设备文件 (b, c)、目录 (d)、连接文件 (l)、socket (s)、及 FIFO (p) 等属性。
-perm mode :查找文件权限“刚好等于”mode 的文件,这个 mode 为类似 chmod的属性值,举例来说,-rwsr-xr-x 的属性为 4755 。
-perm -mode :查找文件权限“必须要全部包括 mode 的权限”的文件,举例来说,我们要查找 -rwxr—r—,即 0744 的文件,使用 -perm -0744,当一个文件的权限为 -rwsr-xr-x,即 4755 时,也会被列出来,因为 -rwsr-xr-x 的属性已经包括了 -rwxr—r— 的属性了。
-perm +mode :查找文件权限“包含任一 mode 的权限”的文件,举例来说,我们查找-rwxr-xr-x,即 -perm +755 时,但一个文件属性为 -rw———-也会被列出来,因为它有 –rw… 的属性存在。
范例五:找出文件名为 passwd的这个文件
[root@www ~]# find / -name passwd
利用这个 -name 可以查找文件名。
范例六:找出 /var 目录下文件类型为 Socket 的文件名有哪些
[root@www ~]# find /var -type s
这个 -type 的属性也很有帮助。尤其是要找出那些怪异的文件,
例如 socket 与 FIFO 文件,可以用 find /var -type p 或 -type s 来找!
范例七:查找文件当中含有 SGID 或 SUID 或 SBIT 的属性
[root@www ~]# find / -perm +7000
所谓的 7000 就是 —-s—s—t,那么只要含有 s 或 t 的就列出,
所以当然要使用 +7000,使用 -7000 表示要含有 —-s—s—t 的所有三个权限,
因此,就是 +7000 。
上述范例中比较有趣的是-perm这个参数。它的重点在找出特殊权限的文件。我们知道SUID与SGID都可以设置在二进制程序上,假设我想要将/bin、/sbin这两个目录下只要具有SUID或SGID的文件就列出来,你可以这样做:
[root@www ~]# find /bin /sbin -perm +6000
因为SUID是4分,SGID是2分,总共为6分,因此可用+6000来处理这个权限。至于find后面可以接多个目录来进行查找,另外,find本来就会查找子目录,这个也要特别注意。最后,我们再来看一下find还有什么特殊功能。
参数:
- 其他可进行的操作:
-exec command :command 为其他命令,-exec 后面可再接其他的命令来处理查找到的结果。
-print :将结果打印到屏幕上,这个操作是默认操作。
范例八:将上个范例找到的文件使用 ls -l 列出来。
[root@www ~]# find / -perm +7000 -exec ls -l {} \;
注意到,那个 -exec 后面的 ls -l 就是额外的命令,命令不支持命令别名,
所以仅能使用 ls –l,不可以使用 ll ,特别注意。
范例九:找出系统中大于 1MB 的文件
[root@www ~]# find / -size +1000k
虽然在 man page中提到可以使用 M 与 G 分别代表 MB 与 GB,
不过,我却试不出来这个功能。所以,目前应该是仅支持到 c 与 k 。
find 的特殊功能就是能够进行额外的动作(action)。我们将范例八的例子以图解来说明,如图7-3所法。
图7-3 find相关的额外命令
该范例中特殊的地方有“{}”以及“\;”,还有-exec这个关键字,这些东西的意义为:
{}代表的是“由find找到的内容”,如上图所示,find的结果会被放置到{}位置中。
-exec一直到“\;”是关键字,代表find额外命令的开始(-exec)到结束(\;),在这中间的就是find 命令内的额外命令。在本例中就是“ls -l {}”。
因为“;”在bash环境下是有特殊意义的,因此利用反斜杠来转义。
通过图7-3你应该就比较容易了解-exec到“\;”之间的意义了吧!
如果你要找的文件是具有特殊属性的,例如SUID、文件所有者、文件大小等,那么利用locate是没有办法达成你的查找的。此时 find 就显得很重要啦!另外,find 还可以利用通配符来找寻文件名。举例来说,你想要找出/etc下面文件名包含httpd的文件,那么你就可以这样做:
[root@www ~]# find /etc -name 'httpd'
不但可以指定查找的目录(连同子目录),并且可以利用额外的参数来找到最正确的文件名。
7.6 权限与命令间的关系(极重要)
我们知道权限对于用户账号来说是非常重要的,因为它可以限制用户能不能读取/新建/删除/修改文件或目录。在这一章我们介绍了很多文件系统的管理命令,第 6 章则介绍了很多文件权限的意义。在这个小节当中,我们就将这两者结合起来,说明一下什么命令在什么样的权限下才能够运行。
让用户能进入某目录成为“可工作目录”的基本权限是什么
可使用的命令:例如cd等切换工作目录的命令。
目录所需权限:用户对这个目录至少需要具有x的权限。
额外需求:如果用户想要在这个目录内利用ls查阅文件名,则用户对此目录还需要r的权限。
用户在某个目录内读取一个文件的基本权限是什么
可使用的命令:例如本章谈到的 cat, more, less 等。
目录所需权限:用户对这个目录至少需要具有x权限。
文件所需权限:用户对文件至少需要具有r的权限才行!
让用户可以修改一个文件的基本权限是什么
可使用的命令:例如nano或未来要介绍的vi编辑器等。
目录所需权限:用户在该文件所在的目录至少要有x权限。
文件所需权限:用户对该文件至少要有 r, w 权限。
让一个用户可以创建一个文件的基本权限是什么
目录所需权限:用户在该目录要具有w, x 的权限,重点在w。
让用户进入某目录并执行该目录下的某个命令的基本权限是什么
目录所需权限:用户在该目录至少要有x的权限。
文件所需权限:用户在该文件至少需要有x的权限。
让一个用户vbird能够进行“cp/dir1/file1/dir2”的命令时,请说明dir1, file1, dir2的最小所需权限。
答:执行cp时,vbird要能够读取源文件,并且写入目标文件。所以应参考上述第二点与第四点的说明,因此各文件/目录的最小权限应该是:
dir1:至少需要有 x 权限;
file1:至少需要有 r 权限;
dir2:至少需要有 w, x 权限。
有一个文件全名为/home/student/www/index.html,各相关文件/目录的权限如下:
drwxr-xr-x 23 root root 4096 Sep 22 12:09 /
drwxr-xr-x 6 root root 4096 Sep 29 02:21 /home
drwx——— 6 student student 4096 Sep 29 02:23 /home/student
drwxr-xr-x 6 student student 4096 Sep 29 02:24 /home/student/www
-rwxr—r— 6 student student 369 Sep 29 02:27 /home/student/www/index.html
请问vbird这个账号(不属于student用户组)能否读取index.html这个文件呢?
答:虽然www与index.html是可以让vbird读取的权限,但是因为目录结构是由根目录一层一层读取的,因此vbird可进入/home但是却不可进入/home/student/,既然连进入/home/student都不许了,当然就读不到index.html了!所以答案是“vbird不会读取到index.html的内容”。
那要如何修改权限呢?其实只要将/home/student的权限修改为最小711,或者直接给予755就可以。这可是很重要的概念。
7.7 重点回顾
绝对路径“一定由根目录/写起”;相对路径“不是由/写起”。
特殊目录有., .., -, ~, ~account,需要注意。
与目录相关的命令有 cd, mkdir, rmdir, pwd 等重要命令。
rmdir 仅能删除空目录,要删除非空目录需使用“rm -r”命令。
用户能使用的命令是依据PATH变量所规定的目录去查找的。
不同的身份(root与一般用户)系统默认的PATH并不相同。差异较大的地方在于/sbin和/usr/sbin。
ls 可以查看文件的属性,尤其-d, -a, -l 等参数特别重要!
文件的复制、删除、移动可以分别使用 cp, rm , mv 等命令来操作。
检查文件的内容(读文件)可使用的命令包括 cat, tac, nl, more, less, head, tail, od等。
cat -n 与 nl 均可显示行号,但默认的情况下,空白行会不会编号并不相同。
touch的目的在修改文件的时间参数,但也可用来创建空文件。
一个文件记录的时间参数有三种,分别是 access time(atime), status time (ctime), modification time(mtime),ls默认显示的是mtime。
除了传统的rwx权限之外,在Ext2/Ext3文件系统中,还可以使用chattr与lsattr设置及查看隐藏属性。常见的包括只能新增数据的+a与完全不能更动文件的+i属性。
新建文件/目录时,新文件的默认权限使用umask来规范。默认目录完全权限为drwxrwxrwx,文件则为-rw-rw-rw-。
文件具有 SUID 的特殊权限时,代表当用户执行此二进制程序时,在执行过程中用户会暂时具有程序所有者的权限。
目录具有SGID 的特殊权限时,代表用户在这个目录下面新建的文件用户组都会与该目录的用户组名相同。
目录具有SBIT的特殊权限时,代表在该目录下用户创建的文件只有自己与root能够删除!
查看文件的类型可以使用file命令来查看。
查找命令的完整文件名可用which或type,这两个命令都是通过PATH变量来查找文件名。
要查找文件的完整文件名可以使用whereis或locate到数据库文件去查找,而不实际查找文件系统。
利用find可以加入许多参数来直接查询文件系统,以获得自己想要知道的文件名。
7.8 本章习题
情境模拟题
假设系统中有两个账号,分别是 alex 与 arod,这两个人除了自己用户组之外还共同支持一个名为 project 的用户组。假设这两个用户需要共同拥有/srv/ahome/目录的开发权,且该目录不许其他人进入查阅。请问该目录的权限应设置为什么?请先以传统权限说明,再以SGID的功能解析。
目标:了解到为何项目开发时目录最好需要设置SGID的权限。
前提:多个账号支持同一用户组,且共同拥有目录的使用权!
需求:需要使用root的身份来进行chmod、chgrp等操作帮用户设置好他们的开发环境才行,这也是管理员的重要任务之一。
首先我们得要先制作出这两个账号的相关数据,账号/用户组的管理在后续我们会介绍,你这里先照着下面的命令来制作即可:
[root@www ~]# groupadd project <==增加新的用户组
[root@www ~]# useradd -G project alex <==新建 alex 账号,且支持 project
[root@www ~]# useradd -G project arod <==新建 arod 账号,且支持 project
[root@www ~]# id alex <==查阅 alex 账号的属性
uid=501(alex) gid=502(alex) groups=502(alex),501(project) <==确实有支持!
[root@www ~]# id arod
uid=502(arod) gid=503(arod) groups=503(arod),501(project)
然后开始来解决我们所需要的环境吧!
1.首先新建所需要开发的项目目录:
[root@www ~]# mkdir /srv/ahome
[root@www ~]# ll -d /srv/ahome
drwxr-xr-x 2 root root 4096 Sep 29 22:36 /srv/ahome
2.从上面的输出结果可发现alex与arod都不能在该目录内创建文件,因此需要进行权限与属性的修改。由于其他人均不可进入此目录,因此该目录的用户组应为project,权限应为770才合理。
[root@www ~]# chgrp project /srv/ahome
[root@www ~]# chmod 770 /srv/ahome
[root@www ~]# ll -d /srv/ahome
drwxrwx—- 2 root project 4096 Sep 29 22:36 /srv/ahome
从上面的权限结果来看,由于 alex/arod 均支持 project,因此似乎没问题了!
3.实际分别以两个用户来测试看看,情况会是如何?先用alex新建文件,然后用arod去处理看看。
[root@www ~]# su - alex <==先切换身份成为 alex 来处理
[alex@www ~]$ cd /srv/ahome <==切换到用户组的工作目录去
[alex@www ahome]$ touch abcd <==新建一个空的文件出来
[alex@www ahome]$ exit <==离开 alex 的身份
[root@www ~]# su - arod
[arod@www ~]$ cd /srv/ahome
[arod@www ahome]$ ll abcd
-rw-rw-r— 1 alex alex 0 Sep 29 22:46 abcd
仔细看一下上面的文件,由于用户组是 alex,
因此对于 abcd 这个文件来说,arod 应该只是其他人,只有 r 的权限而已啊!
[arod@www ahome]$ exit
由上面的结果我们可以知道,若单纯使用传统的rwx而已,则对刚才alex新建的abcd这个文件来说,arod可以删除它,但是却不能编辑它。这不是我们要的样子,赶紧来重新规划一下。
4.加入SGID的权限在里面,并进行测试看看:
[root@www ~]# chmod 2770 /srv/ahome
[root@www ~]# ll -d /srv/ahome
drwxrws—- 2 root project 4096 Sep 29 22:46 /srv/ahome
测试:使用 alex 去创建一个文件,并且查阅文件权限看看:
[root@www ~]# su - alex
[alex@www ~]$ cd /srv/ahome
[alex@www ahome]$ touch 1234
[alex@www ahome]$ ll 1234
-rw-rw-r— 1 alex project 0 Sep 29 22:53 1234
这才是我们要的样子。现在 alex、arod 创建的新文件所属用户组都是 project,
由于两人均属于此用户组,加上 umask 都是 002,这样两人才可以互相修改对方的文件!
所以最终的结果显示,此目录的权限最好是“2770”,文件所有者属于root即可,至于用户组必须要为两人共同支持的project这个用户组才行!
简答题部分
什么是绝对路径与相对路径?
如何更改一个目录的名称?例如由/home/test变为/home/test2。
PATH这个环境变量的意义是什么?
umask有什么用处与优点?
当一个用户的umask分别为033与044,他所建立的文件与目录的权限是什么?
什么是SUID?
当我要查询/usr/bin/passwd这个文件的传统权限、文件类型与文件的隐藏属性,可以使用什么命令来查询?
尝试用find找出目前Linux系统中所有具有SUID的文件有哪些。
找出/etc下面,文件大小介于50KB到60KB之间的文件,并且将权限完整地列出(ls-l)。
找出/etc下面,文件容量大于50KB且文件所有者不是root的文件名,且将权限完整地列出(ls-l)。
找出/etc下面,容量大于1500KB以及容量等于0的文件。
7.9 参考数据与扩展阅读
网友小洲回复SUID/SGID的一篇帖子: