1.理解硬件
1.1磁盘
- 机械磁盘是计算机中的⼀个机械设备
- 磁盘--- 外设
- 慢
- 容量⼤,价格便宜
1.2磁盘物理结构
1.3磁盘的存储结构
扇区:是磁盘存储数据的基本单位,512字节,块设备
如何定位⼀个扇区呢?确定磁头要访问哪⼀个柱⾯(磁道)(cylinder)可以先定位磁头(header)定位⼀个扇区(sector)柱⾯(cylinder),磁头(head),扇区(sector),显然可以定位数据了,这就是数据定位(寻址)⽅式之⼀,CHS寻址⽅式。
扇区是从磁盘读出和写⼊信息的最⼩单位,通常⼤⼩为 512 字节。磁头(head)数:每个盘⽚⼀般有上下两⾯,分别对应1个磁头,共2个磁头磁道(track)数:磁道是从盘⽚外圈往内圈编号0磁道,1磁道...,靠近主轴的同⼼圆⽤于停靠磁头,不存储数据柱⾯(cylinder)数:磁道构成柱⾯,数量上等同于磁道个数扇区(sector)数:每个磁道都被切分成很多扇形区域,每道的扇区数量相同圆盘(platter)数:就是盘⽚的数量磁盘容量=磁头数 × 磁道(柱⾯)数 × 每道扇区数 × 每扇区字节数细节:传动臂上的磁头是共进退的
1.4磁盘的逻辑结构
细节:传动臂上的磁头是共进退的
磁道:某⼀盘⾯的某⼀个磁道展开:
即:⼀维数组
柱面:整个磁盘所有盘⾯的同⼀个磁道,即柱⾯展开:![]()
柱⾯上的每个磁道,扇区个数是⼀样的这不就是⼆维数组吗
整盘:
整个磁盘不就是多张⼆维的扇区数组表(三维数组?)
LBA地址转成CHS地址,CHS如何转换成为LBA地址。
1.5 CHS && LBA地址
- 磁头数*每磁道扇区数 = 单个柱⾯的扇区总数
- LBA = 柱⾯号C*单个柱⾯的扇区总数 + 磁头号H*每磁道扇区数 + 扇区号S - 1
- 即:LBA = 柱⾯号C*(磁头数*每磁道扇区数) + 磁头号H*每磁道扇区数 + 扇区号S - 1
- 扇区号通常是从1开始的,⽽在LBA中,地址是从0开始的
- 柱⾯和磁道都是从0开始编号的
- 总柱⾯,磁道个数,扇区总数等信息,在磁盘内部会⾃动维护,上层开机的时候,会获取到这些参数。
- 柱⾯号C = LBA // (磁头数*每磁道扇区数)【就是单个柱⾯的扇区总数】
- 磁头号H = (LBA % (磁头数*每磁道扇区数)) // 每磁道扇区数
- 扇区号S = (LBA % 每磁道扇区数) + 1
- "//": 表⽰除取整
2.引入文件系统
2.1引⼊"块"概念
注意:
- 磁盘就是⼀个三维数组,我们把它看待成为⼀个"⼀维数组",数组下标就是LBA,每个元素都是扇区
- 每个扇区都有LBA,那么8个扇区⼀个块,每⼀个块的地址我们也能算出来。
- 知道LBA:块号 = LBA/8
- 知道块号:LBA=块号*8 + n. (n是块内第⼏个扇区)
2.2引⼊"分区"概念
2.3引⼊"inode"概念
[root@localhost linux]# ls -l
总⽤量 12
-rwxr-xr-x. 1 root root 7438 "9⽉ 13 14:56" a.out
-rw-r--r--. 1 root root 654 "9⽉ 13 14:56" test.c
每⾏包含7列:• 模式• 硬链接数• ⽂件所有者• 组• ⼤⼩• 最后修改时间• ⽂件名ls -l读取存储在磁盘上的⽂件信息,然后显⽰出来
其实这个信息除了通过这种⽅式来读取,还有⼀个stat命令能够看到更多信息
[root@localhost linux]# stat test.c
File: "test.c"
Size: 654 Blocks: 8 IO Block: 4096 普通⽂件
Device: 802h/2050d Inode: 263715 Links: 1
Access: (0644/-rw-r--r--) Uid: ( 0/ root) Gid: ( 0/ root)
Access: 2017-09-13 14:56:57.059012947 +0800
Modify: 2017-09-13 14:56:40.067012944 +0800
Change: 2017-09-13 14:56:40.069012948 +0800
到这我们要思考⼀个问题,⽂件数据都储存在”块”中,那么很显然,我们还必须找到⼀个地⽅储存 ⽂件的元信息(属性信息),⽐如⽂件的创建者、⽂件的创建⽇期、⽂件的⼤⼩等等。这种储存文件元信息的区域就叫做inode,中⽂译名为”索引节点”。
ls -li命令
注意:Linux下⽂件的存储是属性和内容分离存储的Linux下,保存⽂件属性的集合叫做inode,⼀个⽂件,⼀个inode,inode内有⼀个唯⼀的标识符,叫做inode号
所以⼀个⽂件的属性inode⻓什么样⼦呢?
/*
* Structure of an inode on the disk
*/
struct ext2_inode {__le16 i_mode; /* File mode */__le16 i_uid; /* Low 16 bits of Owner Uid */__le32 i_size; /* Size in bytes */__le32 i_atime; /* Access time */__le32 i_ctime; /* Creation time */__le32 i_mtime; /* Modification time */__le32 i_dtime; /* Deletion Time */__le16 i_gid; /* Low 16 bits of Group Id */__le16 i_links_count; /* Links count 引用计数*/__le32 i_blocks; /* Blocks count */__le32 i_flags; /* File flags */union {struct {__le32 l_i_reserved1;} linux1;struct {__le32 h_i_translator;} hurd1;struct {__le32 m_i_reserved1;} masix1;} osd1; /* OS dependent 1 */__le32 i_block[EXT2_N_BLOCKS];/* Pointers to blocks */__le32 i_generation; /* File version (for NFS) */__le32 i_file_acl; /* File ACL */__le32 i_dir_acl; /* Directory ACL */__le32 i_faddr; /* Fragment address */union {struct {__u8 l_i_frag; /* Fragment number */__u8 l_i_fsize; /* Fragment size */__u16 i_pad1;__le16 l_i_uid_high; /* these 2 fields */__le16 l_i_gid_high; /* were reserved2[0] */__u32 l_i_reserved2;} linux2;struct {__u8 h_i_frag; /* Fragment number */__u8 h_i_fsize; /* Fragment size */__le16 h_i_mode_high;__le16 h_i_uid_high;__le16 h_i_gid_high;__le32 h_i_author;} hurd2;struct {__u8 m_i_frag; /* Fragment number */__u8 m_i_fsize; /* Fragment size */__u16 m_pad1;__u32 m_i_reserved2[2];} masix2;} osd2; /* OS dependent 2 */
};
/*
* Constants relative to the data blocks
*/
#define EXT2_NDIR_BLOCKS 12
#define EXT2_IND_BLOCK EXT2_NDIR_BLOCKS
#define EXT2_DIND_BLOCK (EXT2_IND_BLOCK + 1)
#define EXT2_TIND_BLOCK (EXT2_DIND_BLOCK + 1)
#define EXT2_N_BLOCKS (EXT2_TIND_BLOCK + 1)
备注:EXT2_N_BLOCKS = 15
注意:⽂件名属性并未纳⼊到inode数据结构内部inode的⼤⼩⼀般是128字节或者256,我们后⾯统⼀128字节任何⽂件的内容⼤⼩可以不同,但是属性⼤⼩⼀定是相同的
两个问题:
3.ext2 文件系统
3.1宏观认识
3.2Block Group
ext2⽂件系统会根据分区的⼤⼩划分为数个Block Group。⽽每个Block Group都有着相同的结构组成。
3.3块组内部构成
3.3.1超级块(Super Block)
/*
* Structure of the super block
*/
struct ext2_super_block {__le32 s_inodes_count; /* Inodes count */__le32 s_blocks_count; /* Blocks count */__le32 s_r_blocks_count; /* Reserved blocks count */__le32 s_free_blocks_count; /* Free blocks count */__le32 s_free_inodes_count; /* Free inodes count */__le32 s_first_data_block; /* First Data Block */__le32 s_log_block_size; /* Block size */__le32 s_log_frag_size; /* Fragment size */__le32 s_blocks_per_group; /* # Blocks per group */__le32 s_frags_per_group; /* # Fragments per group */__le32 s_inodes_per_group; /* # Inodes per group */__le32 s_mtime; /* Mount time */__le32 s_wtime; /* Write time */__le16 s_mnt_count; /* Mount count */__le16 s_max_mnt_count; /* Maximal mount count */__le16 s_magic; /* Magic signature */__le16 s_state; /* File system state */__le16 s_errors; /* Behaviour when detecting errors */__le16 s_minor_rev_level; /* minor revision level */__le32 s_lastcheck; /* time of last check */__le32 s_checkinterval; /* max. time between checks */__le32 s_creator_os; /* OS */__le32 s_rev_level; /* Revision level */__le16 s_def_resuid; /* Default uid for reserved blocks */__le16 s_def_resgid; /* Default gid for reserved blocks *//*
* These fields are for EXT2_DYNAMIC_REV superblocks only.
*
* Note: the difference between the compatible feature set and
* the incompatible feature set is that if there is a bit set
* in the incompatible feature set that the kernel doesn't
* know about, it should refuse to mount the filesystem.
*
* e2fsck's requirements are more strict; if it doesn't know
* about a feature in either the compatible or incompatible
* feature set, it must abort and not try to meddle with
* things it doesn't understand...
*/__le32 s_first_ino; /* First non-reserved inode */__le16 s_inode_size; /* size of inode structure */__le16 s_block_group_nr; /* block group # of this superblock */__le32 s_feature_compat; /* compatible feature set */__le32 s_feature_incompat; /* incompatible feature set */__le32 s_feature_ro_compat; /* readonly-compatible feature set */__u8 s_uuid[16]; /* 128-bit uuid for volume */char s_volume_name[16]; /* volume name */char s_last_mounted[64]; /* directory where last mounted */__le32 s_algorithm_usage_bitmap; /* For compression *//** Performance hints. Directory preallocation should only* happen if the EXT2_COMPAT_PREALLOC flag is on.*/__u8 s_prealloc_blocks; /* Nr of blocks to try to preallocate*/__u8 s_prealloc_dir_blocks; /* Nr to preallocate for dirs */__u16 s_padding1;/** Journaling support valid if EXT3_FEATURE_COMPAT_HAS_JOURNAL set.*/__u8 s_journal_uuid[16]; /* uuid of journal superblock */__u32 s_journal_inum; /* inode number of journal file */__u32 s_journal_dev; /* device number of journal file */__u32 s_last_orphan; /* start of list of inodes to delete */__u32 s_hash_seed[4]; /* HTREE hash seed */__u8 s_def_hash_version; /* Default hash version to use */__u8 s_reserved_char_pad;__u16 s_reserved_word_pad;__le32 s_default_mount_opts;__le32 s_first_meta_bg; /* First metablock block group */__u32 s_reserved[190]; /* Padding to the end of the block */
};
3.3.2GDT(Group Descriptor Table)
// 磁盘级blockgroup的数据结构
/*
* Structure of a blocks group descriptor
*/
struct ext2_group_desc
{__le32 bg_block_bitmap; /* Blocks bitmap block */__le32 bg_inode_bitmap; /* Inodes bitmap */__le32 bg_inode_table; /* Inodes table block*/__le16 bg_free_blocks_count; /* Free blocks count */__le16 bg_free_inodes_count; /* Free inodes count */__le16 bg_used_dirs_count; /* Directories count */__le16 bg_pad;__le32 bg_reserved[3];
};
3.3.3块位图(Block Bitmap)
- 作用:标记数据块(Data Block)的使用状态。
- 原理:
- 每个比特(bit)对应一个数据块:
1
:块已被占用(存储了文件数据)。0
:块空闲可用。
- 例如:块位图
11100010
表示前3个块已用,第4-6个块空闲,第7个块已用,第8个块空闲。
- 每个比特(bit)对应一个数据块:
- 示例:
- 若文件系统有 1024 个块,块位图需占用
1024/8 = 128 字节
(1字节=8比特)。
- 若文件系统有 1024 个块,块位图需占用
3.3.4inode位图(Inode Bitmap)
- 作用:标记Inode 的使用状态。
- 原理:
- 每个比特对应一个 Inode:
1
:Inode 已被占用(关联了文件/目录)。0
:Inode 空闲。
- 例如:Inode 位图
10100000
表示第1、3个 Inode 已用,其余空闲。
- 每个比特对应一个 Inode:
- 示例:
- 若块组包含 8192 个 Inode,Inode 位图需占用
8192/8 = 1024 字节
。
- 若块组包含 8192 个 Inode,Inode 位图需占用
特性 | 块位图(Block Bitmap) | Inode 位图(Inode Bitmap) |
---|---|---|
管理对象 | 数据块(Data Blocks) | Inode |
标记内容 | 数据块是否被文件占用 | Inode 是否关联文件/目录 |
大小计算 | 总块数 ÷ 8(字节) | 总Inode数 ÷ 8(字节) |
分配策略 | 优先分配连续空闲块 | 分配第一个空闲 Inode |
3.3.5i节点表(Inode Table)
- 唯一标识文件:每个区对应一个唯一的 Inode 编号(如
Inode 1053
)。 - 存储元数据:包括权限、所有者、大小、时间戳等。
- 数据块寻址:通过指针(直接/间接)定位文件内容所在的磁盘块。
- 当前分组所有Inode属性的集合
- inode编号以分区为单位,整体划分,不可跨分区
属性 | 说明 |
---|---|
物理位置 | 位于文件系统的 块组(Block Group) 内,紧邻 Inode Bitmap。 |
存储单元 | 多个 Inode 连续存储,占用一个或多个磁盘块(Block)。 |
大小固定 | EXT2/3 中每个 Inode 固定为 128字节,EXT4 可扩展(如 256字节)。 |
示例计算:
若磁盘块大小为 4KB,一个块可存储 4096/128 = 32
个 Inode。
3.3.6Data Block
- 对于普通⽂件,⽂件的数据存储在数据块中。
- 对于⽬录,该⽬录下的所有⽂件名和⽬录名存储在所在⽬录的数据块中,除了⽂件名外,ls -l命令看到的其它信息保存在该⽂件的inode中。
- Block 号按照分区划分,不可跨分区
属性 | 说明 |
---|---|
作用 | 存储文件内容或目录条目(文件名 + Inode编号映射)。 |
大小 | 通常为 1KB、2KB、4KB(EXT4默认4KB),格式化时确定,不可动态调整。 |
分配单位 | 文件系统以块为单位分配空间,即使文件只有1字节也占用整个块。 |
寻址方式 | 通过Inode的直接/间接指针定位数据块。 |
Data Block 太大可以跨组保存
3.4inode和datablock映射
索引级别 | 管理能力(假设块大小=4KB,指针4字节) | 图中对应部分 |
---|---|---|
直接块 | 12×4KB = 48KB | 图中左侧"12个直接块"区域 |
一级间接 | 1024指针×4KB = 4MB | "一级间接块索引表指针"指向的表格 |
二级间接 | 1024×1024×4KB = 4GB | 二级索引表的多层结构 |
三级间接 | 1024³×4KB = 4TB | 图中最右侧的三级指针链 |
知道inode号的情况下,在指定分区,请解释:对⽂件进⾏增、删、查、改是在做什么?
- 分区之后的格式化操作,就是对分区进⾏分组,在每个分组中写⼊SB、GDT、Block Bitmap、Inode Bitmap等管理信息,这些管理信息统称: ⽂件系统
- 只要知道⽂件的inode号,就能在指定分区中确定是哪⼀个分组,进⽽在哪⼀个分组确定 是哪⼀个inode
- 拿到inode⽂件属性和内容就全部都有了
通过touch⼀个新⽂件来看看如何⼯作。
[root@localhost linux]# touch abc
[root@localhost linux]# ls -i abc
263466 abc
为了说明问题,我们将上图简化:
1.存储属性内核先找到⼀个空闲的i节点(这⾥是263466)。内核把⽂件信息记录到其中。2.存储数据该⽂件需要存储在三个磁盘块,内核找到了三个空闲块:300,500,800。将内核缓冲区的第⼀块数据复制到300,下⼀块复制到500,以此类推。3.记录分配情况⽂件内容按顺序300,500,800存放。内核在inode上的磁盘分布区记录了上述块列表。4.添加⽂件名到⽬录
新的⽂件名abc。linux如何在当前的⽬录中记录这个⽂件?内核将⼊⼝(263466,abc)添加到⽬录⽂件。⽂件名和inode之间的对应关系将⽂件名和⽂件的内容及属性连接起来。abc → 263466 → 块300/500/800
操作步骤 | 图片中的标注证据 |
---|---|
1. 分配Inode | i节点表 中的263466 条目 |
2. 分配数据块 | 数据区 的块300, 500, 800 |
3. 记录块列表 | 文件所使用的数据块列表:300,500,800 |
4. 添加目录项 | 增加到目录的入口:(263466, abc) |
3.5⽬录与⽂件名
local@bite:~/code/test/test$ pwd
/home/local/code/test/test
local@bite:~/code/test/test$ ls -li
total 24
1596260 -rw-rw-r-- 1 local local 814 Oct 28 20:32 test.c
⽐如:要访问test.c, 就必须打开test(当前⼯作⽬录),然后才能获取test.c对应的inode进⽽对⽂
件进⾏访问。
3.6路径解析
/home/local/code/test/test/test.c
都要从根⽬录开始,依次打开每⼀个⽬录,根据⽬录名,依次访问每个⽬录下指定的⽬录,直到访问到test.c。这个过程叫做Linux路径解析。
所以,我们知道了:访问⽂件必须要有⽬录+⽂件名=路径的原因根⽬录固定⽂件名,inode号,⽆需查找,系统开机之后就必须知道
3.7路径缓存
Linux中,在内核中维护树状路径结构的内核结构体叫做: struct dentry
struct dentry {atomic_t d_count;unsigned int d_flags; /* protected by d_lock */spinlock_t d_lock; /* per dentry lock */struct inode* d_inode; /* Where the name belongs to - NULL is* negative *//** The next three fields are touched by __d_lookup. Place them here* so they all fit in a cache line.*/struct hlist_node d_hash; /* lookup hash list */struct dentry* d_parent; /* parent directory */struct qstr d_name;struct list_head d_lru; /* LRU list *//** d_child and d_rcu can share memory*/union {struct list_head d_child; /* child of parent list */struct rcu_head d_rcu;} d_u;struct list_head d_subdirs; /* our children */struct list_head d_alias; /* inode alias list */unsigned long d_time; /* used by d_revalidate */struct dentry_operations* d_op;struct super_block* d_sb; /* The root of the dentry tree */void* d_fsdata; /* fs-specific data */
#ifdef CONFIG_PROFILINGstruct dcookie_struct* d_cookie; /* cookie, if any */
#endifint d_mounted;unsigned char d_iname[DNAME_INLINE_LEN_MIN]; /* small names */
};
dentry找到了,inode就找到了
操作 | 无缓存 | 有缓存 |
---|---|---|
首次访问 /path/abc | 需读取图中所有目录块和Inode表。 | 仅第一次需访问磁盘。 |
重复访问 | 每次重复解析路径。 | 直接从缓存返回Inode,零磁盘I/O。 |
删除/重命名文件 | 需同步更新缓存和图中磁盘结构。 | 缓存失效,触发重新解析。 |
3.8挂载分区
我们已经能够根据inode号在指定分区找⽂件了,也已经能根据⽬录⽂件内容,找指定的inode了,在指定的分区内,我们可以为所欲为了。可是:
问题:inode不是不能跨分区吗?Linux不是可以有多个分区吗?我怎么知道我在哪⼀个分区???
3.8.1⼀个实验
$ dd if=/dev/zero of=./disk.img bs=1M count=5 #制作⼀个⼤的磁盘块,就当做⼀个分区#创建5MB的空白镜像#通过dd命令创建的disk.img就是典型的磁盘镜像文件
$ mkfs.ext4 disk.img # 格式化写⼊⽂件系统
$ mkdir /mnt/mydisk # 建⽴空⽬录
$ df -h # 查看可以使⽤的分区
Filesystem Size Used Avail Use% Mounted on
udev 956M 0 956M 0% /dev
tmpfs 198M 724K 197M 1% /run
/dev/vda1 50G 20G 28G 42% /
tmpfs 986M 0 986M 0% /dev/shm
tmpfs 5.0M 0 5.0M 0% /run/lock
tmpfs 986M 0 986M 0% /sys/fs/cgroup
tmpfs 198M 0 198M 0% /run/user/0
tmpfs 198M 0 198M 0% /run/user/1002
$ sudo mount -t ext4 ./disk.img /mnt/mydisk/ # 将分区挂载到指定的⽬录$ df -h
Filesystem Size Used Avail Use% Mounted on
udev 956M 0 956M 0% /dev
tmpfs 198M 724K 197M 1% /run
/dev/vda1 50G 20G 28G 42% /
tmpfs 986M 0 986M 0% /dev/shm
tmpfs 5.0M 0 5.0M 0% /run/lock
tmpfs 986M 0 986M 0% /sys/fs/cgroup
tmpfs 198M 0 198M 0% /run/user/0
tmpfs 198M 0 198M 0% /run/user/1002
/dev/loop0 4.9M 24K 4.5M 1% /mnt/mydisk$ sudo umount /mnt/mydisk # 卸载分区
local@bite:/mnt$ df -h
Filesystem Size Used Avail Use% Mounted on
udev 956M 0 956M 0% /dev
tmpfs 198M 724K 197M 1% /run
/dev/vda1 50G 20G 28G 42% /
tmpfs 986M 0 986M 0% /dev/shm
tmpfs 5.0M 0 5.0M 0% /run/lock
tmpfs 986M 0 986M 0% /sys/fs/cgroup
tmpfs 198M 0 198M 0% /run/user/0
tmpfs 198M 0 198M 0% /run/user/1002
注意:
/dev/loop0 在Linux系统中代表第⼀个循环设备(loop device)。循环设备,也被称为回环设备或者loopback设备,是⼀种伪设备(pseudo-device),它允许将⽂件作为块设备(block device)来使⽤。这种机制使得可以将⽂件(⽐如ISO镜像⽂件)挂载(mount)为⽂件系统,就像它们是物理硬盘分区或者外部存储设备⼀样
最多可以同时挂载8个不同的磁盘镜像文件(每个镜像需要独占一个loop设备)
local@bite:/mnt$ ls /dev/loop* -l
brw-rw---- 1 root disk 7, 0 Oct 17 18:24 /dev/loop0
brw-rw---- 1 root disk 7, 1 Jul 17 10:26 /dev/loop1
brw-rw---- 1 root disk 7, 2 Jul 17 10:26 /dev/loop2
brw-rw---- 1 root disk 7, 3 Jul 17 10:26 /dev/loop3
brw-rw---- 1 root disk 7, 4 Jul 17 10:26 /dev/loop4
brw-rw---- 1 root disk 7, 5 Jul 17 10:26 /dev/loop5
brw-rw---- 1 root disk 7, 6 Jul 17 10:26 /dev/loop6
brw-rw---- 1 root disk 7, 7 Jul 17 10:26 /dev/loop7
crw-rw---- 1 root disk 10, 237 Jul 17 10:26 /dev/loop-control
df
命令(最直接)快速判断当前所在分区
.
表示当前目录,输出显示其所在设备(如/dev/vda1
)和挂载点(/home
)。
$ df -h .
Filesystem Size Used Avail Use% Mounted on
/dev/vda1 50G 20G 28G 42% /home
3.8.2一个结论
4.软硬链接
4.1硬链接
基本概念
- 硬链接 是文件系统中指向同一个 inode 的多个文件名,即多个路径指向同一份数据。
- 所有硬链接地位平等,没有“原始文件”和“链接文件”之分。
- 删除任意一个硬链接,只要还有其他链接存在,文件数据就不会被释放。
特点
1.共享 inode
- 所有硬链接指向同一个 inode,因此:
- 修改任一硬链接的内容,其他硬链接也会同步变化。
- 它们的文件属性(权限、所有者、时间戳等)完全相同。
2.不跨文件系统
- 硬链接必须在同一个文件系统内创建(因为 inode 是文件系统局部的)。
3.不能链接目录(超级用户除外)
- 普通用户无法用
ln
创建目录的硬链接,防止形成循环引用(但内核允许.
和..
这样的特殊硬链接)。
4.删除不影响数据
- 只有当所有硬链接都被删除,且没有进程占用文件时,数据才会真正释放。
创建硬链接
ln 源文件 硬链接名
ln file.txt hardlink_to_file.txt
此时 file.txt
和 hardlink_to_file.txt
指向同一个 inode,修改其中一个会影响另一个。
查看硬链接
ls -i
查看 inode 号(相同 inode 表示是硬链接):
ls -i file.txt hardlink_to_file.txt
//输出示例:
123456 file.txt
123456 hardlink_to_file.txt # inode 相同
263563 - rw - r--r--. 2 root root 0 9⽉ 15 17:45 abc
263563 - rw - r--r--. 2 root root 0 9⽉ 15 17:45 abc-hard//2是多个新的文件名指向目标文件,硬连接数//增加inode引用计数的数字
创建目录后发现是2,是因为目录里.也是硬链接
目录里..是3是因为上级目录和上级目录里的.和当前目录里的..是同一inode
4.2软链接
基本概念
软链接(Symbolic Link,又称符号链接)是 Linux/Unix 系统中的一种特殊文件类型,它存储的是另一个文件或目录的路径,类似于 Windows 的“快捷方式”。
创建软链接
ln -s 目标文件或目录 软链接名称
ln -s /var/log/syslog my_log_link # 创建指向系统日志的软链接
此时 my_log_link
是一个独立文件,内容为路径 /var/log/syslog
。
识别软链接
ls -l
显示软链接及其指向的目标:
ls -l my_log_link
//输出示例:
lrwxrwxrwx 1 user group 13 Jan 1 12:00 my_log_link -> /var/log/syslog
//首字母 l 表示软链接。
//-> 后是目标路径。
gcc myapp.c -o /.../myapp # 编译并输出到目标路径
ln -s /.../myapp exe # 创建软链接 exe
现在目录下有一个名为 exe
的软链接,指向 /.../myapp
。
直接运行 exe
./exe
- Shell 会先解析
./exe
的路径:
./
表示当前目录,所以 Shell 查找当前目录下的exe
。- 发现
exe
是一个软链接,指向/.../myapp
。- Shell 最终执行
/.../myapp
。
4.3软硬连接对⽐
4.4软硬连接的⽤途: