将一个文件的内容翻一番, 也就是说, 如果它原来的内容是"abc", 现在让它变成 "abcabc".
当然, 莽夫型的:
cp file tmp_file
cat tmp_file >> file
细心的莽夫还会记得
rm tmp_file
这当然能工作, 但, 效率不高, 而且, 在这样的情况下会失败:
你的剩余空间只有 10M, 你的 file 也是 10M, 这样当你 cp file tmp_file
之后, 你的硬盘就无旋马之地了.
一知半解型的:
cat file file > file
然后他瞪大双眼发现 file里的内容已经血本无归
不死心型的:
cat file >> file
你的硬盘有多大, 你就得等多久.
似乎聪明的方法:
cat <(cat file) >> file
结果跟前者一样
希望分组命令或子SHELL能带来点什么的:
{ cat file file ; } > file
( cat file file ) > file
关键是shell在何时执行 > file, 在执行命令之前! 所以file的内容都没了.
我知道还有一种人会玩弄 exec <&- 之类的东西, 也许这可行
优雅的办法是
dd if=file of=file bs=$(stat -c %s file)c count=1 seek=1
但在这之前, 我这样做过:
dd if=file of=file bs=1c count=$(stat -c %s file) seek=$(stat -c %s file)
真正要COPY的字节数都是 bs * count, 但两者性能是天壤之别, 因为后者的写单位是1字符. 而前者的写单位是文件的当前大小. 注意即使当前文件已经很大了, 指定一个很大的数字作为写的单位却不会引起什么性能上的损失, 这是因为过大的写单位会被以系统最优的写单位分而治之.
关于dd容易搞错的一点是 数字后面跟c表示字节, 跟b表示block, 而不是byte
关于dd更容易搞错的一点是, 指定输出文件的偏移是用seek, 而指定输入文件的则是skip
幕后:
shell会首先处理 > file, 目的是为要启动的命令准备好正确的文件描述符, 只有这一步处理好重定向, 被执行的程序才会继承到正确的文件描述符, 所以这一步要先行.
对命令行上的 <(sub command)
shell要为它自动产生一个文件名, 用set -x后执行可以看到这个自动产生的文件名, 这个文件名当然不用用户手工去清除. 该文件的内容自然是command的输出结果, 但, 启动主命令时需不需要sub command已经完成? 命令说明问题:
cat <( echo 123; ps u; sleep 1; )
其输出是
123
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
zhao 1082 0.0 1.2 4524 1572 pts/0 S 22:03 0:00 -bash
zhao 1154 0.0 0.3 3584 400 pts/0 S 23:36 0:00 cat /dev/fd/63
zhao 1155 0.0 0.4 2536 620 pts/0 R 23:36 0:00 ps u
显然, 在子命令完成之前, 主命令已经被启动, 这正是为什么
cat <( cat file ) >> file
会陷入无限等待的原因, shell以追加方式打开 file, 然后另起一个进程执行sub command, 也就是这里的cat file, 同时主程序也被启动, 这样:
1. 主程序的cat 不断地从 /dev/fd/63 中读取内容, 而
2. /dev/fd/63 的内容由子命令cat file得来
3. 子命令cat file不断读取file的内容, 却怎么也读不到它的尾部, EOF, 这是因为
4. 主程序启动之前已经以追加方式打开了file, 所以主程序的cat 的输出源源不断地把内容送到file中去
这本质上是一个间接无穷递归, 跟 while(1); 类似
阅读(1130) | 评论(0) | 转发(0) |