ThinkChat2.0新版上线,更智能更精彩,支持会话、画图、阅读、搜索等,送10W Token,即刻开启你的AI之旅 广告
## 6.2 文件与目录管理 谈了谈目录与路径之后,再来讨论一下关于文件的一些基本管理吧!文件与目录的管理上,不外乎“显示属性”、 “拷贝”、“删除文件”及“移动文件或目录”等等,由于文件与目录的管理在 Linux 当中是很重要的, 尤其是每个人自己主文件夹的数据也都需要注意管理!所以我们来谈一谈有关文件与目录的一些基础管理部分吧! ### 6.2.1 文件与目录的检视: ls ``` [root@study ~]# ls [-aAdfFhilnrRSt] 文件名或目录名称.. [root@study ~]# ls [--color={never,auto,always}] 文件名或目录名称.. [root@study ~]# 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} :输出 access 时间或改变权限属性时间 (ctime) 而非内容变更时间 (modification time) ``` 在Linux系统当中,这个 ls 指令可能是最常被执行的吧!因为我们随时都要知道文件或者是目录的相关信息啊~ 不过,我们Linux的文件所记录的信息实在是太多了,ls 没有需要全部都列出来呢~ 所以,当你只有下达 ls 时,默认显示的只有:非隐藏文件的文件名、 以文件名进行排序及文件名代表的颜色显示如此而已。举例来说, 你下达“ ls /etc ”之后,只有经过排序的文件名以及以蓝色显示目录及白色显示一般文件,如此而已。 那如果我还想要加入其他的显示信息时,可以加入上头提到的那些有用的选项呢~ 举例来说,我们之前一直用到的 -l 这个长串显示数据内容,以及将隐藏文件也一起列示出来的 -a 选项等等。 下面则是一些常用的范例,实际试做看看: ``` 范例一:将主文件夹下的所有文件列出来(含属性与隐藏文件) [root@study ~]# ls -al ~ total 56 dr-xr-x---. 5 root root 4096 Jun 4 19:49 . dr-xr-xr-x. 17 root root 4096 May 4 17:56 .. -rw-------. 1 root root 1816 May 4 17:57 anaconda-ks.cfg -rw-------. 1 root root 6798 Jun 4 19:53 .bash_history -rw-r--r--. 1 root root 18 Dec 29 2013 .bash_logout -rw-r--r--. 1 root root 176 Dec 29 2013 .bash_profile -rw-rw-rw-. 1 root root 176 Dec 29 2013 .bashrc -rw-r--r--. 1 root root 176 Jun 3 00:04 .bashrc_test drwx------. 4 root root 29 May 6 00:14 .cache drwxr-xr-x. 3 root root 17 May 6 00:14 .config # 这个时候你会看到以 . 为开头的几个文件,以及目录档 (.) (..) .config 等等, # 不过,目录档文件名都是以深蓝色显示,有点不容易看清楚就是了。 范例二:承上题,不显示颜色,但在文件名末显示出该文件名代表的类型(type) [root@study ~]# ls -alF --color=never ~ total 56 dr-xr-x---. 5 root root 4096 Jun 4 19:49 ./ dr-xr-xr-x. 17 root root 4096 May 4 17:56 ../ -rw-------. 1 root root 1816 May 4 17:57 anaconda-ks.cfg -rw-------. 1 root root 6798 Jun 4 19:53 .bash_history -rw-r--r--. 1 root root 18 Dec 29 2013 .bash_logout -rw-r--r--. 1 root root 176 Dec 29 2013 .bash_profile -rw-rw-rw-. 1 root root 176 Dec 29 2013 .bashrc -rw-r--r--. 1 root root 176 Jun 3 00:04 .bashrc_test drwx------. 4 root root 29 May 6 00:14 .cache/ drwxr-xr-x. 3 root root 17 May 6 00:14 .config/ # 注意看到显示结果的第一行,嘿嘿~知道为何我们会下达类似 ./command # 之类的指令了吧?因为 ./ 代表的是“目前目录下”的意思啊!至于什么是 FIFO/Socket ? # 请参考前一章节的介绍啊!另外,那个.bashrc 时间仅写2013,能否知道详细时间? 范例三:完整的呈现文件的修改时间 (modification time) [root@study ~]# ls -al --full-time ~ total 56 dr-xr-x---. 5 root root 4096 2015-06-04 19:49:54.520684829 +0800 . dr-xr-xr-x. 17 root root 4096 2015-05-04 17:56:38.888000000 +0800 .. -rw-------. 1 root root 1816 2015-05-04 17:57:02.326000000 +0800 anaconda-ks.cfg -rw-------. 1 root root 6798 2015-06-04 19:53:41.451684829 +0800 .bash_history -rw-r--r--. 1 root root 18 2013-12-29 10:26:31.000000000 +0800 .bash_logout -rw-r--r--. 1 root root 176 2013-12-29 10:26:31.000000000 +0800 .bash_profile -rw-rw-rw-. 1 root root 176 2013-12-29 10:26:31.000000000 +0800 .bashrc -rw-r--r--. 1 root root 176 2015-06-03 00:04:16.916684829 +0800 .bashrc_test drwx------. 4 root root 29 2015-05-06 00:14:56.960764950 +0800 .cache drwxr-xr-x. 3 root root 17 2015-05-06 00:14:56.975764950 +0800 .config # 请仔细看,上面的“时间”字段变了喔!变成较为完整的格式。 # 一般来说, ls -al 仅列出目前短格式的时间,有时不会列出年份, # 借由 --full-time 可以查阅到比较正确的完整时间格式啊! ``` 其实 ls 的用法还有很多,包括查阅文件所在 i-node 号码的 ls -i 选项,以及用来进行文件排序的 -S 选项,还有用来查阅不同时间的动作的 --time=atime 等选项(更多时间说明请参考本章后面[touch](../Text/index.html#touch)的说明)。而这些选项的存在都是因为 Linux 文件系统记录了很多有用的信息的缘故。那么 Linux 的文件系统中,这些与权限、属性有关的数据放在哪里呢? 放在 i-node 里面。关于这部分,我们会在下一章继续为你作比较深入的介绍啊! 无论如何, ls 最常被使用到的功能还是那个 -l 的选项,为此,很多 distribution 在默认的情况中, 已经将 ll (L 的小写) 设置成为 ls -l 的意思了!其实,那个功能是 [Bash shell](../Text/index.html) 的 [alias](../Text/index.html#alias) 功能呢~也就是说,我们直接输入 ll 就等于是输入 ls -l 是一样的~关于这部分,我们会在后续 bash shell 时再次的强调滴~ ### 6.2.2 复制、删除与移动: cp, rm, mv 要复制文件,请使用 cp (copy) 这个指令即可~不过, cp 这个指令的用途可多了~ 除了单纯的复制之外,还可以创建链接文件 (就是捷径啰),比对两文件的新旧而予以更新, 以及复制整个目录等等的功能呢!至于移动目录与文件,则使用 mv (move), 这个指令也可以直接拿来作更名 (rename) 的动作喔!至于移除吗?那就是 rm (remove) 这个指令啰~下面我们就来瞧一瞧先~ * cp (复制文件或目录) ``` [root@study ~]# cp [-adfilprsu] 来源文件(source) 目标文件(destination) [root@study ~]# cp [options] source1 source2 source3 .... directory 选项与参数: -a :相当于 -dr --preserve=all 的意思,至于 dr 请参考下列说明;(常用) -d :若来源文件为链接文件的属性(link file),则复制链接文件属性而非文件本身; -f :为强制(force)的意思,若目标文件已经存在且无法打开,则移除后再尝试一次; -i :若目标文件(destination)已经存在时,在覆盖时会先询问动作的进行(常用) -l :进行硬式链接(hard link)的链接文件创建,而非复制文件本身; -p :连同文件的属性(权限、用户、时间)一起复制过去,而非使用默认属性(备份常用); -r :递回持续复制,用于目录的复制行为;(常用) -s :复制成为符号链接文件 (symbolic link),亦即“捷径”文件; -u :destination 比 source 旧才更新 destination,或 destination 不存在的情况下才复制。 --preserve=all :除了 -p 的权限相关参数外,还加入 SELinux 的属性, links, xattr 等也复制了。 最后需要注意的,如果来源文件有两个以上,则最后一个目的文件一定要是“目录”才行! ``` 复制(cp)这个指令是非常重要的,不同身份者执行这个指令会有不同的结果产生,尤其是那个-a, -p的选项, 对于不同身份来说,差异则非常的大!下面的练习中,有的身份为root有的身份为一般帐号 (在我这里用 dmtsai 这个帐号), 练习时请特别注意身份的差别喔!好!开始来做复制的练习与观察: ``` 范例一:用root身份,将主文件夹下的 .bashrc 复制到 /tmp 下,并更名为 bashrc [root@study ~]# cp ~/.bashrc /tmp/bashrc [root@study ~]# cp -i ~/.bashrc /tmp/bashrc cp: overwrite `/tmp/bashrc'? n <==n不覆盖,y为覆盖 # 重复作两次动作,由于 /tmp 下面已经存在 bashrc 了,加上 -i 选项后, # 则在覆盖前会询问使用者是否确定!可以按下 n 或者 y 来二次确认呢! 范例二:变换目录到/tmp,并将/var/log/wtmp复制到/tmp且观察属性: [root@study ~]# cd /tmp [root@study tmp]# cp /var/log/wtmp . <==想要复制到目前的目录,最后的 . 不要忘 [root@study tmp]# ls -l /var/log/wtmp wtmp -rw-rw-r--. 1 root utmp 28416 Jun 11 18:56 /var/log/wtmp -rw-r--r--. 1 root root 28416 Jun 11 19:01 wtmp # 注意上面的特殊字体,在不加任何选项的情况下,文件的某些属性/权限会改变; # 这是个很重要的特性!要注意喔!还有,连文件创建的时间也不一样了! # 那如果你想要将文件的所有特性都一起复制过来该怎办?可以加上 -a 喔!如下所示: [root@study tmp]# cp -a /var/log/wtmp wtmp_2 [root@study tmp]# ls -l /var/log/wtmp wtmp_2 -rw-rw-r--. 1 root utmp 28416 Jun 11 18:56 /var/log/wtmp -rw-rw-r--. 1 root utmp 28416 Jun 11 18:56 wtmp_2 # 瞭了吧!整个数据特性完全一模一样ㄟ!真是不赖~这就是 -a 的特性! ``` 这个 cp 的功能很多,由于我们常常会进行一些数据的复制,所以也会常常用到这个指令的。 一般来说,我们如果去复制别人的数据 (当然,该文件你必须要有 read 的权限才行啊! ^_^) 时, 总是希望复制到的数据最后是我们自己的,所以,在默认的条件中, cp 的来源文件与目的文件的权限是不同的,目的文件的拥有者通常会是指令操作者本身。举例来说, 上面的范例二中,由于我是 root 的身份,因此复制过来的文件拥有者与群组就改变成为 root 所有了! 这样说,可以明白吗?^_^ 由于具有这个特性,因此当我们在进行备份的时候,某些需要特别注意的特殊权限文件, 例如密码档 (/etc/shadow) 以及一些配置文件,就不能直接以 cp 来复制,而必须要加上 -a 或者是 -p 等等可以完整复制文件权限的选项才行!另外,如果你想要复制文件给其他的使用者, 也必须要注意到文件的权限(包含读、写、执行以及文件拥有者等等), 否则,其他人还是无法针对你给予的文件进行修订的动作喔!注意注意! ``` 范例三:复制 /etc/ 这个目录下的所有内容到 /tmp 下面 [root@study tmp]# cp /etc/ /tmp cp: omitting directory `/etc' <== 如果是目录则不能直接复制,要加上 -r 的选项 [root@study tmp]# cp -r /etc/ /tmp # 还是要再次的强调喔! -r 是可以复制目录,但是,文件与目录的权限可能会被改变 # 所以,也可以利用“ cp -a /etc /tmp ”来下达指令喔!尤其是在备份的情况下! 范例四:将范例一复制的 bashrc 创建一个链接文件 (symbolic link) [root@study tmp]# ls -l bashrc -rw-r--r--. 1 root root 176 Jun 11 19:01 bashrc <==先观察一下文件情况 [root@study tmp]# cp -s bashrc bashrc_slink [root@study tmp]# cp -l bashrc bashrc_hlink [root@study tmp]# ls -l bashrc* -rw-r--r--. 2 root root 176 Jun 11 19:01 bashrc <==与原始文件不太一样了! -rw-r--r--. 2 root root 176 Jun 11 19:01 bashrc_hlink lrwxrwxrwx. 1 root root 6 Jun 11 19:06 bashrc_slink -> bashrc ``` 范例四可有趣了!使用 -l 及 -s 都会创建所谓的链接文件(link file),但是这两种链接文件却有不一样的情况。这是怎么一回事啊? 那个 -l 就是所谓的实体链接(hard link),至于 -s 则是符号链接(symbolic link), 简单来说,bashrc_slink 是一个“捷径”,这个捷径会链接到bashrc去!所以你会看到文件名右侧会有个指向(->)的符号! 至于bashrc_hlink文件与bashrc的属性与权限完全一模一样,与尚未进行链接前的差异则是第二栏的link数由1变成2了! 鸟哥这里先不介绍实体链接,因为实体链接涉及 i-node 的相关知识,我们下一章谈到文件系统(filesystem)时再来讨论这个问题。 ``` 范例五:若 ~/.bashrc 比 /tmp/bashrc 新才复制过来 [root@study tmp]# cp -u ~/.bashrc /tmp/bashrc # 这个 -u 的特性,是在目标文件与来源文件有差异时,才会复制的。 # 所以,比较常被用于“备份”的工作当中喔! ^_^ 范例六:将范例四造成的 bashrc_slink 复制成为 bashrc_slink_1 与bashrc_slink_2 [root@study tmp]# cp bashrc_slink bashrc_slink_1 [root@study tmp]# cp -d bashrc_slink bashrc_slink_2 [root@study tmp]# ls -l bashrc bashrc_slink* -rw-r--r--. 2 root root 176 Jun 11 19:01 bashrc lrwxrwxrwx. 1 root root 6 Jun 11 19:06 bashrc_slink -> bashrc -rw-r--r--. 1 root root 176 Jun 11 19:09 bashrc_slink_1 <==与原始文件相同 lrwxrwxrwx. 1 root root 6 Jun 11 19:10 bashrc_slink_2 -> bashrc <==是链接文件! # 这个例子也是很有趣喔!原本复制的是链接文件,但是却将链接文件的实际文件复制过来了 # 也就是说,如果没有加上任何选项时,cp复制的是原始文件,而非链接文件的属性! # 若要复制链接文件的属性,就得要使用 -d 的选项了!如 bashrc_slink_2 所示。 范例七:将主文件夹的 .bashrc 及 .bash_history 复制到 /tmp 下面 [root@study tmp]# cp ~/.bashrc ~/.bash_history /tmp # 可以将多个数据一次复制到同一个目录去!最后面一定是目录! ``` 例题:你能否使用 dmtsai 的身份,完整的复制/var/log/wtmp文件到/tmp下面,并更名为dmtsai_wtmp呢?答:实际做看看的结果如下: ``` [dmtsai@study ~]$ cp -a /var/log/wtmp /tmp/dmtsai_wtmp [dmtsai@study ~]$ ls -l /var/log/wtmp /tmp/dmtsai_wtmp -rw-rw-r--. 1 dmtsai dmtsai 28416 6月 11 18:56 /tmp/dmtsai_wtmp -rw-rw-r--. 1 root utmp 28416 6月 11 18:56 /var/log/wtmp ``` 由于 dmtsai 的身份并不能随意修改文件的拥有者与群组,因此虽然能够复制wtmp的相关权限与时间等属性, 但是与拥有者、群组相关的,原本 dmtsai 身份无法进行的动作,即使加上 -a 选项,也是无法达成完整复制权限的! 总之,由于 cp 有种种的文件属性与权限的特性,所以,在复制时,你必须要清楚的了解到: * 是否需要完整的保留来源文件的信息? * 来源文件是否为链接文件 (symbolic link file)? * 来源文件是否为特殊的文件,例如 FIFO, socket 等? * 来源文件是否为目录? * rm (移除文件或目录) ``` [root@study ~]# rm [-fir] 文件或目录 选项与参数: -f :就是 force 的意思,忽略不存在的文件,不会出现警告讯息; -i :互动模式,在删除前会询问使用者是否动作 -r :递回删除啊!最常用在目录的删除了!这是非常危险的选项!!! 范例一:将刚刚在 cp 的范例中创建的 bashrc 删除掉! [root@study ~]# cd /tmp [root@study tmp]# rm -i bashrc rm: remove regular file `bashrc'? y # 如果加上 -i 的选项就会主动询问喔,避免你删除到错误的文件名! 范例二:通过万用字符*的帮忙,将/tmp下面开头为bashrc的文件名通通删除: [root@study tmp]# rm -i bashrc* # 注意那个星号,代表的是 0 到无穷多个任意字符喔!很好用的东西! 范例三:将 cp 范例中所创建的 /tmp/etc/ 这个目录删除掉! [root@study tmp]# rmdir /tmp/etc rmdir: failed to remove '/tmp/etc': Directory not empty <== 删不掉啊!因为这不是空的目录! [root@study tmp]# rm -r /tmp/etc rm: descend into directory `/tmp/etc'? y rm: remove regular file `/tmp/etc/fstab'? y rm: remove regular empty file `/tmp/etc/crypttab'? ^C <== 按下 [crtl]+c 中断 .....(中间省略)..... # 因为身份是 root ,默认已经加入了 -i 的选项,所以你要一直按 y 才会删除! # 如果不想要继续按 y ,可以按下“ [ctrl]-c ”来结束 rm 的工作。 # 这是一种保护的动作,如果确定要删除掉此目录而不要询问,可以这样做: [root@study tmp]# \rm -r /tmp/etc # 在指令前加上反斜线,可以忽略掉 alias 的指定选项喔!至于 alias 我们在bash再谈! # 拜托!这个范例很可怕!你不要删错了!删除 /etc 系统是会挂掉的! 范例四:删除一个带有 - 开头的文件 [root@study tmp]# touch ./-aaa- <==[touch](../Text/index.html#touch)这个指令可以创建空文件! [root@study tmp]# ls -l -rw-r--r--. 1 root root 0 Jun 11 19:22 -aaa- <==文件大小为0,所以是空文件 [root@study tmp]# rm -aaa- rm: invalid option -- 'a' <== 因为 "-" 是选项嘛!所以系统误判了! Try 'rm ./-aaa-' to remove the file `-aaa-'. <== 新的 bash 有给建议的 Try 'rm --help' for more information. [root@study tmp]# rm ./-aaa- ``` 这是移除的指令(remove),要注意的是,通常在Linux系统下,为了怕文件被 root 误杀,所以很多 distributions 都已经默认加入 -i 这个选项了!而如果要连目录下的东西都一起杀掉的话, 例如子目录里面还有子目录时,那就要使用 -r 这个选项了!不过,使用“ rm -r ”这个指令之前,请千万注意了,因为该目录或文件“肯定”会被 root 杀掉!因为系统不会再次询问你是否要砍掉呦!所以那是个超级严重的指令下达呦! 得特别注意!不过,如果你确定该目录不要了,那么使用 rm -r 来循环杀掉是不错的方式! 另外,范例四也是很有趣的例子,我们在之前就谈过,文件名最好不要使用 "-" 号开头, 因为 "-" 后面接的是选项,因此,单纯的使用“ rm -aaa- ”系统的指令就会误判啦! 那如果使用后面会谈到的正则表达式时,还是会出问题的!所以,只能用避过首位字符是 "-" 的方法啦! 就是加上本目录“ ./ ”即可!如果 man rm 的话,其实还有一种方法,那就是“ rm -- -aaa- ”也可以啊! * mv (移动文件与目录,或更名) ``` [root@study ~]# mv [-fiu] source destination [root@study ~]# mv [options] source1 source2 source3 .... directory 选项与参数: -f :force 强制的意思,如果目标文件已经存在,不会询问而直接覆盖; -i :若目标文件 (destination) 已经存在时,就会询问是否覆盖! -u :若目标文件已经存在,且 source 比较新,才会更新 (update) 范例一:复制一文件,创建一目录,将文件移动到目录中 [root@study ~]# cd /tmp [root@study tmp]# cp ~/.bashrc bashrc [root@study tmp]# mkdir mvtest [root@study tmp]# mv bashrc mvtest # 将某个文件移动到某个目录去,就是这样做! 范例二:将刚刚的目录名称更名为 mvtest2 [root@study tmp]# mv mvtest mvtest2 <== 这样就更名了!简单~ # 其实在 Linux 下面还有个有趣的指令,名称为 rename , # 该指令专职进行多个文件名的同时更名,并非针对单一文件名变更,与mv不同。请man rename。 范例三:再创建两个文件,再全部移动到 /tmp/mvtest2 当中 [root@study tmp]# cp ~/.bashrc bashrc1 [root@study tmp]# cp ~/.bashrc bashrc2 [root@study tmp]# mv bashrc1 bashrc2 mvtest2 # 注意到这边,如果有多个来源文件或目录,则最后一个目标文件一定是“目录!” # 意思是说,将所有的数据移动到该目录的意思! ``` 这是搬移 (move) 的意思!当你要移动文件或目录的时后,呵呵!这个指令就很重要啦! 同样的,你也可以使用 -u ( update )来测试新旧文件,看看是否需要搬移啰! 另外一个用途就是“变更文件名!”,我们可以很轻易的使用 mv 来变更一个文件的文件名呢!不过,在 Linux 才有的指令当中,有个 rename , 可以用来更改大量文件的文件名,你可以利用 man rename 来查阅一下,也是挺有趣的指令喔! ### 6.2.3 取得路径的文件名称与目录名称 每个文件的完整文件名包含了前面的目录与最终的文件名,而每个文件名的长度都可以到达 255 个字符耶! 那么你怎么知道那个是文件名?那个是目录名?嘿嘿!就是利用斜线 (/) 来分辨啊! 其实,取得文件名或者是目录名称,一般的用途应该是在写程序的时候用来判断之用的啦~ 所以,这部分的指令可以用在第三篇内的 shell scripts 里头喔! 下面我们简单的以几个范例来谈一谈 basename 与 dirname 的用途! ``` [root@study ~]# basename /etc/sysconfig/network network <== 很简单!就取得最后的文件名~ [root@study ~]# dirname /etc/sysconfig/network /etc/sysconfig <== 取得的变成目录名了! ```