免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
楼主: 一梦如是
打印 上一主题 下一主题

如何更巧妙的利用shell的fd [复制链接]

论坛徽章:
0
11 [报告]
发表于 2007-01-07 18:47 |只看该作者
grep --version; sed --version; awk --version;

一般都是GNU的了...不过有例外

论坛徽章:
0
12 [报告]
发表于 2007-01-08 04:15 |只看该作者
1. 如果说就文件截断来讲split可以算上吧只不过用它来实现你要的功能分分合合也不合适
2. 都是一样的系统调用方法也就那几种不知道汇编程序实现是否能突破这个"兼顾效率和复杂的定位条件"

论坛徽章:
0
13 [报告]
发表于 2007-01-08 11:12 |只看该作者
split显然是调用write(2)写其他文件,不是调用truncate(2),效率上会差很多
除了巧用dd的操作数外,shell下似乎找不到其他调用truncate(2)的命令,或者是我孤陋寡闻没听说过~

其实想想,所谓复杂条件,不可能不读文件,只要读文件,效率就一定会受到文件大小或查找位置的影响。用一些查找算法只能在一定程度上提高效率,的确没必要在这方面太过追究。

论坛徽章:
1
荣誉会员
日期:2011-11-23 16:44:17
14 [报告]
发表于 2007-01-08 19:43 |只看该作者
呵呵,有些日子不来了,一来就发现了有趣的东东。真好!
梦兄的确发现了一个有趣的现象,就是某些程序重定向后会在句柄中保持文件指针的正确位置,例如linux下的head。这样也就解决了在《perl在编辑巨大文件时的应用》一贴(链接在一楼)中r2007兄未实现的solution:用dd截断文件而不必专门计算一次截断的偏移量。于是对于该贴中的删除文件前10行的例子,我们可以这样做:
  1. { head -10 <&3; dd <&3 >&4;} 3<HUGEFILE 4<>HUGEFILE
复制代码

其中,4<>HUGEFILE的用法来自r2007兄的研究结果,这样dd在写文件时就会自动作截断处理,于是就不必第二次调用dd去截断文件了。
嗯,真的很棒!很简洁,效率也很高。正如梦兄所说的,速度比perl的解法要高一个量级。我想这是因为我们的perl程序要逐行进行文件进行处理的,dd则没有这个负担,所以运行快些。当然对于这个特定的例子,perl的解法还有可以优化的余地,我就不提了。
不过dd解法也有缺点,那就是适用范围相对的比较窄,而perl的程序就要灵活得多。呵呵,各有千秋吧。^_^

另外,linux下的head的这个特性是否在其它平台上也有呢?我猜想不单与head程序本身有关,恐怕和具体的shell实现也有一定的关系。我没有环境,请有条件的朋友帮忙试试,谢了!woodie在linux下试过,gsed、gawk/mawk都不行,有趣的是perl就可以,真是巧了!这样也行:
  1. { perl -ne 'exit if ($.==10)' <&3; dd <&3 >&4;} 3<HUGEFILE 4<>HUGEFILE
复制代码


说明:以上结果是在linux下的bash环境下得出的。你的环境下能工作吗?要自己试过才知道。^_^

嗯,很有收获,谢谢大家!
—————————————————————
修正一下错误。^_^

—————————————————————
继续改错。
经过讨论,上面的代码仍然没有截断文件,误导大家了,非常抱歉!
总结一下woodie现在的认识:
1. fd中会保留文件指针的位置,但不同的程序的情况不太一样,head/perl的指针位置是可以信赖的,而sed/awk是块的边界或者文件尾。
2. dd正确截断文件的方法:a)设置of参数;b)设置seek参数。二者缺一不可。还有:c)不要用conv=notrunc。[feel free to fix me]
3. dd拷贝数据块的性能比行模式下的程序要快一个量级。
4. 相对于dd的截断方法,perl的方法简单明了:
perl -e 'truncate "path/to/your/file", $offset"

最后谢谢大家参加讨论,尤其是r2007,指出我的错误。谢谢你们!

[ 本帖最后由 woodie 于 2007-1-9 22:54 编辑 ]

论坛徽章:
0
15 [报告]
发表于 2007-01-08 20:07 |只看该作者
就是某些程序重定向后会在句柄中保持文件指针的位置

