Linux 使用perl读取系统文件而不在open上发出额外的seek系统调用
我正在尝试使用perl解析来自Linux 使用perl读取系统文件而不在open上发出额外的seek系统调用,linux,perl,file-io,seek,procfs,Linux,Perl,File Io,Seek,Procfs,我正在尝试使用perl解析来自/proc和/syslinux伪文件系统(和)的一些伪文件。这类文件不同于常规文件-它们由自定义文件操作处理程序实现。它们中的大多数对stat的大小为零,一些无法打开以供读取,另一些无法写入。有时它们的实现不正确(这是错误的,但它已经在内核中),我仍然希望直接从perl读取它们,而不启动一些帮助工具 有一个使用perl读取/proc/loadavg的快速示例,该文件已正确实现: perl -e 'open F,"</proc/loadavg"; $_=<
/proc
和/sys
linux伪文件系统(和)的一些伪文件。这类文件不同于常规文件-它们由自定义文件操作处理程序实现。它们中的大多数对stat的大小为零,一些无法打开以供读取,另一些无法写入。有时它们的实现不正确(这是错误的,但它已经在内核中),我仍然希望直接从perl读取它们,而不启动一些帮助工具
有一个使用perl读取/proc/loadavg
的快速示例,该文件已正确实现:
perl -e 'open F,"</proc/loadavg"; $_=<F>; print '
有lseek
系统调用由open
perl函数使用
使用cat/proc/loadavg
策略时,没有额外的seek
类型的系统调用:
$ strace cat /proc/loadavg 2>&1 | egrep -A2 ^open.*loadavg
open("/proc/loadavg", O_RDONLY) = 3
fstat(3, {st_mode=S_IFREG|0444, st_size=0, ...}) = 0
fadvise64(3, 0, 0, POSIX_FADV_SEQUENTIAL) = 0
我要读取(或写入)的特殊文件错误地执行了seek
文件操作,并且在seek
之后不会向read
(或write
)系统调用提供任何有用的数据
有没有办法在不调用额外的lseek
的情况下打开文件以读取perl5(无外部模块)?(并且不使用系统(“cat
)
有没有办法在不调用额外的lseek
的情况下打开文件以在perl5中写入
有sysopen,但它也有额外的lseek:
perl-e'使用Fcntl;sysopen(F,“/proc/loadavg”,仅限ordu);sysread(F,$\uu2048);打印'
正如您所注意到的,Perl的内置打开
屏蔽了相当多的魔力。如果这种魔力妨碍了你,那么会有sysopen
和POSIX::open()
提供降低的魔力POSIX::open()
非常不神奇,它返回的是文件描述符而不是Perl文件句柄,您必须使用POSIX::read()
而不是普通的Perl操作符从中获取数据。如果这还不适合你的情况,你可能就不走运了
自从perl 5第一次发布以来,
POSIX
模块是核心perl发行版的一部分,因此如果您没有它,您的perl安装将受到严重影响。如果您想真正做到低级别,甚至避免使用POSIX::open()
中的mmap
(同时避免加载庞大的POSIX
模块),自己执行syscall()
s。可能希望需要syscall.ph
来获取SYS\u open
和SYS\u read
的值(如果您不知道)(对我来说,我知道read
、write
和open
分别是0
、1
、2
,这对于下面的syscall
函数很重要)
以下代码:
strace perl -mPOSIX -e'$fd=POSIX::open("/proc/loadavg");POSIX::read($fd,
$_, 9999);' 2>&1 | egrep -A2 '^open.*loadavg'
给出如下内容(对于我来说,open()
是openat()
)
试着这样做:
strace perl -MFcntl -E'$p="/proc/loadavg"; $fd=syscall 2, $p, O_RDONLY; $bf =
"\0"x50; syscall 0, $fd, $bf, 50' 2>&1 | egrep -A1 '^open.*loadavg'
并获得:
open("/proc/loadavg", O_RDONLY) = 3
read(3, "0.45 0.18 0.20 2/241 12349\n", 50) = 27
编辑:关于 读取的末尾有
\0
特殊字符。如何从POSIX::read解析多行,现在没有while()
请注意,当您“while()
”时,您实际上只是一次调用read()
一个字节,并检查'\n'
字符——或者设置为$/
(输入记录分隔符)的任何内容(您可以通过strace
确认)
因此,检查$/
的简单循环就足够了。(请注意,read()
成功返回读取的字节数(0表示EOF)。下面是单个“readline
”的粗略示例:
请注意,如果您打算实现任何类型的可移植性,
syscall
-ing可能是最糟糕的选择之一,但这是专用性的代价。(POSIX::open/read/close()
)在这个意义上也没有多大改善。要保持可移植性,最好使用@ikegami的注释(在我试用过的linux设备上,open F,“@ikegami,什么样的黑魔法(,如文档中所述,PerlIO层在中有文档记录。请查看perl-MPerlIO-E'open F,“@ikegame,还有fstat
带有my$SET,”>:unix“../driver\u命令;print$SET$command。”\n";close$SET
;我可以禁用它吗?我的脚本仍然无法与驱动程序通信;但是简单的回显相同的命令>../driver\u命令
可以工作,我在这里只看到额外的fstat。Calle,请添加一些文档链接。ikegami推荐Calle,谢谢,POSIX::open+read可以工作,没有任何额外的系统调用:perl-e'usePOSIX();$fd=POSIX::open(“/proc/loadavg”);$bytes=POSIX::read($fd,$buf,30);POSIX::close($fd);print$bytes.“read:“$buf;”结果为
27 read:0.16 0.09 0.02…”读取的末尾有“\0”特殊字符。如何从POSIX::read解析多行,现在没有while()
。“read、write和open是0,1,2”对于任何linux平台,它们总是0、1和2吗?不;直接使用系统调用不是最方便的。请尝试require syscall.ph
,以了解系统读取的内容,系统写入的内容,系统打开的
常量适合您。旁注:我没有关闭文件描述符的任何方法。您可以使用PO六::close()
,但您也可以使用syscall(SYS\u close,$fd)
,(对我来说这是syscall(3,$fd)
)。
strace perl -MFcntl -E'$p="/proc/loadavg"; $fd=syscall 2, $p, O_RDONLY; $bf =
"\0"x50; syscall 0, $fd, $bf, 50' 2>&1 | egrep -A1 '^open.*loadavg'
open("/proc/loadavg", O_RDONLY) = 3
read(3, "0.45 0.18 0.20 2/241 12349\n", 50) = 27
require 'syscall.ph';
require Fcntl;
my($path, $fd, $buf, $res);
$path = '/proc/meminfo';
$fd = syscall SYS_open(), $path, O_RDONLY;
$buf = ' ';
$res = '';
$res .= $buf while syscall SYS_read(), $fd, $buf, 1 and $buf ne $/;
syscall SYS_close(), $fd; # optional in this case