鸟哥的 Linux 私房菜 -- 档案与目录管理

since2012/04/23

     
 
最近更新日期:2006/08/22
本文已不再维护,更新文章请参考此处
在前一章节里面我们认识了 Linux 系统下的档案权限概念以及目录的配置说明。 在这个章节当中,我们就直接来进一步的操作与管理档案与目录吧!包括在不同的目录间变换、 建立与删除目录、建立与删除档案,还有寻找档案、查阅档案内容等等, 都会在这个章节作个简单的介绍啊!

大标题的图示目录与路径:
由前一章节『Linux 的档案权限与目录配置』中约略了解到 Linux 的『树状目录』概念之后,接下来就得要实际的来搞定一些基本的路径问题了!这些目录的问题当中, 最重要的莫过于『绝对路径』与『相对路径』的意义啦!赶紧来了解一下!


小标题的图示相对路径与绝对路径:
在开始目录的切换之前,你必须要先了解一下所谓的『路径 (PATH)』, 有趣的是:什么是『相对路径』与『绝对路径』? 虽然前一章已经稍微针对这个议题提过一次,不过,这里不厌其烦的再次的强调一下!

如果你还记得前一章的内容的话,那么应该还记得 Linux 里面的目录是呈现『树状目录』 的情况,就是有分支的啦!好了,假设你需要在任意一个目录下变换到根目录的 etc 底下,那么你就应该要使用『 cd /etc 』这个情况, 这也就是所谓的『绝对路径』,他是从根目录连续写上来的一个情况, 所以不论你在哪一个路径现执行这一个指令,都会将你移动到该路径下。那如果我是使用 『cd etc 』呢?那表示你要切换到『目前这个目录下的 etc 目录中』,情况可是不一样的呦!通常第一次接触 Linux 的使用者常会搞错这一个路径的观念!
  • 绝对路径:路径的写法『一定由根目录 / 写起』,例如: /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 这三个目录中,请问如果需要用到绝对路径的话,那么是否很麻烦呢?是的! 如此一来每个目录下的东西就很难对应的起来!这个时候相对路径的写法就显的特别的重要了!

此外,如果您跟鸟哥一样,喜欢将路径的名字写的很长,好让自己知道那个目录是在干什么的,例如: /data4/staiwan19961109/models-3/smoke 这个目录,而另一个目录在 /data4/staiwan19961109/models-3/cctm ,那么我从第一个要到第二个目录去的话,怎么写比较方便? 当然是『 cd ../cctm 』比较方便啰!对吧!

但是对于档案的正确性来说,『绝对路径的正确度要比较好~』。 一般来说,鸟哥会建议您,如果是在写程序 (shell scripts) 的条件下,务必使用绝对路径的写法。 怎么说呢?因为绝对路径的写法虽然比较麻烦,但是可以肯定这个写法绝对不会有问题。 如果使用相对路径在程序当中,则可能由于您执行的工作环境不同,导致一些问题的发生。 这个问题在例行性命令当中尤其重要!这个现象我们在 shell script 时,会再次的提醒您喔! ^_^

小标题的图示目录的相关操作:
在之前我们稍微提到这个变换目录的指令是 cd ,还有哪些可以进行目录操作的指令呢? 例如建立目录啊、删除目录之类的~还有,得要先知道的,就是有哪些比较特殊的目录呢? 举例来说,底下这些就是比较特殊的目录,得要用力的记下来才行:
.         代表此层目录
..        代表上一层目录
-         代表前一个工作目录
~         代表『目前用户身份』所在的家目录
~account  代表 account 这个用户的家目录
在目录底下有两个目录是一定会存在的!那就是 . 与 .. 啰~ 分别代表此层与上层目录的意思。那我们在前一章 Linux 文件属性与目录配置 里面也知道根目录 (/) 是所有目录的最顶层,那么 / 有 .. 吗?!您可以使用 ls -al / 去看看, 答案是『有的!』不过,您也可以查阅到,根目录的 . 与 .. 属性完全一模一样,哈哈! 原来根目录的顶层 (..) 与他自己 (.) 是同一个目录啦! ^_^

