# 6.2 文件与目录管理

谈了谈目录与路径之后，再来讨论一下关于文件的一些基本管理吧！文件与目录的管理上，不外乎“显示属性”、 “拷贝”、“删除文件”及“移动文件或目录”等等，由于文件与目录的管理在 Linux 当中是很重要的， 尤其是每个人自己主文件夹的数据也都需要注意管理！所以我们来谈一谈有关文件与目录的一些基础管理部分吧！

## 6.2.1 文件与目录的检视： ls

```shell
[root@study ~]# ls [-aAdfFhilnrRSt] 文件名或目录名称..
[root@study ~]# ls [--color={never,auto,always}] 文件名或目录名称..
[root@study ~]# ls [--full-time] 文件名或目录名称..
选项与参数：
-a  ：全部的文件，连同隐藏文件（ 开头为 . 的文件） 一起列出来（常用）
-A  ：全部的文件，连同隐藏文件，但不包括 . 与 .. 这两个目录
-d  ：仅列出目录本身，而不是列出目录内的文件数据（常用）
-f  ：直接列出结果，而不进行排序 （ls 默认会以文件名排序！）
-F  ：根据文件、目录等信息，给予附加数据结构，例如：
      *:代表可可执行文件； /:代表目录； =:代表 socket 文件； &#124;:代表 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 选项等等。 下面则是一些常用的范例，实际试做看看：

```shell
范例一：将主文件夹下的所有文件列出来（含属性与隐藏文件）
[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]的说明）。而这些选项的存在都是因为 Linux 文件系统记录了很多有用的信息的缘故。那么 Linux 的文件系统中，这些与权限、属性有关的数据放在哪里呢？ 放在 i-node 里面。关于这部分，我们会在下一章继续为你作比较深入的介绍啊！

无论如何， ls 最常被使用到的功能还是那个 -l 的选项，为此，很多 distribution 在默认的情况中， 已经将 ll （L 的小写） 设置成为 ls -l 的意思了！其实，那个功能是 \[Bash shell] 的 \[alias] 功能呢～也就是说，我们直接输入 ll 就等于是输入 ls -l 是一样的～关于这部分，我们会在后续 bash shell 时再次的强调滴～

## 6.2.2 复制、删除与移动： cp, rm, mv

要复制文件，请使用 cp （copy） 这个指令即可～不过， cp 这个指令的用途可多了～ 除了单纯的复制之外，还可以创建链接文件 （就是捷径啰），比对两文件的新旧而予以更新， 以及复制整个目录等等的功能呢！至于移动目录与文件，则使用 mv （move）， 这个指令也可以直接拿来作更名 （rename） 的动作喔！至于移除吗？那就是 rm （remove） 这个指令啰～下面我们就来瞧一瞧先～

* cp （复制文件或目录）

```shell
[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 这个帐号）， 练习时请特别注意身份的差别喔！好！开始来做复制的练习与观察：

```shell
范例一：用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 等等可以完整复制文件权限的选项才行！另外，如果你想要复制文件给其他的使用者， 也必须要注意到文件的权限（包含读、写、执行以及文件拥有者等等）， 否则，其他人还是无法针对你给予的文件进行修订的动作喔！注意注意！

```shell
范例三：复制 /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）时再来讨论这个问题。

```shell
范例五：若 ~/.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呢？答：实际做看看的结果如下：

```shell
[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 （移除文件或目录）

```shell
[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]这个指令可以创建空文件！
[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 （移动文件与目录，或更名）

```shell
[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 的用途！

```shell
[root@study ~]# basename /etc/sysconfig/network
network         <== 很简单！就取得最后的文件名～
[root@study ~]# dirname /etc/sysconfig/network
/etc/sysconfig  <== 取得的变成目录名了！
```


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://inityun.gitbook.io/niao-ge-de-linux-si-fang-cai-1/chapter_6/6.2-wen-jian-yu-mu-lu-guan-li.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