挑个刺~
我认为这句话不够准确,应该是任何程序重定向都会在fd中保存文件指针的位置。
前面有兄弟说的HP-UX的head,以及sed,awk,cat等,并非没保存文件指针,而是遍历了整个文件,将文件指针定位到了文件尾,所以它们使用过的fd,就无法再从中获得内容了。
可以用下面这个例子证明
  1. seq 1000000 >file
  2. exec 3<file
  3. cat <&3

  4. cat <&3
复制代码

第一个cat命令执行时,用ctrl+c打断~~,这样第二个cat就会接着输出了~

论坛徽章:
1
荣誉会员
日期:2011-11-23 16:44:17
16 [报告]
发表于 2007-01-09 09:10 |只看该作者
我想这里的情况并不是遍历文件——对于我们的来说,那样做是没有意义的。不是吗?
如下面的sed和awk都在读入第10行后退出,绝不是要遍历整个文件。
{ sed '10q' <&3;cat <&3;} 3<tmp
{ awk 'NR==10{exit}' <&3;cat <&3;} 3<tmp
那么,这样说是不是准确些:它们是在退出前将文件指针移动到了文件尾部,也可以说它们事后打扫了“犯罪现场”,而没有保留我们希望它们保留的特定时刻的文件指针位置。
至于梦兄楼上举的例子,我想正是因为control-C强行中断了cat的执行,打乱了cat正常的处理过程的缘故。

论坛徽章:
0
17 [报告]
发表于 2007-01-09 09:41 |只看该作者
原帖由 woodie 于 2007-1-8 19:43 发表
呵呵,有些日子不来了,一来就发现了有趣的东东。真好!
梦兄的确发现了一个有趣的现象,就是某些程序重定向后会在句柄中保持文件指针的位置,例如linux下的head。这样也就解决了在《perl在编辑巨大文件时的应用 ...

不错,学习了

论坛徽章:
0
18 [报告]
发表于 2007-01-09 09:52 |只看该作者
觉得“它们是在退出前将文件指针移动到了文件尾部”比较合常理,如果 head -10 会历遍文件,我只有说“欧麦嘎”了!
ps: woodie,在 HP-UX下面测试通过。

论坛徽章:
0
19 [报告]
发表于 2007-01-09 10:12 |只看该作者
虽然分开文件读和写指针,没有使用临时文件,从而节省了1/2磁盘空间和1/2磁盘读写量,相对是很大改进。
我的想法是:根本不进行文件块拷贝操作,只是修改文件开始指针,并且重新设置大小。或许有些贪婪了,哈

论坛徽章:
0
20 [报告]
发表于 2007-01-09 10:44 |只看该作者
原帖由 woodie 于 2007-1-9 09:10 发表
我想这里的情况并不是遍历文件——对于我们的来说,那样做是没有意义的。不是吗?
如下面的sed和awk都在读入第10行后退出,绝不是要遍历整个文件。
{ sed '10q' <&3;cat <&3;} 3<tmp
{ awk ' ...

的确,我关于遍历的说法欠准确。

而且,我发现了我前面的一个观点是错误的:“sed和awk一定将文件指针置为文件尾”,特此声明。
用下面的方法测试
  1. seq 10000 >6
  2. exec 3<6
  3. strace awk 'NR==10{exit}' <&3
  4. cat <&3
  5. exec 3>&-
复制代码

关于标准输入的strace信息只有下面几句
  1. fstat64(0, {st_mode=S_IFREG|0644, st_size=48894, ...}) = 0
  2. ioctl(0, SNDCTL_TMR_TIMEBASE or TCGETS, 0xbffc0368) = -1 ENOTTY (Inappropriate ioctl for device)
  3. fstat64(0, {st_mode=S_IFREG|0644, st_size=48894, ...}) = 0
  4. read(0, "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n11\n12\n13\n14"..., 4096) = 4096
  5. exit_group(0)                           = ?
复制代码

它的文件指针在fd所指文件的4096字节!sed '10q'的信息及结果也是如此。
我上次使用的测试文件是个大小为21字节的文件,一次读4096字节碰巧已经seek到了文件尾。而当时我又没用strace仔细研究,因此错误得得出了上面那个观点。

又发现一个有趣的命令——tac
  1. exec 3<6
  2. cat <&3 >/dev/null
  3. tac <&3
  4. cat <&3
复制代码

它是迄今为止我发现的唯一一个可以逆转文件指针的shell命令,虽然其文件指针固定在了8192字节(小于8192字节的仍然定位于文件尾)

可惜这两个发现似乎没有什么实用性,姑且当兴趣研究吧~
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP