0%

Linux-文件目录管理

文件目录管理

下表罗列了Linux文件系统中主要目录的内容

目 录 内 容
/bin 构建最小系统所需要的命令(最常用的命令)
/boot 内核和启动文件
/dev 各种设备文件
/etc 系统软件的启动和配置文件
/home 用户的主目录(用户所有数据,极其重要)
/lib C编译器的库
/media 可移动介质的安装点
/opt 可选的应用软件包(用deb包安装的部分软件在这)
/proc 进程的映像
/root 根用户root的主目录
/sbin 和系统操作有关的命令
/tmp 临时文件存放点
/usr 非系统的程序和命令(apt安装的位置)
/var 系统专用的数据和配置文件

mkdir: 建立目录

mkdir命令可以一次建立一个或几个目录.

1
$ mkdir document picture ## 新建两个目录

这样的创建是先利用cd到你想创建的位置,再创建目录.用户也可以用绝对路径来新建目录,这样的话不需要用cd来跳转到创建的位置,在任意位置用mkdir加绝对路径即可创建目录,

1
$ mkdir ~/picture/temp ## 在主目录的picture目录下创建temp子目录

这个命令合法是因为picture目录存在主目录下,如果用户试图在一个不存在的目录下创建新子目录,那命令会报错.为了避免这个报错,我们可以用-p选项来创建目录.

1
2
$ mkdir -p /home/username ## 在home目录下创建username目录,如果他存在那就不去创建
$ mkdir -p ~/test1/test2 ## 如果主目录下没有test1,那么不会报错,而是先创建test1再在其中创建test2

touch: 建立一个空文件

touch后面接文件名作为参数,可以在当前目录创建一个或多个新文件,

1
2
$ touch hello ## 在当前目录创建文件名为hello的文件
$ touch 'hello world' ## 在当前目录创建文件名为 'hello world' 的文件

如果我们在上面的’hello world’中不加引号,那touch会认为创建hello和world两个文件.用touch命令创建的文件是空文件,其内不包含任何内容.

touch除了创建空文件的作用,其更重要的用途是更新一个文件的建立日期和时间.

1
2
3
4
5
$ ls -l init.el~ ## 查看文件的时间属性
-rw-r--r-- 1 lyd lyd 997 2月 5 21:54 init.el~ ## 原来文件时间属性是2024/2/5-21:54
$ touch init.el~ ## 修改文件的时间属性
$ ls -l init.el~ ## 查看改过的文件时间属性
-rw-r--r-- 1 lyd lyd 997 3月 20 20:52 init.el~ ## 改过以后文件时间变成了2024/3/20-20:52

touch命令在自动备份和整理文件文件时非常有用.

mv: 移动和重命名

mv其实是move的缩写形式.这个命令可以用来移动文件或目录到另一个路径.这里移动到的文件

1
2
$ mv hello bin/ ## 把hello文件移动到bin目录下
$ mv Photos/ 桌面/ ## 把Photos目录移动到桌面目录下

由于执行mv命令的时候并不会有任何信息显示,那么如果目标目录中有一个同名文件,不加任何选项的mv命令会强制替换文件.这一行为极其危险,容易强制替换掉一些关键文件.为了避免这种情况出现,我们可以用-i选项来控制覆盖文件与否,

1
$ mv -i hello test/ ## 出现同名文件询问是否覆盖

其会先询问用户是否覆盖旧文件,输入y表示直接覆盖,输入n表示取消移动操作.

另外一个避免强制覆盖的选项是-b,其与-i的询问不同,如果出现同名文件,那么他会在转移之前将目标目录中的同名文件的文件名后面加一个~,形成一个备份,从而避免文件覆盖情况的发生.

1
$ mv -b hello test/ ## 出现同名文件则对其备份

Linux中不存在重命名的操作,我们可以认为重命名只不过是在同一级目录下的移动而已.因此我们可以用mv命令来实现对文件或目录的重命名.

1
2
$ mv hello world ## 在同级目录下进行重命名
$ mv /home/lyd/hello /home/lyd/learning/world ## 移动到其他目录并且重命名

使用mv命令可能出现的一些简单情况,

1
$ mv file1 file2 ## 移动file1到file2

如果file2存在,他的内容会被file1的内容覆盖.如果file2不存在,那就会创建file2.但这两种情况下,file1都不会存在.

1
$ mv file1 file2 dir1/ ## 移动file1和file2到目录dir1中

这个命令的前提是目录dir1必须已经存在.

1
$ mv dir1/ dir2/ ## 移动目录dir1到目录dir2

如果目录dir2不存在,创建目录dir2,并且移动目录dir1的内容到目录dir2中,同时删除目录dir1.如果dir2存在,移动目录dir1及他的内容到目录dir2.

cp: 复制文件和目录

cp命令用来复制文件和目录.下面的指令用来将test.php复制到test目录下

1
$ cp test.php test/ ## 复制文件到指定路径

和mv命令一样,cp在默认情况下也会强制覆盖目标目录中的同名文件.同样我们可以用-i选项来对这种覆盖文件的情况进行提示,我们也可以用-b选项来避免询问,通过对同名文件进行一个修改命名再进行复制.这两个选项的使用和mv命令的一样,因此不再赘述.

如果我们希望复制一个目录到另一个目录下,而直接用cp命令进行复制,则会有如下结果

1
2
$ cp learning/ Downloads/ ## 报错的复制目录
cp: 未指定 -r;略过目录 'learning/'

这是因为cp命令在执行复制任务的时候会自动跳过目录.如果我们一定要连同目录及其内部的文件一块复制到另一个目录,我们需要用-r选项来实现这一操作.

1
$ cp -r learning/ Downloads/ ##  复制目录到指定目录

使用cp可能出现的一些简单情况,

1
$ cp file1 file2 ## 复制文件file1内容到文件file2

如果file2存在,那么file2的内容会被file1的内容覆盖.如果file2不存在,那就会创建一个file2.但和mv删除file1不同,cp命令会保留file1.

1
$ cp file1 file2 dir1/ ## 复制文件file1和file2到目录dir1

但这里必须要求目录dir1存在.

1
$ cp dir1/* dir2/ ## 用通配符移动文件

与-r选项不同,用通配符来批量移动dir1中的文件,要求dir2存在并且移动只会复制dir1中的文件和子目录,不会在dir2中复制dir1这个目录.

rmdir 和 rm: 删除目录和文件

rmdir命令可以用来删除目录.其只需要在rmdir命令后面接要删除的文件名即可.

1
2
$ mkdir remove ##创建一个空目录
$ rmdir remove ##删除指定的空目录

但rmdir只能用于删除空目录,一旦试图用其删除非空目录,那么会有如下报错

1
2
$ rmdir learning
rmdir: 删除 'learning' 失败: 目录非空

因此,如果我们想要用rmdir删除非空目录,我们需要先删除该目录下的所有子目录及文件.

对于文件的删除可以用rm命令,其实rm命令也可以针对目录,此处rm命令删除的目录是允许出现非空目录,因此rm的应用远比rmdir更为广泛.rm命令可以一次性删除单个或多个文件,

1
2
$ rm test/* ## 删除test目录下的所有文件
$ rm halo ## 删除halo文件

和前面的mv和cp命令一样,rm不会在运行过程中出现任何提示,利用rm命令删除的文件并不会被移入回收站,而是直接从系统中删除.因此为了安全的使用rm,我们一般用-i选项来在删除过程之前给出提示等待用户确认,与前面的mv和cp一样.但有个例外,如果我们删除只读文件,那么即便我们不使用-i选项,rm命令也会对这一操作进行询问

1
2
$ rm test ## 删除test只读文件
rm: 是否删除有写保护的普通空文件 'test'?

如果对这个交互操作默认是y,且不想多次交互,我们可以用-f选项来跳过这些交互操作,rm会自动对这些交互操作回答y.

1
$ rm -f test ## -f选项跳过交互操作 

我们可以用带-r选项的rm命令会递归的删除指定目录下所有文件和子目录.

1
$ rm -r Photos/ ## 递归删除Photos目录

关键在于使用rm -rf命令一定要注意评估删除的后果,不然可能会破坏系统的稳定性,故慎用rm -r命令.

Linux文件目录权限

Linux的文件目录权限针对三类人群:文件所有者(属主),文件属组用户,其他人.关键在于其他人的多样性,可能会对文件目录内容进行修改,从而有机会造成不可预料的信息损坏.root用户虽然应该归属于上面的其他人,但root用户显然具有对系统任意文件的查看,修改,执行权利,因为root用户拥有控制一台计算机的所有权限.

文件所有者一般是文件的创建者.但这并不是绝对的,root用户可以修改一个文件的属主用户.换言之,在某个用户在linux系统创建了某个文件,此时文件所有者(属主)自动是文件创建者,但后续过程中root用户可以将文件所有者进行转让,这个转让过程也仅能用root用户进行.

当然文件的权限也会被给予一个用户组,我们称这个用户组为文件的属组.组是一群用户组成的一个集合.文件属组中的用户按照设置对文件享有特定的权限.通常而言,当一个用户创建了一个文件,那么该文件的属主就是这个用户,而文件的属组则是有且仅有该用户的用户组.当然我们也可以设置这个文件属组是一个不包括文件属主的用户组.如果文件属主执行文件操作的时候,系统只会关注于文件属主的权限,而文件属组的权限并不会对文件属主的权限造成影响.

其他人则是不包括文件所有者,文件属组用户和root用户以外的其他用户.通常其他人的权限十分低,甚至于无法对文件有任何权限.

可以用来赋予用户的文件和目录的权限为读取(r),写入(w)和执行(x).对于文件而言,读取权限意味着可以打开并查看文件的内容,写入权限控制着对文件的修改权限,至于是否能呢更狗删除和重命名一个文件则是由其父目录的权限设置所控制.要让一个文件可执行,必须设置其执行权限.可执行文件有两类,一类是可以直接由CPU执行的二进制代码,另一类则是Shell脚本程序.

对目录而言,目录的执行权限其实是控制用户是否能够进入该目录,因此目录的执行权限其实上是目录的最基本的权限.而读取权限负责确定能否列出该目录的内容,写入权限则控制在目录中创建,删除和重命名文件.

ls -l: 查看文件类型

前面介绍ls命令时,提到了ls -l来查看文件的属性,此处进一步解释展示的文件属性的参数

1
2
3
$ ls -l  ## 列出所有文件和目录以及其对应的属性
总计 152
drwxr-xr-x 2 lyd lyd 4096 2月 5 09:49 公共
  • 第一个字段中的第一个字符表示文件类型,这个例子是d,其表示这是一个目录,具体的字符和文件类型的对应下表所示,
文件类型 符号 文件类型 符号
普通文件 - 本地域套接口 s
目录 d 有名管道 p
字符设备文件 c 符号链接 l
块设备文件 b    

</div>
其中具体的含义大概解释如下,Linux一般用设备文件来表示一个特定的硬件设备.Linux中有两类设备文件:字符设备文件和块设备文件.其中字符设备指的是能从他那读取成字符序列的设备,如磁带和串行设备;块设备则是指用来存储数据并对其各部分内容提供同等访问权的设备,如磁盘.一般我们可以称字符设备为顺序访问设备,块设备则为随机访问设备.这是因为块设备可以从硬盘的任何随机位置获取数据,而字符设备则必须按照数据发送的顺序从串行线路上获得.但是系统中存在设备文件,并不代表着他一定链接着相应的硬件设备,而是表示其具有处理对应硬件设备的能力.

关于本地域套接口和有名管道这两个文件涉及到了进程间通信,日常使用并不常见.

符号链接会在后续的ln里介绍,类似于windows系统的快捷方式.

  • 接下来的rwxr-xr-x则是三组权限位,断句如下rwx,r-x,r-x,分别代表着属主,属组,其他用户的权限.r表示可读取,w表示可写入,x表示可执行,如果某个权限被禁用,那么其会用短横线-取代.
  • 紧跟着三组权限位的数字表示文件的链接树木.此处是2.表示该目录存在两个链接,关于链接后续会给出介绍.
  • 后面第三个字段和第四个字段表示文件的属主和属组.

ls -l可以用来查看某个特定文件的属性,但是如果我们需要查看目录的属性则需要用ls -ld命令来查看.

chown 和 chgrp: 改变文件所有权

chown命令用于改变文件的所有权.chown命令的基本语法为:

1
chown [OPTION] ... [OWNER][:[GROUP]] FILE... ## chown语法基本结构

这条命令可以将文件FILE的属主更改为OWNER,属组更改为GROUP. 下面命令给出了一个示例,其将文件的属主更改为LYD,同时将文件属组更改为root组,

1
$ sudo chown LYD:root file ## 修改文件file的属主为LYD,同时修改属组为root组

如果我们只需要修改文件的属主,那么我们只需要输入OWNER,不需要输入:GROUP.

1
$ sudo chown LYD file ## 修改文件file的属主为LYD,但不对属组进行修改

同样,我们只修改文件属组的话,只需要输入:GROUP,但这里要注意的是冒号:并不是可省略的,省略参数OWNER即可,

1
$ sudo chown :root file ## 修改文件file的属组为root,但不对属主进行操作

我们在前面用chown修改单个文件的属组和属组.实际上我们可以用chown来修改目录文件的属主和属组,但是显然如果我们只修改目录文件的属主和属组的话,并没有什么意义.因此我们可以利用chown命令的-R选项,用于改变一个目录及其下所有文件(包括子目录)的所有权设置.

1
$ sudo chown -R LYD:root iso/ ## 递归修改iso文件及其下的所有文件(包括子目录)的所有权

由于chown可以更改文件的属主和属组属性,但实际上Linux系统提供了另一个命令chgrp,其专门用来修改文件的属组.

1
$ chgrp nogroup days ## 更改文件属组

同样和chown一样,我们也可以用-R选项来递归的更改目录及其下所有文件和子目录的属组.但是这里chgrp和chown有一个关键区别在于,chown修改文件属组需要用root用户权限,然而对于chgrp,其只需要修改的用户在文件的属组就可以修改文件的属组.

chmod: 改变文件权限

chmod用来改变一个文件的权限.其修改删除权限的模式是用户组+/-权限的表达式.具体而言,用户组分为文件属主(u),文件属组(g),其他人(o),以及所有人(a).权限则表示读取(r),写入(w)和执行(x).

1
$ chmod u+x days ## 为days文件属主提供文件执行权限

chmod可以用a来同时指定包括文件属主,文件属组和其他人的三类人,我们可以利用以此同时给全部人员增加或删除权限.

1
$ chmod a+w days ## 为days文件的所有人同时提供文件的写入权限

如果我们需要同时给三类人增删权限,除了用a来表示所有人以外,实际上我们可以不加任何用户组标记,直接用+/-权限的形式,同样可以给全部人员增加或删除权限

1
$ chmod +rw file ## 为文件file的所有用户增加读取权限和写入权限

这个命令中我们通过+rw同时给所有用户添加了读取权限和写入权限,这也就是说我们可以在一个命令中同时给用户添加或删除一个或多个权限.进一步我们可以利用逗号来分隔不同的两个修改权限操作

1
$ chmod u+r,go-w file ## 为文件file的属主添加读取权限,属组和其他人则删除写入权限

在这里,我们用了一个go来同时对属组和其他人进行修改权限操作,因此实际上我们可以看出来前面用的所有人标识符a和ugo等价.上面我们用逗号分隔符来分隔对不同用户的修改权限操作,实际上我们也可以用逗号分隔符来分隔对同一用户做的不同修改操作.

1
$ chmod u+r,u-w file ## 为文件file的属主添加读取权限的同时,删除文件属主的写入权限

如果用上面的添加或删除操作修改用户的权限来达到预期会极其复杂,中间也可能需要多次用ls -l查看文件属性.因此chmod还存在一个规则:用户组=权限来直接设置文件权限.

1
$ chmod ug=rw,o=r file ## 文件的属主和属组权限更改为读取权限和写入权限,而其他人的权限更改为读取权限

如果文件本身就有一个默认设定的权限,=这种规则会先重置需要修改的用户组的默认规则,然后按照=设定的权限重新赋予.虽然我们举了对所有用户用=修改权限的例子,但实际上,=规则是可以只对其中部分进行修改的.

最后最为常用的是用户组1=用户组2,其的作用在于将用户组1的权限和用户组2的权限设置成一样.明确来说,他的作用是将用户组2的权限覆盖用户组1的权限.

1
$ chmod o=u file ## 将文件file的其他人权限设置成文件属主的权限

最为关键的一点是只有文件的属主和root用户才可以修改文件的权限.

1
$ chmod u+r file1 file2 ## 为文件file1和file2的属主增加读取权限

但这里要注意这样的修改要么在root用户下进行,要么两个文件的属主是同一个用户

虽然我们前面已经将权限用三个字母来表示,但这对批量修改文件的权限十分麻烦,因此我们可以用八进制来代表设置权限.由于对于任意的权限而言,其只存在两种状态:设置(1)和不设置(0).所以我们可以得到任意一组权限设置的八进制表示,如’rwx’的二进制为111,八进制为7;’r-x’的二进制为101,八进制为5.这样我们就可以将完整的9位权限位用3个八进制数来表示,例如’rwxr-x-w-‘分别对应的三个三位二进制为111/101/010,其对应的三个八进制数752.

1
$ chmod 752 file ## 将文件权限设置为 rwx/ r-x/ -w- 

ln: 建立链接

ln命令是用来为某个文件在另一个位置创建一个同步的链接.链接主要分为符号链接(软链接)和硬链接两大类.无论硬链接还是软链接,他们都不会重新复制原来的文件,他们只会占用非常少量的磁盘空间.

符号链接,也被称为软链接,其用ln -s命令来创建生成.软链接具有如下的特点,

  1. 软链接以路径的形式存在,类似于windows系统的快捷方式

  2. 软链接可以跨越不同的文件系统

  3. 软链接可以对一个不存在的文件名进行链接

  4. 软链接还可以对目录文件进行链接7

    1
    2
    3
    $ ln -s TARGET LINKNAME ## 为文件TARGET创建了一个别名LINKNAME
    $ ls -l LINKNAME ## 查看LINK_NAME的属性
    lrwxrwxrwx 1 lyd lyd 6 4月 15 11:31 LINK_NAME -> TARGET

从这里我们可以看出这个文件被指向TARGET文件,因此访问LINK_NAME就相当于访问TARGET.需要注意的是,这里的LINKNAME只是提供了访问TARGET的一个路径,因此我们删除LINKNAME并不会影响TARGET的正常运行,反之我们删除TARGET,虽然不会同时删除LINKNAME,但是其存在已经没有任何意义了.

同样符号链接还可用于目录,

1
$ ln -s learning/ LINK ## 为目录learning创建一个别名LINK

此外,对于软链接而言,其还存在删除和修改操作如下,

1
$ rm -rf LINKNAME ## 删除软链接

切记不要在软链接后面加/,不然如果软链接对应的是目录文件,可能会直接把目录文件里的内容全部删除.

1
$ ln -snf NEWTARGET LINK ## 将LINK链接的文件从原文件更改到新文件NEWTARGET

这里的修改操作,不止允许同一类型之间文件的链接相互更改,还可以把普通文件的链接文件链接到目录文件,亦或反之.

Linux中的另一种链接称为硬链接.其将两个独立的文件联系在一起,因此硬链接和软链接的本质区别是,硬链接是直接引用,而软链接是通过名称进行引用.

硬链接具有的特性如下,

  1. 以文件副本的形式存在,但不占用实际空间
  2. 不允许给目录创建硬链接
  3. 硬链接不能跨越文件系统创建,只能在同一个文件系统里创建

硬链接和软链接不同,硬链接用不带-s选项的ln命令直接创建,

1
2
3
$ ln world worldlink ## 创建world的硬链接文件worldlink
$ ls -l worldlink ## 查看硬链接文件的属性
-r----xrw- 2 lyd lyd 4 4月 8 07:39 world_link

根据上述查看的文件属性,我们得知这两个文件是独立的,但是会被联系在一起而已.

无论软链接还是硬链接,只是对目标文件的一个访问渠道而已,因此我们在任何一类链接文件上修改都会导致目标文件的变化.

输入输出重定向和管道

重定向和管道操作是Linux的Shell命令里的一种高级特性,其允许用户修改程序获取输入或者生成输出的位置.

在默认情况下程序输出结果的位置称之为标准输出.通常来说,标准输出位都是显示器.输出重定向的作用是将程序的输出转移到另一个地方去,

1
$ ls > ~/ls_out ## 将输出结果定向到ls_out文件

如果指定文件不存在,那么这个命令会创建这个文件,反之如果这个文件是存在的,那么他会直接覆盖文件原有的内容.如果我们希望能够保留原来文件中的内容,那么我们可以用输出重定向符号>>,

1
2
3
4
5
6
7
$ date > date_out ## 将date命令的输出重定向到date_out文件
$ cat date_out ## 查看date_out文件
2024年 04月 16日 星期二 21:15:39 CST
$ uname -r >> date_out ## 将输出结果重定向至date_out文件,并且仅在末尾输出,不覆盖原文件
$ cat date_out ## 再次查看date_out文件
2024年 04月 16日 星期二 21:15:39 CST
6.5.0-26-generic

类似于标准输出的定义,程序默认情况下接受输入的地方称之为标准输入.通常来说,标准输入指向键盘.如果使用不带任何参数的cat命令,cat不会执行而是等待从标准输入来获取数据,用户可以输入一行会直接输出在屏幕上,直到Ctrl+D用来给cat命令输入一个文件结束符.
在此,我们罗列一下基于shell的常用快捷键及其含义

  1. Ctrl+c 终止当前正在执行的程序
  2. Ctrl+z 中断当前进程,但不是终止进程,只是将进程挂起,我们可以用fg命令来重新调用进程(后续介绍)
  3. Ctrl+l 清空屏幕
  4. Ctrl+d 输入特殊的二进制值,表示EOF,作为文件的结束

通过使用输入重定向符号<可以让程序从一个文件中获取输入,

1
$ cat < file ## 输出file里的内容

显然cat可以直接接受参数来显示文件内容,因此输入重定向对这类命令并没有优势,故其使用比较少.

类似,其也存在另一种重定向符号<<,被称之为立即文档.立即文档告诉shell从键盘接受输入,并传递给程序,

1
2
3
4
5
6
7
8
9
10
$ cat << EOF ## 立即文档作为输入,EOF用来输入文档终止
> Hello
> ,
> world
> !
> EOF
Hello
,
world
!

这里的EOF只是代用常见的终止缩写,实际上是可以随意使用的,只需要保证输入的内容中不会出终止代号即可.进一步,上面提到的两个重定向符号是可以在同一个命令中出现的.

管道符号|的出现则进一步使输出重定向的功能变灵活.通过一条竖线,将一个命令的输出作为下一个命令的输入,

1
2
3
$ ls | grep ld ##罗列文件列表以后查找文件名包含ld的文件
world
worldlink

当然管道可以继续叠加使用,虽然会十分复杂但是运行起来会很高效.