使用cat和tee预先添加到文件时的奇怪行为

时间:2014-08-15 22:12:46

标签: linux bash shell unix

prepend to a file one liner shell?解决问题的一个方法是:

cat header main | tee main > /dev/null

正如一些评论所指出的那样,这对大文件不起作用。

这是一个有效的例子:

$ echo '1' > h
$ echo '2' > t
$ cat h t | tee t > /dev/null
$ cat t
1
2

它破裂的地方:

$ head -1000 /dev/urandom > h
$ head -1000 /dev/urandom > t
$ cat h t | tee t > /dev/null
^C

命令挂起,杀死后我们留下:

$ wc -l t
7470174 t

导致命令卡住并无限添加行的上述行为是什么原因造成的? 1行文件场景有什么不同?

2 个答案:

答案 0 :(得分:4)

行为完全不确定。执行cat header main | tee main > /dev/null时,会发生以下情况:

1)猫打开标题 2)猫打开主要 3)cat读取标题并将其内容写入stdout 4)cat读取main并将其内容写入stdout 5)tee打开主要用于书写,截断它 6)tee读取stdin并将读取的数据写入main

上面的排序是一种可能的排序,但这些事件可能以许多不同的顺序发生。 5必须在6之前,2必须在4之前,1必须在3之前,但是排序完全有可能是5,1,3,2,4,6。在任何情况下,如果文件很大,则步骤5很可能在步骤4完成之前发生,这将导致部分数据被丢弃。完全有可能首先发生第5步,在这种情况下,以前主要的所有数据都将丢失。

您看到的特殊情况很可能是因为写入时阻塞了cat并在读完输入之前进入睡眠状态。 tee然后写入更多数据t并尝试从管道读取,然后进入睡眠状态,直到cat写入更多数据。 cat写入缓冲区,tee将其放入t,循环重复。

答案 1 :(得分:4)

  

cat header main | tee main>的/ dev / null的

这是一个可怕而可怕的想法。你永远不应该有一个读取和写入文件的管道。

您可以先将结果放入临时文件中,然后将其移动到位:

cat header main >main.new && mv main{.new,}

或者为了最大限度地缩短文件的两个副本存在的时间,并且同时在目录中永远不会同时显示这两个副本,您可以在打开原件进行读取并写入新文件后将其删除直接进入以前的位置。然而,这确实意味着存在一个短暂的差距,在此期间文件根本不存在。

exec 3<main && rm main && cat header - <&3 >main && exec 3<&-