当我尝试打印设备文件时,输出显示十六进制格式的二进制数据。但是执行后ls -l /dev/sda
我得到:
brw-rw---- 1 root disk 8, 0 Jan 29 12:29 /dev/sda
我不明白文件的实际大小是多少?这些数字代表什么意思?
答案1
总结:这就是开发人员实现的ls.c
。根据文件类型,长选项的输出字符串-l
将以不同的方式构建。GNU 文档未提及格式差异(请参阅有关 OpenBSD 手册页的附注)。
设备文件和 ls 源代码
/dev/sda
是块设备(本部分后面会解释)。它与常规文件不同。ls.c
根据正在处理的文件类型构建长输出字符串。如下所示,对于块设备,输出字符串中不会附加任何有关大小的信息!
ls.c
有以下几行代码:
3757 static void
3758 print_long_format (const struct fileinfo *f)
3759 {
( partially omited )
3868 if (f->stat_ok
3869 && (S_ISCHR (f->stat.st_mode) || S_ISBLK (f->stat.st_mode)))
3870 {
3871 char majorbuf[INT_BUFSIZE_BOUND (uintmax_t)];
3872 char minorbuf[INT_BUFSIZE_BOUND (uintmax_t)];
3873 int blanks_width = (file_size_width
3874 - (major_device_number_width + 2
3875 + minor_device_number_width));
3876 sprintf (p, "%*s, %*s ",
3877 major_device_number_width + MAX (0, blanks_width),
3878 umaxtostr (major (f->stat.st_rdev), majorbuf),
3879 minor_device_number_width,
3880 umaxtostr (minor (f->stat.st_rdev), minorbuf));
3881 p += file_size_width + 1;
3882 }
3883 else
3884 {
3885 char hbuf[LONGEST_HUMAN_READABLE + 1];
3886 char const *size =
3887 (! f->stat_ok
3888 ? "?"
3889 : human_readable (unsigned_file_size (f->stat.st_size),
3890 hbuf, file_human_output_opts, 1,
3891 file_output_block_size));
3892 int pad;
3893 for (pad = file_size_width - mbswidth (size, 0); 0 < pad; pad--)
3894 *p++ = ' ';
3895 while ((*p++ = *size++))
3896 continue;
3897 p[-1] = ' ';
3898 }
请注意,如果文件类型为S_ISCHR
(字符设备,连续数据流)或 S_ISBLK
(块设备,随机访问),则主设备号和次设备号将打印到字符数组中p
(本质上是一个字符串)。这是附加到输出字符串的唯一数据p
。然而,当我们else
说到ls
会明白我们正在处理文件除了块设备或字符设备之外p
. 对于那些文件,它将存储在大小数组中的数据分配给该大小数组的下一段(这是while ((*p++ = *size++))
一部分)。
核心思想是 ls 知道它正在查看的文件类型,并据此建立输出
设备文件到底是什么?
本质上它们是引用。它们是应用程序处理实际物理设备及其驱动程序的方式。例如,/dev/sda
和/dev/sr0
(即 CD/DVD 驱动器)。有些设备只是抽象。例如,,/dev/zero
和/dev/null
不是/dev/random
物理设备。它们是与内核进程交互的方式。
因为它们是引用,所以它们没有文件大小是有道理的。可以知道这些文件在/dev
目录中占用的大小,但它们与它们所代表的实际设备并不对应!
因此,开发人员以这种方式实现代码的原因也是可以理解的ls.c
。99.99% 的情况下,引用的文件大小都是不需要的。
但是块设备(我们通常指的是硬盘和 USB 驱动器)是物理设备,具有真实的物理大小,那么我们如何找出这一点呢?
找出实际块设备的大小
下面的方法说明了如何找出 /dev/ 中块设备引用的硬盘 /ssd /USB 驱动器的大小
lsblk
或者lsblk /dev/sda
sudo blockdev --getsize64 /dev/sda
sudo fdisk -l /dev/sda
或sudo fdisk -l
适用于所有开发者sudo parted /dev/sda print
或sudo parted -l
适用于所有开发者awk '{print $1*512}' /sys/class/block/sda/size
awk '{$3=$3*1024;print}' /proc/partitions
或awk '$4 == "sda1" {$3=$3*1024;print}' /proc/partitions
特定分区。
补充说明
/proc/devices
包含与块设备对应的所有主设备编号的列表du
和stat
命令find
可以显示这些引用的大小,但对于日常生活来说不是必需的(如果有的话)- 块设备的表示形式有所不同;一些文件实现了块的表示
512
(例如在/sys
文件系统下),而其他文件 -1024。这是 Unix/Linux 世界中的惯例,因为这就是硬盘上实际物理块的分配方式。 - 与 GNU 不同
ls
文档不同,OpenBSD 手册页明确指出:“如果文件是字符特殊文件或块特殊文件,文件的主设备号和次设备号显示在大小字段中“(我加了强调)
参考
答案2
我找不到任何文档来解释为什么ls
显示它们而不是简单的0
类似du
或stat
的简单内容,但正如 Byte Commander 所说,它们是主设备号和次设备号该特殊文件。从源头来看:
if (f->stat_ok
&& (S_ISCHR (f->stat.st_mode) || S_ISBLK (f->stat.st_mode)))
{
char majorbuf[INT_BUFSIZE_BOUND (uintmax_t)];
char minorbuf[INT_BUFSIZE_BOUND (uintmax_t)];
int blanks_width = (file_size_width
- (major_device_number_width + 2
+ minor_device_number_width));
sprintf (p, "%*s, %*s ",
major_device_number_width + MAX (0, blanks_width),
umaxtostr (major (f->stat.st_rdev), majorbuf),
minor_device_number_width,
umaxtostr (minor (f->stat.st_rdev), minorbuf));
p += file_size_width + 1;
}
此代码是这print_long_format()
,当输出格式很长(就是-l
)时使用,使用设备编号代替字符和块设备的大小。
要获取设备的实际尺寸,可以列出以下几种方法这篇 Unix 和 Linux 文章。
答案3
看来你错过了“一切皆文件”的概念。
在 UNIX 世界中,一切(数据、设备、套接字等)都映射到文件。这些文件有类型 - 就您的主目录而言,您(大多数情况下)会找到所谓的常规文件(文本、程序……)。
与这些常规文件相比,/dev 目录包含(顾名思义)设备文件。因此,您将找到以下类型的文件C性格,b锁定并页ipe 代表设备,例如 /dev/mem 是一个代表系统内存的文件,/dev/ttyACM0 可以是一个串行调制解调器。这些(设备)文件和负责的驱动程序之间的链接是使用 ls 所示的主编号和次编号创建的(如上所述)。
设备的大小是设备特定的属性,必须使用设备特定的工具进行查询(如上文所示),因为没有唯一的方法来处理该属性(SSD 可能有固定大小 - 但串行端口可以提供无限的数据流,所以没有固定的大小,/dev/null 有无限的存储空间:))。
您可以在这里继续阅读:https://en.wikipedia.org/wiki/Everything_is_a_file