底下我们就来谈一谈几个常见的处理目录的指令吧:
  • cd:变换目录
  • pwd:显示当前目录
  • mkdir:建立一个新的目录
  • rmdir:删除一个空的目录

  • cd (变换目录)
  • 我们知道 dmtsai 这个用户的家目录是 /home/dmtsai ,而 root 家目录则是 /root ,假设我以 root 身份在 Linux 系统中,那么简单的说明一下这几个特殊的目录的意义是:
    [root@linux ~]# cd [相对路径或绝对路径]
    # 最重要的就是目录的绝对路径与相对路径,还有一些特殊目录的符号啰!
    [root@linux ~]# cd ~dmtsai
    # 代表去到 dmtsai 这个用户的家目录,亦即 /home/dmtsai
    [root@linux dmtsai]# cd ~
    # 表示回到自己的家目录,亦即是 /root 这个目录
    [root@linux ~]# cd
    # 没有加上任何路径,也还是代表回到自己家目录的意思喔!
    [root@linux ~]# cd ..
    # 表示去到目前的上层目录,亦即是 /root 的上层目录的意思;
    [root@linux /]# cd -
    # 表示回到刚刚的那个目录,也就是 /root 啰~
    [root@linux ~]# cd /var/spool/mail
    # 这个就是绝对路径的写法!直接指定要去的完整路径名称!
    [root@linux mail]# cd ../mqueue
    # 这个是相对路径的写法,我们由 /var/spool/mail 去到 /var/spool/mqueue 就这样写!
    
    cd 是 Change Directory 的缩写,这是用来变换工作目录的指令。注意,目录名称与 cd 指令之间存在一个空格。 一登入 Linux 系统后,root 会在 root 的家目录,亦即 /root 下,OK!那回到上一层目录可以用『 cd .. 』。 利用相对路径的写法必须要确认您目前的路径才能正确的去到想要去的目录。例如上表当中最后一个例子, 您必须要确认您是在 /var/spool/mail 当中,并且知道在 /var/spool 当中有个 mqueue 的目录才行啊~ 这样才能使用 cd ../mqueue 去到正确的目录说,否则就要直接输入 cd /var/spool/mqueue 啰~

    其实,我们的提示字符,亦即那个 [root@linux ~]# 当中,就已经有指出当前目录了, 刚登入时会到自己的家目录,而家目录还有一个代码,那就是『 ~ 』符号! 例如上面的例子可以发现,使用『 cd ~ 』可以回到个人的家目录里头去呢! 另外,针对 cd 的使用方法,如果仅输入 cd 时,代表的就是『 cd ~ 』的意思喔~ 亦即是会回到自己的家目录啦!而那个『 cd - 』比较难以理解,请自行多做几次练习, 就会比较明白了。
    Tips:
    还是要一再地提醒,我们的 Linux 的默认指令列模式 (bash shell) 具有档案补齐功能, 您要常常利用 [tab] 按键来达成您的目录完整性啊!这可是个好习惯啊~ 可以避免您按错键盘输入错字说~ ^_^
    鸟哥的图示

  • pwd (显示目前所在的目录)
  • [root@linux ~]# pwd [-P]
    参数:
    -P  :显示出确实的路径,而非使用链接 (link) 路径。
    范例:
    [root@linux ~]# pwd
    /root   <== 显示出目录啦~
    [root@linux ~]# cd /var/mail
    [root@linux mail]# pwd
    /var/mail
    [root@linux mail]# pwd -P
    /var/spool/mail   <== 怎么回事?有没有加 -P 差很多~
    [root@linux mail]# ls -l /var/mail
    lrwxrwxrwx  1 root root 10 Jun 25 08:25 /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 的参数啦!他可以让我们取得正确的目录名称,而不是以链接文件的路径来显示的。 如果您是 Fedora Core 4 的话,刚刚好, /var/mail 是 /var/spool/mail 的连结档, 所以,透过到 /var/mail 下达 pwd -P 就能够知道这个参数的意义啰~ ^_^


  • mkdir (建立新目录)
  • [root@linux ~]# mkdir [-mp] 目录名称
    参数:
    -m :配置文件案的权限喔!直接设定,不需要看预设权限 (umask) 的脸色~
    -p :帮助你直接将所需要的目录递归建立起来!
    范例:
    [root@linux ~]# cd /tmp
    [root@linux tmp]# mkdir test    <== 建立一名为 test 的新目录
    [root@linux tmp]# mkdir test1/test2/test3/test4
    mkdir: cannot create directory `test1/test2/test3/test4': 
    No such file or directory  <== 没办法直接建立此目录啊!
    [root@linux tmp]# mkdir -p test1/test2/test3/test4
    # 加了这个 -p 的参数,可以自行帮您建立多层目录!
    [root@linux tmp]# mkdir -m 711 test2
    [root@linux 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 依序的建立起目录!并且, 如果该目录本来就已经存在时,系统也不会显示错误讯息喔!挺快乐的吧! ^_^

    另外,有个地方您必须要先有概念,那就是『预设权限』的地方。我们可以利用 -m 来强制给予一个新的目录相关的属性, 例如上表当中,我们给予 -m 711 来给予新的目录 drwx--x--x 的属性。不过,如果没有给予 -m 属性时, 那么默认的新建目录属性又是什么呢?这个跟 umask 有关,我们在后头会加以介绍的。


  • rmdir (删除『空』的目录)
  • [root@linux ~]# rmdir [-p] 目录名称
    参数:
    -p :连同上层『空的』目录也一起删除
    范例:
    [root@linux 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@linux tmp]# rmdir test
    [root@linux tmp]# rmdir test1
    rmdir: `test1': Directory not empty
    [root@linux tmp]# rmdir -p test1/test2/test3/test4
    [root@linux tmp]# ls -l
    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 -rf test 啰!不过,还是使用 rmdir 比较不危险!不过,你也可以尝试以 -p 的参数加入,来删除上层的目录喔!

    小标题的图示关于执行文件路径的变量: $PATH
    在提过了绝对路径、相对路径与指令的下达方式之后,您应该会稍微注意到一件事情,那就是:『 为什么我可以在任何地方执行 /bin/ls 这个指令呢? 』对呀! 为什么我可以直接执行 ls 就一定可以显示出一些讯息而不会说找不到该 /bin/ls 指令呢? 这是因为环境变量 PATH 的帮助所致呀!当我们在执行一个指令的时候, 系统会依照 PATH 的设定去每个 PATH 定义的路径下搜寻执行文件,先搜寻到的指令先被执行之!现在,请下达 echo $PATH , echo 有『显示、印出』的意思,而 PATH 前面加的 $ 表示后面接的是变量,所以即会显示出目前的 PATH 了!
    [root@linux ~]# echo $PATH
    /sbin:/usr/sbin:/bin:/usr/bin:/usr/X11R6/bin:/usr/local/bin:/usr/local/sbin
    
    注意到了吗?对啦! /bin 在 PATH 的设定之中,所以自然就可以找的到 ls 啦! PATH 对于执行档来说,是个很重要的『变量』,他主要是用来规范指令搜寻的目录。 而每个目录是有顺序的,每个目录中间以冒号『:』来分隔,就如同上面范例中提到的啰! 那么 PATH 这个变量还有什么地方重要呢?
    • 如果你将 ls 移动到 /root 底下的话 (mv /bin/ls /root) ,然后你自己本身也在 /root 底下 (cd /root) ,但是当你执行 ls 的时候,他就是不理你?怎么办?这是因为 PATH 这个变量没有 /root 这个目录,而你又将 ls 移动到 /root 底下了,自然系统就找不到可执行文件了,因此就会告诉你, command not found !那么该怎么克服这种问题呢?有两个方法,其一:直接将 /root 的路径加入 PATH 当中!如何增加?可以使用:
      [root@linux ~]# PATH="$PATH":/root
      
      这种方式来增加 PATH 搜寻目录即可!另一种方式则是使用完整文件名来下达指令, 亦即直接使用相对或绝对路径来执行,例如:
      [root@linux ~]# /root/ls
      [root@linux ~]# ./ls
      
      因为在同一个目录中,而我们又知道在同一个目录中的目录符号为『 . 』,因此,就以上面的 ./ls 来执行也可以!这种执行方式以后您应该会很常见到才对!

    • 如果我有两个 ls 档案在不同的目录中,例如 /usr/local/bin/ls 底下与 /bin/ls 那么当我下达 ls 的时候,哪个 ls 会被执行?那还用说,就找出 PATH 里面哪个目录先被查询,则那个目录下的档案就会被先执行了!

    • 咦!既然如此的话,那么为何不要在 PATH 里面加入 . 这个目录,如此一来的话, 不就可以直接在所在目录执行档案了吗?因为 . 代表所在目录嘛!是这样没错!但是有没有想过,如果某天, 某个怪怪的使用者在 /tmp 里面写了一个 ls 的档案,偏偏他是有害的档案,那么当你在 /tmp 底下执行 ls 时,怎么办?!没错,可能会『中标』,所以啰,为了安全起见,不建议将『 . 』加入 PATH 的搜寻当中!
    关于更多的 PATH 与相关的『变量』及『环境变量』概念,我们会在第三篇 bash shell 时, 再更深入的介绍啰~而经过上面的说明,您应该也能够比较了解的是:『 为什么绝对路径下达指令的方法比相对路径要正确的多 』这句话的意义啰~ ^_^ 因为是直接找到该指令来执行,而不是透过 PATH 这个变量的内容去搜寻的啊!

    大标题的图示档案与目录管理:
    谈了谈目录与路径之后,再来讨论一下关于档案的一些基本管理吧!档案与目录的管理上,不外乎『显示属性』、 『拷贝』、『删除档案』及『移动档案或目录』等等,由于档案与目录的管理在 Linux 当中是很重要的! 尤其是每个人自己家目录的数据也都需要注意管理!由于我们在执行程序的时后,系统默认有一个搜寻的路径顺序, 如果有两个以上相同档名的执行档分别在不同的路径时,呵呵,就需要特别留意啰! 这里我们来谈一谈有关档案与目录的一些基础管理部分吧!


    小标题的图示档案与目录的检视: ls
    [root@linux ~]# ls [-aAdfFhilRS] 目录名称
    [root@linux ~]# ls [--color={none,auto,always}] 目录名称
    [root@linux ~]# ls [--full-time] 目录名称
    参数:
    -a  :全部的档案,连同隐藏档( 开头为 . 的档案) 一起列出来~
    -A  :全部的档案,连同隐藏档,但不包括 . 与 .. 这两个目录,一起列出来~
    -d  :仅列出目录本身,而不是列出目录内的档案数据
    -f  :直接列出结果,而不进行排序 (ls 预设会以档名排序!)
    -F  :根据档案、目录等信息,给予附加数据结构,例如:
          *:代表可执行文件; /:代表目录; =:代表 socket 档案; |:代表 FIFO 档案;
    -h  :将档案容量以人类较易读的方式(例如 GB, KB 等等)列出来;
    -i  :列出 inode 位置,而非列出文件属性;
    -l  :长数据串行出,包含档案的属性等等数据;
    -n  :列出 UID 与 GID 而非使用者与群组的名称 (UID与GID会在账号管理提到!)
    -r  :将排序结果反向输出,例如:原本档名由小到大,反向则为由大到小;
    -R  :连同子目录内容一起列出来;
    -S  :以档案容量大小排序!
    -t  :依时间排序
    --color=never  :不要依据档案特性给予颜色显示;
    --color=always :显示颜色
    --color=auto   :让系统自行依据设定来判断是否给予颜色
    --full-time    :以完整时间模式 (包含年、月、日、时、分) 输出
    --time={atime,ctime} :输出 access 时间或 改变权限属性时间 (ctime) 
                           而非内容变更时间 (modification time)
    范例:
    
    在 Linux 系统当中,这个 ls 指令可能是最常被执行的吧!因为我们随时都要知道档案或者是目录的相关信息啊~ 不过,我们 Linux 的档案所记录的信息实在是太多了, ls 没有需要全部都列出来呢~ 所以,当您只有下达 ls 时,默认显示的只有:非隐藏档的档名、 以档名进行排序及文件名代表的颜色显示;如此而已。举例来说, 您下达 ls /etc 之后,只有经过排序的文件名以及以蓝色显示目录及白色显示一般档案,如此而已。

    那如果我还想要加入其他的显示信息时,可以加入上头提到的那些有用的参数呢~ 举例来说,我们之前一直用到的 -l 这个长串显示数据内容,以及将隐藏档也一起列示出来的 -a 参数等等。
    范例一:将家目录下的所有档案列出来(含属性与隐藏文件)
    [root@linux ~]# ls -al ~
    total 252
    drwxr-x---   9 root root  4096 Jul 16 23:40 .
    drwxr-xr-x  24 root root  4096 Jul 16 23:45 ..
    -rw-------   1 root root  1491 Jun 25 08:53 anaconda-ks.cfg
    -rw-------   1 root root 12543 Jul 18 01:23 .bash_history
    -rw-r--r--   1 root root    24 Dec  4  2004 .bash_logout
    -rw-r--r--   1 root root   191 Dec  4  2004 .bash_profile
    -rw-r--r--   1 root root   395 Jul  4 11:45 .bashrc
    -rw-r--r--   1 root root 68495 Jun 25 08:53 install.log
    -rw-r--r--   1 root root  5976 Jun 25 08:53 install.log.syslog
    drwx------   2 root root  4096 Jul  4 16:03 .ssh
    -rw-------   1 root root 12613 Jul 16 23:40 .viminfo
    # 这个时候您会看到以 . 为开头的几个档案,以及目录文件 ./../.ssh 等等,
    # 不过,目录文件都是以深蓝色显示,有点不容易看清楚就是了。
    
    范例二:承上题,不显示颜色,但在文件名末显示出该文件名代表的类型(type)
    [root@linux ~]# ls -alF --color=never  ~
    total 252
    drwxr-x---   9 root root  4096 Jul 16 23:40 ./
    drwxr-xr-x  24 root root  4096 Jul 16 23:45 ../
    -rw-------   1 root root  1491 Jun 25 08:53 anaconda-ks.cfg
    -rw-------   1 root root 12543 Jul 18 01:23 .bash_history
    -rw-r--r--   1 root root    24 Dec  4  2004 .bash_logout
    -rw-r--r--   1 root root   191 Dec  4  2004 .bash_profile
    -rw-r--r--   1 root root   395 Jul  4 11:45 .bashrc
    -rw-r--r--   1 root root 68495 Jun 25 08:53 install.log
    -rw-r--r--   1 root root  5976 Jun 25 08:53 install.log.syslog
    drwx------   2 root root  4096 Jul  4 16:03 .ssh/
    -rw-------   1 root root 12613 Jul 16 23:40 .viminfo
    # 注意看到显示结果的第一行,嘿嘿~知道为何我们会下达类似 ./command 
    # 之类的指令了吧?因为 ./ 代表的是『目前目录下』的意思啊!至于什么是 FIFO/Socket ?
    # 请参考前一章节的介绍啊!
    
    范例三:完整的呈现档案的修改时间 *(modification time)
    [root@linux ~]# ls -al --full-time  ~
    total 252
    drwxr-x---   9 root root  4096 2005-07-16 23:40:13.000000000 +0800 .
    drwxr-xr-x  24 root root  4096 2005-07-16 23:45:05.000000000 +0800 ..
    -rw-------   1 root root  1491 2005-06-25 08:53:37.000000000 +0800 anaconda-ks.cfg
    -rw-------   1 root root 12543 2005-07-18 01:23:33.000000000 +0800 .bash_history
    -rw-r--r--   1 root root    24 2004-12-04 05:44:13.000000000 +0800 .bash_logout
    -rw-r--r--   1 root root   191 2004-12-04 05:44:13.000000000 +0800 .bash_profile
    -rw-r--r--   1 root root   395 2005-07-04 11:45:16.000000000 +0800 .bashrc
    -rw-r--r--   1 root root 68495 2005-06-25 08:53:34.000000000 +0800 install.log
    -rw-r--r--   1 root root  5976 2005-06-25 08:53:28.000000000 +0800 install.log.syslog
    drwx------   2 root root  4096 2005-07-04 16:03:24.000000000 +0800 .ssh
    -rw-------   1 root root 12613 2005-07-16 23:40:13.000000000 +0800 .viminfo
    # 请仔细看,上面的『时间』字段变了喔!变成较为完整的格式。
    # 一般来说, ls -al 仅列出目前短格式的时间,有时不会列出年份,
    # 藉由 --full-time 可以查阅到比较正确的完整时间格式啊!
    
    其实 ls 的用法还有很多,包括查阅档案所在 i-node 的 ls -i 参数,以及用来进行档案排序的 -S 参数,还有用来查阅不同时间的动作的 --time=atime 等参数。而这些参数的存在都是因为 Linux 文件系统记录了很多有用的信息的缘故。那么 Linux 的文件系统中,这些与权限、属性有关的数据放在哪里呢? 放在 i-node 里面。关于这部分,我们会在下个章节继续跟您作比较深入的介绍啊!

    无论如何, ls 最常被使用到的功能还是那个 -l 的参数,为此,很多 distribution 在预设的情况中, 已经将 ll (L 的小写) 设定成为 ls -l 的意思了!其实,那个功能是 Bash shell 的 alias 功能呢~ 也就是说,我们直接输入 ll 就等于是输入 ls -l 是一样的~关于这部分,我们会在第三章 bash shell 时再次的强调滴~


    小标题的图示复制、移动与删除: cp, rm, mv
    要复制档案,请使用 cp (copy) 这个指令即可~不过, cp 这个指令的用途可多了~ 除了单纯的复制之外,还可以建立连结档 (就是快捷方式啰),比对两档案的新旧而予以更新, 以及复制整个目录等等的功能呢!至于移动目录与档案,则使用 mv (move), 这个指令也可以直接拿来作更名 (rename) 的动作喔!至于移除吗?那就是 rm (remove) 这个指令啰~底下我们就来瞧一瞧先~


  • cp (复制档案或目录)
  • [root@linux ~]# cp [-adfilprsu] 来源档(source) 目的檔(destination)
    [root@linux ~]# cp [options] source1 source2 source3 .... directory
    参数:
    -a  :相当于 -pdr 的意思;
    -d  :若来源文件为链接文件的属性(link file),则复制链接文件属性而非档案本身;
    -f  :为强制 (force) 的意思,若有重复或其他疑问时,不会询问使用者,而强制复制;
    -i  :若目的檔(destination)已经存在时,在覆盖时会先询问是否真的动作!
    -l  :进行硬式连结 (hard link) 的连结档建立,而非复制档案本身;
    -p  :连同档案的属性一起复制过去,而非使用默认属性;
    -r  :递归持续复制,用于目录的复制行为;
    -s  :复制成为符号链接文件 (symbolic link),亦即『快捷方式』档案;
    -u  :若 destination 比 source 旧才更新 destination !
    最后需要注意的,如果来源档有两个以上,则最后一个目的文件一定要是『目录』才行!
    范例:
    范例一:将家目录下的 .bashrc 复制到 /tmp 下,并更名为 bashrc
    [root@linux ~]# cd /tmp
    [root@linux tmp]# cp ~/.bashrc bashrc
    [root@linux tmp]# cp -i ~/.bashrc bashrc
    cp: overwrite `basrhc'? n
    # 重复作两次动作,由于 /tmp 底下已经存在 bashrc 了,加上 -i 参数,
    # 则在覆盖前会询问使用者是否确定!可以按下 n 或者 y 呢!
    # 但是,反过来说,如果不想要询问时,则加上 -f 这个参数来强制直接覆盖!
    
    范例二:将 /var/log/wtmp 复制到 /tmp 底下
    [root@linux tmp]# cp /var/log/wtmp . <==想要复制到当前目录,最后的 . 不要忘
    [root@linux tmp]# ls -l /var/log/wtmp wtmp
    -rw-rw-r--  1 root utmp 71808 Jul 18 12:46 /var/log/wtmp
    -rw-r--r--  1 root root 71808 Jul 18 21:58 wtmp
    # 注意到了吗?!在不加任何参数的情况下,档案的所属者会改变,连权限也跟着改变了~
    # 这是个很重要的特性!要注意喔!还有,连档案建立的时间也不一样了!
    # 如果您想要将档案的所有特性都一起复制过来,可以加上 -a 喔!
    [root@linux tmp]# cp -a /var/log/wtmp wtmp_2
    [root@linux tmp]# ls -l /var/log/wtmp wtmp_2
    -rw-rw-r--  1 root utmp 71808 Jul 18 12:46 /var/log/wtmp
    -rw-rw-r--  1 root utmp 71808 Jul 18 12:46 wtmp_2
    # 瞭了吧!整个资料特性完全一模一样ㄟ!真是不赖~这就是 -a 的特性!
    
    范例三:复制 /etc/ 这个目录下的所有内容到 /tmp 底下
    [root@linux tmp]# cp /etc/ /tmp
    cp: omitting directory `/etc'   <== 如果是目录,不能直接复制,要加上 -r 的参数
    [root@linux tmp]# cp -r /etc/ /tmp
    # 还是要再次的强调喔! -r 是可以复制目录,但是,档案与目录的权限会被改变~
    # 所以,也可以利用 cp -a /etc /tmp 来下达指令喔!
    
    范例四:将范例一复制的 bashrc 建立一个连结档 (symbolic link)
    [root@linux tmp]# ls -l bashrc
    -rw-r--r--  1 root root 395 Jul 18 22:08 bashrc
    [root@linux tmp]# cp -s bashrc bashrc_slink
    [root@linux tmp]# cp -l bashrc bashrc_hlink
    [root@linux tmp]# ls -l bashrc*
    -rw-r--r--  2 root root 395 Jul 18 22:08 bashrc
    -rw-r--r--  2 root root 395 Jul 18 22:08 bashrc_hlink
    lrwxrwxrwx  1 root root   6 Jul 18 22:31 bashrc_slink -> bashrc
    # 那个 bashrc_slink 是由 -s 的参数造成的,建立的是一个『快捷方式』,
    # 所以您会看到在档案的最右边,会显示这个档案是『连结』到哪里去的!
    # 至于那个 bashrc_hlink 有趣了!建立了这个档案之后, bashrc 与 bashrc_hlink 
    # 所有的参数都一样,只是,第二栏的 link 数改变成为 2 了~而不是原本的 1 喔!
    # 这两种连结的方式的异同,我们会在下一章里面进行介绍的!
    
    范例五:若 ~/.bashrc 比 /tmp/bashrc 新才复制过来
    [root@linux tmp]# cp -u ~/.bashrc /tmp/bashrc
    # 这个 -u 的特性,是在目标档案与来源档案有差异时,才会复制的。
    # 所以,比较常被用于『备份』的工作当中喔! ^_^
    
    范例六:将范例四造成的 bashrc_slink 复制成为 bashrc_slink_2
    [root@linux tmp]# cp bashrc_slink bashrc_slink_2
    [root@linux tmp]# ls -l bashrc_slink*
    lrwxrwxrwx  1 root root   6 Jul 18 22:31 bashrc_slink -> bashrc
    -rw-r--r--  1 root root 395 Jul 18 22:48 bashrc_slink_2
    # 这个例子也是很有趣喔!原本复制的是连结档,但是却将连结档的实际档案复制过来了
    # 也就是说,如果没有加上任何参数时,复制的是源文件,而非链接文件的属性!
    # 若要复制链接文件的属性,就得要使用 -d 或者 -a 的参数了!
    
    范例七:将家目录的 .bashrc 及 .bash_history 复制到 /tmp 底下
    [root@linux tmp]# cp ~/.bashrc ~/.bash_history /tmp
    # 可以将多个数据一次复制到同一个目录去!
    
    这个 cp 的功能很多,而由于我们常常在进行一些数据的复制,所以也会常常用到这个指令的。 一般来说,我们如果去复制别人的数据 (当然,该档案您必须要有 read 的权限才行啊! ^_^) 时, 总是希望复制到的数据最后是我们自己的,所以,在预设的条件中, cp 的来源档与目的档的权限是不同的,目的档的拥有者通常会是指令操作者本身。举例来说, 上面的范例二中,由于我是 root 的身份,因此复制过来的档案拥有者与群组就改变成为 root 所有了! 这样说,可以明白吗?! ^_^

    由于具有这个特性,因此,当我们在进行备份的时候,某些需要特别注意的特殊权限档案, 例如密码文件 (/etc/shadow) 以及一些配置文件,就不能直接以 cp 来复制,而必须要加上 -a 或者是 -p 等等可以完整复制档案权限的参数才行!另外,如果您想要复制档案给其他的使用者, 也必须要注意到档案的权限(包含读、写、执行以及档案拥有者等等), 否则,其他人还是无法针对您给予的档案进行修订的动作喔!注意注意!

    至于上面的范例当中,第四个范例是最有趣的,使用 -l 及 -s 都会建立所谓的连结档 (link file), 但是这两种连结档确有不一样的展现情况。这是怎么一回事啊? 那个 -l 就是所谓的 hard link ,至于 -s 则是 symbolic link ,鸟哥这里先不介绍, 因为这个涉及 i-node 的相关知识,我们还没有介绍到,下一章再来讨论这个 link 的问题喔! 总之,由于 cp 有种种的文件属性与权限的特性,所以,在复制时,您必须要清楚的了解到:
    • 是否需要完整的保留来源档案的信息?
    • 来源档案是否为连结档 (symbolic link file)?
    • 来源档是否为特殊的档案,例如 FIFO, socket 等?
    • 来源文件是否为目录?

  • rm (移除档案或目录)
  • [root@linux ~]# rm [-fir] 档案或目录
    参数:
    -f  :就是 force 的意思,强制移除;
    -i  :互动模式,在删除前会询问使用者是否动作
    -r  :递归删除啊!最常用在目录的删除了
    范例:
    范例一:建立一档案后予以删除
    [root@linux ~]# cd /tmp
    [root@linux tmp]# cp ~/.bashrc bashrc
    [root@linux tmp]# rm -i bashrc
    rm: remove regular file `bashrc'? y
    # 如果加上 -i 的参数就会主动询问喔!那么如果不要询问呢?就加 -f 参数啊!
    
    范例二:删除一个不为空的目录
    [root@linux tmp]# mkdir test
    [root@linux tmp]# cp ~/.bashrc test/ <== 将档案复制到此目录去,就不是空的目录了
    [root@linux tmp]# rmdir test
    rmdir: `test': Directory not empty <== 删不掉啊!因为这不是空的目录!
    [root@linux tmp]# rm -rf test
    
    范例三:删除一个带有 - 开头的档案
    [root@linux tmp]# ls *aa*
    -rw-r--r--  1 root  root      0 Aug 22 10:52 -aaa-
    [root@linux tmp]# rm -aaa-
    rm: invalid option -- a
    Try `rm --help' for more information.  <== 因为 "-" 是参数嘛!
    [root@linux tmp]# rm ./-aaa-
    
    这是移除的指令( remove ),相当于 dos 下的 del 指令!这里要注意的是,通常在 Linux 系统下,为了怕档案被误杀,所以很多 distributions 都已经预设有 -i 这个参数, -i 是指每个档案被杀掉之前都会让使用者确认一次,以预防误杀档案!而如果要连目录下的东西都一起杀掉的话, 例如子目录里面还有子目录时,那就要使用 -rf 这个参数了!不过,使用『 rm -rf 』这个指令之前,请千万注意了,因为,该目录或档案『肯定』会被 root 杀掉!因为系统不会再次询问你是否要砍掉呦!所以那是个超级严重的指令下达呦! 得特别注意!不过,如果你确定该目录不要了,那么使用 rm -rf 来循环杀掉是不错的方式!

    另外,范例三也是很有趣的例子,我们在之前就谈过,档名最好不要使用 "-" 号开头, 因为 "-" 后面接的是参数,因此,单纯的使用『 rm -aaa- 』系统的指令就会误判啦! 那如果使用后面会谈到的正规表示法时,还是会出问题的!所以,只能用避过首位字符是 "-" 的方法啦! 就是加上本目录『 ./ 』即可!如果 man rm 的话,其实还有一种方法,那就是『 rm -- -aaa- 』也可以啊!


  • mv (移动档案与目录,或更名)
  • [root@linux ~]# mv [-fiu] source destination
    [root@linux ~]# mv [options] source1 source2 source3 .... directory
    参数:
    -f  :force 强制的意思,强制直接移动而不询问;
    -i  :若目标档案 (destination) 已经存在时,就会询问是否覆盖!
    -u  :若目标档案已经存在,且 source 比较新,才会更新 (update)
    范例:
    范例一:复制一档案,建立一目录,将档案移动到目录中
    [root@linux ~]# cd /tmp
    [root@linux tmp]# cp ~/.bashrc bashrc
    [root@linux tmp]# mkdir mvtest
    [root@linux tmp]# mv bashrc mvtest
    # 将某个档案移动到某个目录去,就是这样做!
    
    范例二:将刚刚的目录名称更名为 mvtest2
    [root@linux tmp]# mv mvtest mvtest2 <== 这样就更名了!简单~
    # 其实在 Linux 底下还有个有趣的指令,名称为 rename ,
    # 该指令则专职进行档案的更名呢!用途也是不少~可以参阅 man rename 喔!
    
    范例三:再建立两个档案,再全部移动到 /tmp/mvtest2 当中
    [root@linux tmp]# cp ~/.bashrc bashrc1
    [root@linux tmp]# cp ~/.bashrc bashrc2
    [root@linux tmp]# mv bashrc1 bashrc2 mvtest2
    # 注意到这边,如果有多个来源档案或目录,则最后一个目标文件一定是『目录!』
    # 意思是说,将所有的数据移动到该目录的意思!
    
    这是搬移 (move) 的意思!当你要移动档案或目录的时后,呵呵!这个指令就很重要啦! 同样的,你也可以使用 -u ( update )来测试新旧档案,看看是否需要搬移啰! 另外一个用途就是『变更档名!』,我们可以很轻易的使用 mv 来变更一个档案的档名呢!不过,在 Linux 才有的指令当中,有个 rename , 可以用来更改大量档案的档名,您可以利用 man rename 来查阅一下,也是挺有趣的指令喔!

    小标题的图示取得路径的文件名与目录名称
    我们前面介绍的完整文件名 (包含目录名称与文件名) 当中提到,完整档名最长可以到达 4096 个字符。 那么您怎么知道那个是档名?那个是目录名?嘿嘿!就是利用斜线 (/) 来分辨啊! 其实,取得文件名或者是目录名称,一般的用途应该是在写程序的时候,用来判断之用的啦~ 所以,这部分的指令可以用在第三篇内的 shell scripts 里头喔! 底下我们简单的以几个范例来谈一谈 basename 与 dirname 的用途!
    [root@linux ~]# basename /etc/sysconfig/network
    network  <== 很简单!就取得最后的档名~
    [root@linux ~]# dirname /etc/sysconfig/network
    /etc/sysconfig  <== 取得的变成目录名了!
    
    很简单的应用吧!

    大标题的图示档案内容查阅:
    刚刚我们提到的都只是在于显示档案的属性与权限,或者是移动与复制一个档案或目录而已, 那么如果我们要查阅一个档案的内容时,该如何是好呢?!这里有相当多有趣的指令可以来分享一下: 最常使用的显示档案内容的指令可以说是 cat 与 more 及 less 了!此外,如果我们要查看一个很大型的档案 ( 好几百MB时 ),但是我们只需要后端的几行字而已,那么该如何是好?呵呵!用 tail 呀,此外, tac 这个指令也可以达到!好了,说说各个指令的用途吧!
    • cat  由第一行开始显示档案内容
    • tac  从最后一行开始显示,可以看出 tac 是 cat 的倒着写!
    • nl   显示的时候,顺道输出行号!
    • more 一页一页的显示档案内容
    • less 与 more 类似,但是比 more 更好的是,他可以往前翻页!
    • head 只看头几行
    • tail 只看尾巴几行
    • od   以二进制的方式读取档案内容!

    小标题的图示直接检视档案内容
    直接查阅一个档案的内容可以使用 cat/tac/nl 这几个指令啊!


  • cat (concatenate)
  • [root@linux ~]# cat [-AEnTv]
    参数:
    -A  :相当于 -vET 的整合参数,可列出一些特殊字符~
    -E  :将结尾的断行字符 $ 显示出来;
    -n  :打印出行号;
    -T  :将 [tab] 按键以 ^I 显示出来;
    -v  :列出一些看不出来的特殊字符
    范例:
    范例一:检阅 /etc/issue 这个档案的内容
    [root@linux ~]# cat /etc/issue
    Fedora Core release 4 (Stentz)
    Kernel \r on an \m
    
    范例二:承上题,顺便打印出行号时!
    [root@linux ~]# cat -n /etc/issue
         1  Fedora Core release 4 (Stentz)
         2  Kernel \r on an \m
         3
    # 看到了吧!可以印出行号呢!这对于大档案要找某个特定的行时,有点用处!
    
    范例三:将 /etc/xinetd.conf 的内容完整的显示出来(包含特殊字符)
    [root@linux ~]# cat -A /etc/xinetd.conf
    #$
    # Simple configuration file for xinetd$
    #$
    # Some defaults, and include /etc/xinetd.d/$
    $
    defaults$
    {$
    ^Iinstances               = 60$
            log_type                = SYSLOG authpriv$
            log_on_success^I^I= HOST PID$
            log_on_failure^I^I= HOST$
    ^Icps^I^I^I= 25 30$
    }$
    $
    includedir /etc/xinetd.d$
    # 在一般的环境中,打印出来的结果在有 [tab] 与空格键,其实看不出来,
    # 那么使用 cat -A 时,会将 [tab] 按键以 ^I 显示,而断行字符也会显示出来~
    # 最特殊的当然就是断行字符了!这个段行字符在 Linux 与 Windows 是不一样的。
    # 在 Linux 是以 $ 为断行字符,而在 Windows 则是以 ^M$ 为断行字符。
    # 这部分我们会在 vi 软件的介绍时,再次的说明到喔!
    
    嘿嘿! Linux 里面有『猫』?!喔!不是的, cat 是 Concatenate (连续)的简写, 主要的功能是将一个档案的内容连续的印出在屏幕上面!例如上面的例子中,我们将 /etc/issue 印出来!如果加上 -n 的话,则每一行前面还会加上行号呦!鸟哥个人是比较少用 cat 啦!毕竟当你的档案内容的行数超过 40 行以上,嘿嘿!根本来不及看!所以,配合等一下要介绍的 more 或者是 less 来执行比较好!此外,如果是一般的 DOS 档案时,就需要特别留意一些奇奇怪怪的符号了, 例如断行与 [tab] 等,要显示出来,就得加入 -A 之类的参数了!


  • tac (反向列示)
  • [root@linux ~]# tac /etc/issue
    
    Kernel \r on an \m
    Fedora Core release 4 (Stentz)
    # 嘿嘿!与刚刚上面的范例一比较,是由最后一行先显示喔!
    
    tac 这个好玩了!怎么说呢?详细的看一下, cat 与 tac ,有没有发现呀!对啦! tac 刚好是将 cat 反写过来,所以他的功能就跟 cat 相反啦, cat 是由『第一行到最后一行连续显示在屏幕上』,而 tac 则是『 由最后一行到第一行反向在屏幕上显示出来 』,很好玩吧!


  • nl (添加行号打印)
  • [root@linux ~]# nl [-bnw] 档案
    参数:
    -b  :指定行号指定的方式,主要有两种:
          -b a :表示不论是否为空行,也同样列出行号;
          -b t :如果有空行,空的那一行不要列出行号;
    -n  :列出行号表示的方法,主要有三种:
          -n ln :行号在屏幕的最左方显示;
          -n rn :行号在自己字段的最右方显示,且不加 0 ;
          -n rz :行号在自己字段的最右方显示,且加 0 ;
    -w  :行号字段的占用的位数。
    范例:
    范例一:列出 /etc/issue 的内容
    [root@linux ~]# nl /etc/issue
         1  Fedora Core release 4 (Stentz)
         2  Kernel \r on an \m
    
    # 注意看,这个档案其实有三行,第三行为空白(没有任何字符),
    # 因为他是空白行,所以 nl 不会加上行号喔!如果确定要加上行号,可以这样做:
    
    [root@linux ~]# nl -b a /etc/issue
         1  Fedora Core release 4 (Stentz)
         2  Kernel \r on an \m
         3
    # 呵呵!行号加上来啰~那么如果要让行号前面自动补上 0 呢?可这样
    
    [root@linux ~]# nl -b a -n rz /etc/issue
    000001  Fedora Core release 4 (Stentz)
    000002  Kernel \r on an \m
    000003
    # 嘿嘿!自动在自己字段的地方补上 0 了~预设字段是六位数,如果想要改成 3 位数?
    
    [root@linux ~]# nl -b a -n rz -w 3 /etc/issue
    001     Fedora Core release 4 (Stentz)
    002     Kernel \r on an \m
    003
    # 变成仅有 3 位数啰~
    
    nl 可以将输出的档案内容自动的加上行号!其结果与 cat -n 有点不太一样, nl 可以将行号做比较多的显示设计,包括位数与是否自动补齐 0 等等的功能呢~

    小标题的图示可翻页检视
    前面提到的 nl 与 cat, tac 等等,都是一次性的将数据显示到屏幕上面,那有没有可以进行一页一页翻动的指令啊? 让我们可以一页一页的观察,才不会前面的看不到啊~呵呵!有的!那就是 more 与 less 啰~


  • more (一页一页翻动)
  • [root@linux ~]# more /etc/man.config
    #
    # Generated automatically from man.conf.in by the
    # configure script.
    #
    # man.conf from man-1.5p
    #
    .......中间省略.......
    --More--(28%) <== 重点在这一行喔!
    
    仔细的给他看到上面的范例,如果 more 后面接的档案长度大于屏幕输出的行数时, 就会出现类似上面的图示。重点在最后一行,最后一行会显示出目前显示的百分比, 而且还可以在最后一行输入一些有用的指令喔!在 more 这个程序的运作过程中,你有几个按键可以按的:
    • 空格键 (space):代表向下翻一页;
    • Enter         :代表向下翻『一行』;
    • /字符串         :代表在这个显示的内容当中,向下搜寻『字符串』;
    • :f            :立刻显示出文件名以及目前显示的行数;
    • q             :代表立刻离开 more ,不再显示该档案内容。
    要离开 more 这个指令的显示工作,可以按下 q 就能够离开了。而要向下翻页,就使用空格键即可。 比较有用的是搜寻字符串的功能,举例来说,我们使用『 more /etc/man.config 』来观察该档案, 若想要在该档案内搜寻 MANPATH 这个字符串时,可以这样做:
    [root@linux ~]# more /etc/man.config
    #
    # Generated automatically from man.conf.in by the
    # configure script.
    #
    # man.conf from man-1.5p
    #
    .......中间省略.......
    /MANPATH   <== 输入了 / 之后,光标就会自动跑到最底下一行等待输入!
    
    如同上面的说明,输入了 / 之后,光标就会跑到最底下一行,并且等待您的输入, 您输入了字符串之后,嘿嘿! more 就会开始向下搜寻该字符串啰~而重复搜寻同一个字符串, 可以直接按下 n 即可啊!最后,不想要看了,就按下 q 即可离开 more 啦!


  • less (一页一页翻动)
  • [root@linux ~]# less /etc/man.config
    #
    # Generated automatically from man.conf.in by the
    # configure script.
    #
    # man.conf from man-1.5p
    ......中间省略........
    :   <== 这里可以等待您输入指令!
    
    less 的用法比起 more 又更加的有弹性,怎么说呢?在 more 的时候,我们并没有办法向前面翻, 只能往后面看,但若使用了 less 时,呵呵!就可以使用 [pageup] [pagedown] 等按键的功能来往前往后翻看文件,您瞧,是不是更容易使用来观看一个档案的内容了呢!?

    除此之外,在 less 里头可以拥有更多的『搜寻』功能喔!不止可以向下搜寻,也可以向上搜寻~ 实在是很不错用~基本上,可以输入的指令有:
    • 空格键    :向下翻动一页;
    • [pagedown]:向下翻动一页;
    • [pageup]  :向上翻动一页;
    • /字符串     :向下搜寻『字符串』的功能;
    • ?字符串     :向上搜寻『字符串』的功能;
    • n         :重复前一个搜寻 (与 / 或 ? 有关!)
    • N         :反向的重复前一个搜寻 (与 / 或 ? 有关!)
    • q         :离开 less 这个程序;
    查阅档案内容还可以进行搜寻的动作~瞧~ less 是否很不错用啊! 其实 less 还有很多的功能喔!详细的使用方式请使用 man less 查询一下啊! ^_^

    小标题的图示资料撷取
    我们可以将输出的资料作一个最简单的撷取,那就是取出前面 (head) 与取出后面 (tail) 文字的功能。 不过,要注意的是, head 与 tail 都是以『行』为单位来进行数据撷取的喔!


  • head (取出前面几行)
  • [root@linux ~]# head [-n number] 档案 
    参数:
    -n  :后面接数字,代表显示几行的意思
    范例:
    [root@linux ~]# head /etc/man.config
    # 默认的情况中,显示前面十行!若要显示前 20 行,就得要这样:
    
    [root@linux ~]# head -n 20 /etc/man.config
    
    head 的英文意思就是『头』啦,那么这个东西的用法自然就是显示出一个档案的前几行啰! 没错!就是这样!若没有加上 -n 这个参数时,默认只显示十行,若只要一行呢?那就加入『 head -n 1 filename 』即可!


  • tail (取出后面几行)
  • [root@linux ~]# tail [-n number] 档案 
    参数:
    -n  :后面接数字,代表显示几行的意思
    范例:
    [root@linux ~]# tail /etc/man.config
    # 默认的情况中,显示最后的十行!若要显示最后的 20 行,就得要这样:
    
    [root@linux ~]# tail -n 20 /etc/man.config
    
    那么有 head 自然就有 tail ( 尾巴 ) 啰!没错!这个 tail 的用法跟 head 的用法差不多类似,只是显示的是后面几行就是了!默认也是显示十行,若要显示非十行,就加 -n number 的参数!
    例题一:假如我想要显示 ~/.bashrc 的第 11 到第 20 行呢?
    答:
      这个应该不算难,想一想,在第 11 到第 20 行,那么我取前 20 行,再取后十行,所以结果就是:『 head –n 20 ~/.bashrc | tail –n 10 』,这样就可以得到第 11 到第 20 行之间的内容了! 但是里面涉及到管线命令,需要在第三篇的时候才讲的到!


    小标题的图示非纯文本档: od
    我们上面提到的,都是在查阅纯文本档 (ASCII 格式的档案) 的内容。 那么万一我们想要查阅非文本文件,举例来说,例如 /usr/bin/passwd 这个执行档的内容时, 又该如何去读出信息呢?事实上,由于执行档通常是 binary file ,使用上头提到的指令来读取他的内容时, 确实会产生类似乱码的数据啊!那怎么办?没关系,我们可以利用 od 这个指令来读取喔!
    [root@linux ~]# 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 ;
    范例:
    [root@linux ~]# 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
    .....中间省略.......
    
    利用这个指令,可以将 data file 或者是 binary file 的内容数据给他读出来喔! 虽然读出的来数值预设是使用非文本文件,亦即是 16 进位的数值来显示的, 不过,我们还是可以透过 -t c 的参数来将数据内的字符以 ASCII 类型的字符来显示, 虽然对于一般用户来说,这个指令的用处可能不大,但是对于工程师来说, 这个指令可以将 binary file 的内容作一个大致的输出,他们可以看得出东西的啦~ ^_^


    小标题的图示修改档案时间与建置新档: touch
    我们在 ls 这个指令的介绍时,有稍微提到每个档案在 linux 底下都会记录三个主要的变动时间, 咦!那么三个时间是哪三个呢?
    • modification time (mtime):当该档案的『内容数据』变更时,就会更新这个时间! 内容数据指的是档案的内容,而不是档案的属性喔!
    • status time (ctime):当该档案的『状态 (status)』改变时,就会更新这个时间,举例来说, 像是权限与属性被更改了,都会更新这个时间啊~
    • access time (atime):当『该档案的内容被取用』时,就会更新这个读取时间 (access)。 举例来说,我们使用 cat 去读取 ~/.bashrc ,就会更新 atime 了。
    这是个挺有趣的现象,举例来说,我们来看一看您自己的 /etc/man.config 这个档案的时间吧!
    [root@linux ~]# ls -l /etc/man.config
    -rw-r--r--  1 root root 4506 Apr  8 19:11 /etc/man.config
    [root@linux ~]# ls -l --time=atime /etc/man.config
    -rw-r--r--  1 root root 4506 Jul 19 17:53 /etc/man.config
    [root@linux ~]# ls -l --time=ctime /etc/man.config
    -rw-r--r--  1 root root 4506 Jun 25 08:28 /etc/man.config
    
    看到了吗?在默认的情况下, ls 显示出来的是该档案的 mtime ,也就是这个档案的内容上次被更动的时间。 至于我的系统是在 6/25 的时候安装的,因此,这个档案被产生但是状态被更动的时间就回溯到那个时间点了! 而还记得刚刚我们使用的范例当中,有使用到这个档案啊,所以啊,他的 atime 就会变成刚刚使用的时间了!

    档案的时间是很重要的,因为,如果档案的时间误判的话,可能会造成某些程序无法顺利的运作~ OK!那么万一我发现了一个档案来自未来(嘿嘿!不要怀疑!很多时候会有这个问题的!这个我们在安装的时候, 提到的 GMT 时间就是那个意思啦~),那该如何让该档案的时间变成『现在』的时刻呢? 很简单啊!就用『touch』这个指令即可!
    [root@linux ~]# touch [-acdmt] 档案
    参数:
    -a  :仅修订 access time;
    -c  :仅修改时间,而不建立档案;
    -d  :后面可以接日期,也可以使用 --date="日期或时间"
    -m  :仅修改 mtime ;
    -t  :后面可以接时间,格式为[YYMMDDhhmm]
    范例:
    
    范例一:新建一个空的档案
    [root@linux ~]# cd /tmp
    [root@linux tmp]# touch testtouch
    [root@linux tmp]# ls -l testtouch
    -rw-r--r--  1 root root    0 Jul 19 20:49 testtouch
    # 注意到,这个档案的大小是 0 呢!在预设的状态下,如果 touch 后面有接档案,
    # 则该档案的三个时间 (atime/ctime/mtime) 都会更新为目前的时间。若该档案不存在,
    # 则会主动的建立一个新的空的档案喔!例如上面这个例子!
    
    范例二:将 ~/.bashrc 复制成为 bashrc,假设复制完全的属性,检查其日期
    [root@linux tmp]# cp ~/.bashrc bashrc
    [root@linux tmp]# ll bashrc; ll --time=atime bashrc; ll --time=ctime bashrc
    -rwxr-xr-x  1 root root 395 Jul  4 11:45 bashrc  <==这是 mtime
    -rwxr-xr-x  1 root root 395 Jul 19 20:44 bashrc  <==这是 atime
    -rwxr-xr-x  1 root root 395 Jul 19 20:53 bashrc  <==这是 ctime
    # 在这个案例当中,我们使用了 ; 这个指令分隔符,他的用法我们会在 Bash shell 中提到。
    # 此外, ll 是 ls -l 的命令别名,这个我们也会在 bash shell 当中再次提及,
    # 您目前可以简单的想成, ll 就是 ls -l 的简写即可!至于 ; 则是同时下达两个指令,
    # 且让两个指令『依序』执行的意思。上面的结果当中我们可以看到,该档案变更的日期
    # Jul 4 11:45,但是 atime 与 ctime 不一样啰~
    
    范例三:修改案例二的 bashrc 档案,将日期调整为两天前
    [root@linux tmp]# touch -d "2 days ago" bashrc
    [root@linux tmp]# ll bashrc; ll --time=atime bashrc; ll --time=ctime bashrc
    -rwxr-xr-x  1 root root 395 Jul 17 21:02 bashrc
    -rwxr-xr-x  1 root root 395 Jul 17 21:02 bashrc
    -rwxr-xr-x  1 root root 395 Jul 19 21:02 bashrc
    # 跟上个范例比较看看,本来是 19 日的变成了 17 日了 (atime/mtime)~
    # 不过, ctime 并没有跟着改变喔!
    
    范例四:将上个范例的 bashrc 日期改为 2005/07/15 2:02
    [root@linux tmp]# touch -t 0507150202 bashrc
    [root@linux tmp]# ll bashrc; ll --time=atime bashrc; ll --time=ctime bashrc
    -rwxr-xr-x  1 root root 395 Jul 15 02:02 bashrc
    -rwxr-xr-x  1 root root 395 Jul 15 02:02 bashrc
    -rwxr-xr-x  1 root root 395 Jul 19 21:05 bashrc
    # 注意看看,日期在 atime 与 mtime 都改变了,但是 ctime 则是记录目前的时间!
    
    透过 touch 这个指令,我们可以轻易的修订档案的日期与时间。并且,也可以建立一个空的档案喔! 不过,要注意的是,即使我们复制一个档案时,复制所有的属性,但也没有办法复制 ctime 这个属性的。 ctime 可以记录这个档案最近的状态 (status) 被改变的时间。无论如何,还是要告知大家, 我们平时看的文件属性中,比较重要的还是属于那个 mtime 啊!我们关心的常常是这个档案的『内容』 是什么时候被更动的说~瞭乎?

    无论如何, touch 这个指令最常被使用的情况是:
    • 建立一个空的档案;
    • 将某个档案日期修订为目前 (mtime 与 atime)

    大标题的图示档案与目录的默认权限与隐藏权限
    由前一章的 Linux 文件属性 的内容我们可以知道一个档案有若干个属性,包括 ( r, w, x ) 等基本属性,及是否为目录 (d) 与档案 (-) 或者是连结档 (l) 等等的属性!那么要修改属性的方法在前面也约略提过了,这里再加强补充一下! 此外,由于 Linux 还可以设定其他的系统安全属性,使用 chattr 来设定,而以 lsattr 来查看,最重要的属性就是可以设定其不可修改的特性!让连档案的拥有者都不能进行修改! 这个属性可是相当重要的,尤其是在安全机制上面 ( security )!

    首先,先来复习一下上一章谈到的权限概念,将底下的例题看一看先~

    例题二:你的系统有个一般身份用户 dmtsai,他的群组为 users,他的家目录在 /home/dmtsai, 你想将你的 ~/.bashrc 复制给他(假设你是 root),可以怎么作?
    答:
      cp ~/.bashrc ~dmtsai/bashrc
      chown dmtsai:users ~dmtsai/bashrc

    在上面这个范例当中,我为了怕覆盖掉 dmtsai 自己的 ~dmtsai/.bashrc ,所以将档名更名了~ 而复制给他后,还要修正这个档案的拥有者与群组才行喔!

    例题三:我想在 /tmp 底下建立一个目录,这个目录名称为 chap2_2_ex1 ,并且,这个目录拥有者为 dmtsai, 群组为 users ,此外,任何人都可以进入该目录浏览档案,不过除了 dmtsai 之外,其他人都不能修改该目录下的档案。
    答:
      因为除了 dmtsai 之外,其他人不能修改该目录下的档案,此外, dmtsai 可以修改, 所以整个目录的权限应该是 drwxr-xr-x 才对!因此
      mkdir /tmp/chap2_2_ex1
      chown -R dmtsai:users /tmp/chap2_2_ex1
      chmod -R 755 /tmp/chap2_2_ex1

    在上面这个例题当中,如果您知道 755 那个分数是怎么计算出来的,那么您应该对于权限有一定程度的概念了。 如果您不知道 755 怎么来的?那么.....赶快回去前一章看看 chmod 那个指令的介绍部分啊!这部分很重要喔!您得要先清楚的了解到才行~否则就进行不下去啰~ 假设您对于权限都认识的差不多了,那么底下我们就要来谈一谈, 『新增一个档案或目录时,默认的权限是什么?』这个议题!


    小标题的图示档案预设权限:umask
    OK!那么现在我们知道如何建立或者是改变一个目录或档案的属性了,不过, 您知道当你建立一个新的档案或目录时,他的默认属性会是什么吗?呵呵!那就与 umask 这个玩意儿有关了!那么 umask 是在搞什么呢?基本上, umask 就是指定 『目前用户在建立档案或目录时候的属性默认值』, 那么如何得知或设定 umask 呢?他的指定条件以底下的方式来指定:
    [root@linux ~]# umask
    0022
    [root@linux ~]# umask -S
    u=rwx,g=rx,o=rx
    
    查阅的方式有两种,一种可以直接输入 umask ,就可以看到数字型态的权限设定分数, 一种则是加入 -S (Symbolic) 这个参数,就会以符号类型的方式来显示出权限了! 奇怪的是,怎么 umask 会有四组数字啊?不是只有三组吗?是没错啦~ 第一组是特殊权限用的,我们先不要理他,所以先看后面三组即可。

    在默认权限的属性上,目录与档案是不一样的。由于档案我们不希望他具有可执行的权力, 预设情况中,档案是没有可执行 (x) 权限的。因此:
    • 若使用者建立为『档案』则预设『没有可执行 ( x ) 项目』,亦即只有 rw 这两个项目,也就是最大为 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@linux ~]# umask
    0022
    [root@linux ~]# touch test1
    [root@linux ~]# mkdir test2
    [root@linux ~]# ll 
    -rw-r--r--  1 root root    0 Jul 20 00:36 test1
    drwxr-xr-x  2 root root 4096 Jul 20 00:36 test2
    
    呵呵!瞧见了吧?!确定属性是没有错的。好了,假如我们想要让与使用者同群组的人也可以存取档案呢? 也就是说,假如 dmtsai 是 users 这个群组的人,而 dmtsai 作的档案希望让 users 同群组的人也可以存取, 这也是常常被用在团队开发计划时,常常会考虑到的权限问题。在这样的情况下, 我们的 umask 自然不能取消 group 的 w 权限,也就是说,我们希望制作出来的档案应该是 -rw-rw-r-- 的模样,所以啰, umask 应该是要 002 才好 (仅拿掉 others 的 w 权限)。那么如何设定 umask 呢? 简单的很,直接在 umask 后面输入 002 就好了!
    [root@linux ~]# umask 002
    [root@linux ~]# touch test3
    [root@linux ~]# mkdir test4
    [root@linux ~]# ll 
    -rw-rw-r--  1 root root    0 Jul 20 00:41 test3
    drwxrwxr-x  2 root root 4096 Jul 20 00:41 test4
    
    所以说,这个 umask 对于档案与目录的默认权限是很有关系的!这个概念可以用在任何服务器上面, 尤其是未来在您架设文件服务器 (file server) ,举例来说, SAMBA Server 或者是 FTP server 时, 都是很重要的观念!这牵涉到您的使用者是否能够将档案进一步利用的问题喔!不要等闲视之!

    例题四:假设您的 umask 为 003 ,请问该 umask 情况下,建立的档案与目录权限为?
    答:
      umask 为 003 ,所以拿掉的属性为 --------wx,因此:
      档案: (-rw-rw-rw-) - (--------wx) = -rw-rw-r--
      目录: (drwxrwxrwx) - (--------wx) = drwxrwxr--

    Tips:
    关于 umask 与权限的计算方式中,教科书喜欢使用二进制的方式来进行 AND 与 NOT 的计算, 不过,鸟哥还是比较喜欢使用符号方式来计算~联想上面比较容易一点~ 但是,有的书籍或者是 BBS 上面的朋友,有的人喜欢使用档案默认属性 666 与目录默认属性 777 来与 umask 进行相减的计算~这是不好的喔!以上面例题四的案例来看, 如果使用默认属性相加减,则档案变成:666-003=663,亦即是 -rw-rw--wx ,这可是完全不对的喔! 想想看,原本档案就已经去除 x 的默认属性了,怎么可能突然间冒出来了? 所以,这个地方得要特别小心喔!
    鸟哥的图示
    在预设的情况中, root 的 umask 会拿掉比较多的属性,root 的 umask 默认是 022 , 这是基于安全的考虑啦~至于一般身份使用者,通常他们的 umask 为 002 ,亦即保留同群组的写入权力! 其实,关于预设 umask 的设定可以参考 /etc/bashrc 这个档案的内容,不过,不建议修改该档案, 您可以参考 bash shell 提到的环境参数配置文件 (~/.bashrc) 的说明~这部分我们在第三章的时候会提到!


    小标题的图示档案隐藏属性:
    什么?档案还有隐藏属性?光是那九个权限就快要疯掉了,竟然还有隐藏属性,真是要命~ 但是没办法,就是有档案的隐藏属性存在啊!不过,这些隐藏的属性确实对于系统有很大的帮助的~ 尤其是在系统安全 (Security) 上面,重要的紧呢!底下我们就来谈一谈如何设定与检查这些隐藏的属性吧!


  • chattr (配置文件案隐藏属性)
  • [root@linux ~]# chattr [+-=][ASacdistu] 档案或目录名称
    参数:
    +   :增加某一个特殊参数,其他原本存在参数则不动。
    -   :移除某一个特殊参数,其他原本存在参数则不动。
    =   :设定一定,且仅有后面接的参数
    
    A  :当设定了 A 这个属性时,这个档案(或目录)的访问时间 atime (access) 
         将不可被修改,可避免例如手提式计算机容易有磁盘 I/O 错误的情况发生!
    S  :这个功能有点类似 sync 的功能!就是会将数据同步写入磁盘当中!
         可以有效的避免数据流失!
    a  :当设定 a 之后,这个档案将只能增加数据,而不能删除,只有 root 
         才能设定这个属性。 
    c  :这个属性设定之后,将会自动的将此档案『压缩』,在读取的时候将会自动解压缩,
         但是在储存的时候,将会先进行压缩后再储存(看来对于大档案似乎蛮有用的!)
    d  :当dump(备份)程序被执行的时候,设定 d 属性将可使该档案(或目录)不具有dump功能
    i  :这个 i 可就很厉害了!他可以让一个档案『不能被删除、改名、设定连结也无法写入
         或新增资料!』对于系统安全性有相当大的帮助!
    j  :当使用 ext3 这个文件系统格式时,设定 j 属性将会使档案在写入时先记录在 
         journal 中!但是当 filesystem 设定参数为 data=journalled 时,由于已经设定了
         日志了,所以这个属性无效!
    s  :当档案设定了 s 参数时,他将会被完全的移除出这个硬盘空间。
    u  :与 s 相反的,当使用 u 来配置文件案时,则数据内容其实还存在磁盘中,
         可以使用来 undeletion.
    注意:这个属性设定上面,比较常见的是 a 与 i 的设定值,而且很多设定值必须要身为
    root 才能够设定的喔!
    范例:
    [root@linux ~]# cd /tmp
    [root@linux tmp]# touch attrtest
    [root@linux tmp]# chattr +i attrtest
    [root@linux tmp]# rm attrtest
    rm: remove write-protected regular empty file `attrtest'? y
    rm: cannot remove `attrtest': Operation not permitted
    # 看到了吗?呼呼!连 root 也没有办法将这个档案删除呢!赶紧解除设定!
    [root@linux tmp]# chattr -i attrtest
    
    这这个指令是重要的,尤其是在系统的安全性上面!由于这些属性是隐藏的性质,所以需要以 lsattr 才能看到该属性呦!其中,个人认为最重要的当属 +i 这个属性了,因为他可以让一个档案无法被更动,对于需要强烈的系统安全的人来说, 真是相当的重要的!里头还有相当多的属性是需要 root 才能设定的呢!此外,如果是 log file 这种的登录档,就更需要 +a 这个可以增加,但是不能修改旧有的数据与删除的参数了! 怎样?很棒吧!未来提到登录档的认知时,我们再来聊一聊如何设定他吧!


  • lsattr (显示档案隐藏属性)
  • [root@linux ~]# lsattr [-aR] 档案或目录
    参数:
    -a :将隐藏文件的属性也秀出来;
    -R :连同子目录的数据也一并列出来! 
    范例:
    [root@linux tmp]# chattr +aij attrtest
    [root@linux tmp]# lsattr
    ----ia---j--- ./attrtest
    
    使用 chattr 设定后,可以利用 lsattr 来查阅隐藏的属性。不过, 这两个指令在使用上必须要特别小心,否则会造成很大的困扰。例如:某天你心情好,突然将 /etc/shadow 这个重要的密码记录档案给他设定成为具有 i 的属性,那么过了若干天之后, 你突然要新增使用者,却一直无法新增!别怀疑,赶快去将 i 的属性拿掉吧!

    小标题的图示档案特殊权限: SUID/SGID/Sticky Bit
    我们前面一直提到关于档案的重要权限,那就是 rwx 这三个读、写、执行的权限。 但是,眼尖的朋友们一定注意到了一件事,那就是,怎么我们的 /tmp 权限怪怪的? 还有,那个 /usr/bin/passwd 也怪怪的?怎么回事啊?看看先:
    [root@linux ~]# ls -ld /tmp ; ls -l /usr/bin/passwd
    drwxrwxrwt  5 root root 4096 Jul 20 10:00 /tmp
    -r-s--x--x  1 root root 18840 Mar  7 18:06 /usr/bin/passwd
    
    不是只有 rwx 吗?还有其他的特殊权限啊?啊.....头又开始昏了~ @_@ 呵呵,不要担心啦,我们这里先不谈这两个权限,只是先介绍一下而已。 因为要了解这几个特殊的权限,必须要先具有账号的 ID 概念,以及程序的程序 (process) 概念后, 才能够进一步的了解这个特殊权限所代表的意义。

  • Set UID
  • 会制作出 s 与 t 的权限,是为了让一般用户在执行某些程序的时候, 能够暂时的具有该程序拥有者的权限。 举例来说好了,我们知道账号与密码的存放档案其实是 /etc/passwd 与 /etc/shadow 。 而 /etc/shadow 这个档案的权限是什么?是『-r--------』。且他的拥有者是 root 喔!在这个权限中,仅有 root 可以『强制』储存,其他人是连看都没有办法看的吶!

    但是偏偏鸟哥使用 dmtsai 这个一般身份用户去更新自己的密码时,使用的就是 /usr/bin/passwd 这个程序, 却是可以更新自己的密码的,也就是说, dmtsai 这个一般身份使用者可以存取 /etc/shadow 这个密码文件! 但!怎么可能?明明 /etc/shadow 就是没有 dmtsai 可以存取的权限啊!呵呵~这就是 s 这个权限的帮助啦! 当 s 这个权限在 user 的 x 时,也就是类似上表的 -r-s--x--x ,称为 Set UID ,简称为 SUID , 这个 UID 代表的是 User 的 ID ,而 User 代表的则是这个程序 (/usr/bin/passwd) 的拥有者 (root 啊!)。 那么由上面的定义中,我们知道了,当 dmtsai 这个使用者执行 /usr/bin/passwd 时,他就会『暂时』的得到档案拥有人 root 的权限

    SUID 仅可用在『二进制制档案(binary file)』上, SUID 因为是程序在执行的过程中拥有档案拥有者的权限,因此,他仅可用于 binary file , 不能够用在批处理文件 (shell script) 上面的!这是因为 shell script 只是将很多的 binary 执行档叫进来执行而已!所以 SUID 的权限部分,还是得要看 shell script 呼叫进来的程序的设定, 而不是 shell script 本身。当然,SUID 对于目录也是无效的~这点要特别留意。

  • Set GID
  • 进一步来说,如果 s 的权限是在 group 时,那么就是 Set GID ,简称为 SGID。 SGID 可以用在两个部分喔!
    • 档案:如果 SGID 是设定在 binary file 上面,则不论使用者是谁,在执行该程序的时候, 他的有效群组 (effective group) 将会变成该程序的群组所有人 (group id)。

    • 目录:如果 SGID 是设定在 A 目录上面,则在该 A 目录内所建立的档案或目录的 group ,将会是 此 A 目录的 group !
    一般来说, SGID 应该是比较多用在特定的多人团队的项目开发上, 在系统当中应该会比较少这个设定才对~

  • Sticky Bit
  • 这个 Sticky Bit 目前只针对目录有效,对于档案已经没有效果了。 SBit 对于目录的作用是:『在具有 SBit 的目录下,用户若在该目录下具有 w 及 x 的权限, 则当用户在该目录下建立档案或目录时,只有档案拥有者与 root 才有权力删除』。换句话说:当甲这个用户于 A 目录下是拥有 group 或者是 other 的项目,并且拥有 w 的权限, 这表示『甲用户对该目录内任何人建立的目录或档案均可进行 "删除/更名/搬移" 等动作。』 不过,如果将 A 目录加上了 Sticky bit 的权限项目时, 则甲只能够针对自己建立的档案或目录进行删除/更名/移动等动作。

    举例来说,我们的 /tmp 本身的权限是『drwxrwxrwt』, 在这样的权限内容下,任何人都可以在 /tmp 内新增、修改档案,但仅有该档案/目录建立者与 root 能够删除自己的目录或档案。这个特性也是挺重要的啊!你可以这样做个简单的测试:
      1. 以 root 登入系统,并且进入 /tmp 当中;
      2. touch test,并且更改 test 权限成为 777 ;
      3. 以一般使用者登入,并进入 /tmp;
      4. 尝试删除 test 这个档案!
    更多关于 SUID/SGID/Sticky Bit 的介绍,我们会在 程序与资源管理 中再次提及的,目前,您先有个简单的基础概念就好了!当然,也可以参考鸟园讨论区的这一篇讨论: http://phorum.vbird.org/viewtopic.php?t=20256

  • SUID/SGID/SBIT 权限设定
  • 前面介绍过 SUID 与 SGID 的功能,那么如何开启档案使成为具有 SUID 与 SGID 的权限呢?! 这就需要刚刚的数字更改权限的方法了!现在你应该已经知道数字型态个更改权限方式为『三个数字』的组合, 那么如果在这三个数字之前再加上一个数字的话,那最前的面数字就代表这几个属性了! ( 注:通常我们使用 chmod xyz filename 的方式来设定 filename 的属性时,则是假设没有 SUID, SGID 及 Sticky bit 啦! )
    • 4 为 SUID
    • 2 为 SGID
    • 1 为 Sticky bit
    假设要将一个文件属性改为『-rwsr-xr-x』时,由于 s 在用户权力中,所以是 SUID ,因此, 在原先的 755 之前还要加上 4 ,也就是:『 chmod 4755 filename 』来设定!此外,还有大 S 与大 T 的产生喔!参考底下的范例啦!(注意:底下的范例只是练习而已, 所以鸟哥使用同一个档案来设定,您必须了解 SUID 不是用在目录上,而 SBIT 不是用在档案上的喔!)
    [root@linux ~]# cd /tmp
    [root@linux tmp]# touch test
    [root@linux tmp]# chmod 4755 test; ls -l test
    -rwsr-xr-x  1 root root 0 Jul 20 11:27 test
    [root@linux tmp]# chmod 6755 test; ls -l test
    -rwsr-sr-x  1 root root 0 Jul 20 11:27 test
    [root@linux tmp]# chmod 1755 test; ls -l test
    -rwxr-xr-t  1 root root 0 Jul 20 11:27 test
    [root@linux tmp]# chmod 7666 test; ls -l test
    -rwSrwSrwT  1 root root 0 Jul 20 11:27 test
    # 这个例子就要特别小心啦!怎么会出现大写的 S 与 T 呢?不都是小写的吗?
    # 因为 s 与 t 都是取代 x 这个参数的,但是你有没有发现阿,我们是下达 
    # 7666 喔!也就是说, user, group 以及 others 都没有 x 这个可执行的标志 
    # ( 因为 666 嘛! ),所以,这个 S, T 代表的就是『空的』啦!怎么说? 
    # SUID 是表示『该档案在执行的时候,具有档案拥有者的权限』,但是档案
    # 拥有者都无法执行了,哪里来的权限给其他人使用?当然就是空的啦! ^_^
    

    小标题的图示文件类型:file
    如果你想要知道某个档案的基本数据,例如是属于 ASCII 或者是 data 档案,或者是 binary , 且其中有没有使用到动态函式库 (share library) 等等的信息,就可以利用 file 这个指令来检阅喔! 举例来说:
    [root@linux ~]# file ~/.bashrc
    /root/.bashrc: ASCII text  <== 告诉我们是 ASCII 的纯文本档啊!
    [root@linux ~]# file /usr/bin/passwd
    /usr/bin/passwd: setuid ELF 32-bit LSB executable, Intel 80386, version 1 
    (SYSV), for GNU/Linux 2.2.5, dynamically linked (uses shared libs), stripped
    # 数据可多了~包括这个日 Set UID 2的档案,使用 shared libs,
    # 适合于 Intel 的 386 以上机种的硬件,很清楚吧!
    [root@linux ~]# file /var/lib/slocate/slocate.db
    /var/lib/slocate/slocate.db: data  <== 这是 data 档案!
    
    透过这个指令,我们可以简单的先判断这个档案的格式为何喔!

    大标题的图示档案的搜寻:
    档案的搜寻可就厉害了!因为我们常常需要知道那个档案放在哪里,所以来谈一谈怎么搜寻吧!在 Linux 底下也有相当优异的搜寻系统呦!通常 find 不很常用的!因为速度慢之外,也很操硬盘!通常我们都是先使用 whereis 或者是 locate 来检查,如果真的找不到了,才以 find 来搜寻呦!为什么呢?因为 whereis 与 locate 是利用数据库来搜寻数据,所以相当的快速,而且并没有实际的搜寻硬盘,比较省时间啦!


  • which (寻找『执行档』)
  • [root@linux ~]# which [-a] command
    参数:
    -a :将所有可以找到的指令均列出,而不止第一个被找到的指令名称
    范例:
    [root@linux ~]# which passwd
    /usr/bin/passwd
    [root@linux ~]# which traceroute -a
    /usr/sbin/traceroute
    /bin/traceroute
    
    这个指令是根据『PATH』这个环境变量所规范的路径,去搜寻『执行档』的档名~ 所以,重点是找出『执行档』而已!且 which 后面接的是『完整档名』喔!若加上 -a 参数,则可以列出所有的可以找到的同名执行文件,而非仅显示第一个而已!


  • whereis (寻找特定档案)
  • [root@linux ~]# whereis [-bmsu] 档案或目录名
    参数:
    -b    :只找 binary 的档案
    -m    :只找在说明文件 manual 路径下的档案
    -s    :只找 source 来源档案
    -u    :没有说明档的档案!
    范例:
    [root@linux ~]# whereis passwd
    passwd: /usr/bin/passwd /etc/passwd /etc/passwd.OLD 
    /usr/share/man/man1/passwd.1.gz /usr/share/man/man5/passwd.5.gz
    # 任何与 passwd 有关的档名都会被列出来~
    
    [root@linux ~]# whereis -b passwd
    passwd: /usr/bin/passwd /etc/passwd /etc/passwd.OLD
    
    [root@linux ~]# 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 就可以啦!例如上面的范例针对 passwd 这支程序来说明!如果不加任何参数的话,那么就将所有的数据列出来啰!

    那么 whereis 到底是使用什么咚咚呢?为何搜寻的速度会比 find 快这么多?! 其实那也没有什么!这是因为 Linux 系统会将系统内的所有档案都记录在一个数据库档案里面, 而当使用 whereis 或者是底下要说的 locate 时,都会以此数据库档案的内容为准, 因此,有的时后你还会发现使用这两个执行档时,会找到已经被杀掉的档案! 而且也找不到最新的刚刚建立的档案呢! 这就是因为这两个指令是由数据库当中的结果去搜寻档案的所在啊!

    另外,基本上 Linux 每天会针对 Linux 主机上所有档案的所在进行搜寻数据库的更新, 更新的程序就是 updatedb ,你可以在 FC4 系统的 /etc/cron.daily/slocate.cron 这个档案找到相关的机制呦!当然,也可以直接使用 /usr/bin/updatedb 来更新数据库档案呢!

  • locate
  • [root@linux ~]# locate filename
    [root@linux ~]# locate passwd
    /lib/security/pam_passwdqc.so
    /lib/security/pam_unix_passwd.so
    /usr/lib/kde3/kded_kpasswdserver.so
    /usr/lib/kde3/kded_kpasswdserver.la
    .......中间省略.......
    
    这个 locate 的使用更简单,直接在后面输入『档案的部分名称』后,就能够得到结果。 举上面的例子来说,我输入 locate passwd ,那么在完整文件名 (包含路径名称) 当中,只要有 passwd 在其中, 就会被显示出来的!这也是个很方便好用的指令,如果您忘记某个档案的完整档名时~~

    但是,这个东西还是有使用上的限制呦!为什么呢?您会发现使用 locate 来寻找数据的时候特别的快, 这是因为 locate 寻找的数据是由『已建立的数据库 /var/lib/slocate/』 里面的数据所搜寻到的,所以不用直接在去硬盘当中存取数据,呵呵!当然是很快速啰! 那么有什么限制呢?就是因为他是经由数据库来搜寻的,而数据库的建立默认是在每天执行一次 (每个 distribution 都不同, FC4 是每天更新数据库一次!),所以当您新建立起来的档案, 却还在数据库更新之前搜寻该档案,那么 locate 会告诉您『找不到!』呵呵!因为必须要更新数据库呀!

    那么我到底要建立哪些数据库呢?是否全部都要建立?似乎不需要,这个时候, 你可以自己选择需要建立档案数据库的目录呢!你可以在 /etc/updatedb.conf 这个档案内设定。 建议您使用默认值就好了,不过,在 /etc/updatedb.conf 里面,请把『DAILY_UPDATE=no』改成 『DAILY_UPDATE=yes』就好了。至于修改的方法等到我们第三章提完 vi 后,您就会晓得啰~ 当然啦,也可以自行手动执行 updatedb 即可!


  • find
  • [root@linux ~]# find [PATH] [option] [action]
    参数:
    1. 与时间有关的参数:
       -atime n :n 为数字,意义为在 n 天之前的『一天之内』被 access 过的档案;
       -ctime n :n 为数字,意义为在 n 天之前的『一天之内』被 change 过状态的档案;
       -mtime n :n 为数字,意义为在 n 天之前的『一天之内』被 modification 过的档案;
       -newer file :file 为一个存在的档案,意思是说,只要档案比 file 还要新,
                     就会被列出来~
    2. 与使用者或组名有关的参数:
       -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 搜寻。
    3. 与档案权限及名称有关的参数:
       -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.... 的属性存在!
    4. 额外可进行的动作:
       -exec command :command 为其他指令,-exec 后面可再接额外的指令来处理搜寻到
                       的结果。
       -print        :将结果打印到屏幕上,这个动作是预设动作!
    范例:
    范例一:将过去系统上面 24 小时内有更动过内容 (mtime) 的档案列出
    [root@linux ~]# find / -mtime 0
    # 那个 0 是重点!0 代表目前的时间,所以,从现在开始到 24 小时前,
    # 有变动过内容的档案都会被列出来!那如果是三天前的 24 小时内?
    # find / -mtime 3 ,意思是说今天之前的 3*24 ~ 4*24 小时之间
    # 有变动过的档案都被列出的意思!同时 -atime 与 -ctime 的用法相同。
    
    范例二:寻找 /etc 底下的档案,如果档案日期比 /etc/passwd 新就列出
    [root@linux ~]# find /etc -newer /etc/passwd
    # -newer 用在分辨两个档案之间的新旧关系是很有用的!
    
    范例三:搜寻 /home 底下属于 dmtsai 的档案
    [root@linux ~]# find /home -user dmtsai
    # 这个东西也很有用的~当我们要找出任何一个用户在系统当中的所有档案时,
    # 就可以利用这个指令将属于某个使用者的所有档案都找出来喔!
    
    范例四:搜寻系统中不属于任何人的档案
    [root@linux ~]# find / -nouser
    # 透过这个指令,可以轻易的就找出那些不太正常的档案。
    # 如果有找到不属于系统任何人的档案时,不要太紧张,
    # 那有时候是正常的~尤其是您曾经以原始码自行编译软件时。
    
    范例五:找出档名为 passwd 这个档案
    [root@linux ~]# find / -name passwd
    # 利用这个 -name 可以搜寻档名啊!
    
    范例六:搜寻文件属性为 f (一般档案) 的档案
    [root@linux ~]# find /home -type f
    # 这个 -type 的属性也很有帮助喔!尤其是要找出那些怪异的档案,
    # 例如 socket 与 FIFO 档案,可以用 find /var -type p 或 -type s 来找!
    
    范例七:搜寻档案当中含有 SGID/SUID/SBIT 的属性
    [root@linux ~]# find / -perm +7000 
    # 所谓的 7000 就是 ---s--s--t ,那么只要含有 s 或 t 的就列出,
    # 所以当然要使用 +7000 ,使用 -7000 表示要含有 ---s--s--t 的所有三个权限,
    # 因此,就是 +7000 ~瞭乎?
    
    范例八:将上个范例找到的档案使用 ls -l 列出来~
    [root@linux ~]# find / -perm +7000 -exec ls -l {} \;
    # 注意到,那个 -exec 后面的 ls -l 就是额外的指令,
    # 而那个 {} 代表的是『由 find 找到的内容』的意思~所以, -exec ls -l {}
    # 就是将前面找到的那些档案以 ls -l 列出长的数据!至于 \; 则是表示
    # -exec 的指令到此为止的意思~意思是说,整个指令其实只有在 
    # -exec (里面就是指令下达) \;
    # 也就是说,-exec 最后一定要以 \; 结束才行!这样了解了吗?!
    
    范例九:找出系统中,大于 1MB 的档案
    [root@linux ~]# find / -size +1000k
    # 虽然在 man page 提到可以使用 M 与 G 分别代表 MB 与 GB,
    # 不过,俺却试不出来这个功能~所以,目前应该是仅支持到 c 与 k 吧!
    
    如果你要寻找一个档案的话,那么使用 find 会是一个不错的主意! 他可以根据不同的参数来给予档案的搜寻功能!例如你要寻找一个档名为 httpd.conf 的档案,你知道他应该是在 /etc 底下,那么就可以使用『 find /etc -name httpd.conf 』噜! 那如果你记得有一个档案档名包含了 httpd ,但是不知道全名怎办?!呵呵,就用通配符 * 吧,如上以:『 find /etc -name '*httpd*' 』就可将档名含有 httpd 的档案都列出来啰!不过,由于 find 在寻找数据的时后相当的耗硬盘!所以没事情不要使用 find 啦!有更棒的指令可以取代呦!那就是 whereislocate 啰!!

    但,不管怎么说, find 在找寻特殊的文件属性,以及特殊的档案权限 (SUID/SGID等等) 时, 是相当有用的工具程序之一!重要重要!

    大标题的图示本章习题练习:
    ( 要看答案请将鼠标移动到『答:』底下的空白处,按下左键圈选空白处即可察看 )
    • 什么是绝对路径与相对路径
    • 绝对路径的写法为由 / 开始写,至于相对路径则不由 / 开始写!此外,相对路径为相对于目前工作目录的路径!
    • 如何更改一个目录的名称?例如由 /home/test 变为 /home/test2
    • mv /home/test /home/test2
    • PATH 这个环境变量的意义?
    • 这个是用来指定执行档执行的时候,档案搜寻的目录路径。
    • umask 有什么用处与优点?
    • umask 可以拿掉一些属性,因此,适当的定义 umask 有助于系统的安全, 因为他可以用来建立默认的目录或档案的权限。
    • 当一个使用者的 umask 分别为 033 与 044 他所建立的档案与目录的权限为何?
    • 在 umask 为 033 时,则预设是拿掉 group 与 other 的 w(2)x(1) 权限,因此权限就成为『档案 -rw-r--r-- , 目录 drwxr--r-- 』而当 umask 044 时,则拿掉 r 的属性,因此就成为『档案 -rw--w--w-,目录 drwx-wx-wx』
    • 什么是 SUID ?
    • 当一个指令具有 SUID 的功能时,则当其他人使用这个指令时,该程序将具有指令拥有者的权限。
    • 当我要查询 /usr/bin/passwd 这个档案的一些属性时,可以使用什么指令来查询?
    • ls -al, file, lsattr
    • 尝试用 find 找出目前 linux 系统中,所有具有 SUID 的档案有哪些?
    • find / -perm -4000 -print

    2002/06/26:第一次完成 2003/02/06:重新编排与加入 FAQ
    2003/02/07:加入 basename 与 dirname 的说明
    2004/03/15:将连结档的内容移动至下一章节:Linux 磁盘与硬件管理
    2005/07/19:将旧的文章移动到 这里 了。
    2005/07/20:呼呼!好不容易啊~在被台风尾扫到的七月份,终于写完这个咚咚~
    2005/07/21:在 find 部分,多增加了范例九,以及关于利用档案大小 (size) 搜寻的功能。
    2005/07/25:在 SUID/SGID/SBIT 部分,依据 netman 与 小州 兄的建议,修改了部分的叙述!
    2006/04/09:在 rmdir 的范例内,少了一个 -p 的参数!
    2006/06/15:经由讨论区网友 dm421 的通知,发现 chattr 的部分关于 d 写错了,已订正。
    2006/08/22:增加 rm 的一些简单的说明!尤其是『 rm ./-aaa- 』的删除方法!
     
         
    http://linux.vbird.org is designed by VBird during 2001-2011. ksu.edu 

    本网页主要以Firefox配合解析度 1024x768 作为设计依据     鸟哥自由软件整合应用研究室