Linux 使用cat和tee预结束文件时的奇怪行为

Linux 使用cat和tee预结束文件时的奇怪行为,linux,bash,shell,unix,Linux,Bash,Shell,Unix,解决此问题的一个方法是: 正如一些评论所指出的,这不适用于大文件 下面是一个例子: $ 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 命令挂起,杀死它后,我们将得到

解决此问题的一个方法是:

正如一些评论所指出的,这不适用于大文件

下面是一个例子:

$ 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

是什么导致上述行为,其中命令被卡住并无限添加行?单行文件场景有什么不同?

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

1) cat opens header
2) cat opens main
3) cat reads header and writes its content to stdout
4) cat reads main and writes its content to stdout
5) tee opens main for writing, truncating it
6) tee reads stdin and writes the data read into main
上述顺序是一种可能的顺序,但这些事件可能以许多不同的顺序发生。5必须在6之前,2必须在4之前,1必须在3之前,但顺序完全可以是5,1,3,2,4,6。在任何情况下,如果文件很大,则步骤5很可能在步骤4完成之前发生,这将导致丢弃部分数据。完全有可能先执行步骤5,在这种情况下,以前在main中的所有数据都将丢失

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

cat割台总管|三通总管>/dev/null

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

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

cat header main >main.new && mv main{.new,}
或者,为了最大限度地减少文件的两个副本存在的时间,并且不会同时在目录中显示这两个副本,您可以在打开原始文件进行读写后将其删除,并将新文件直接写入其以前的位置。然而,这确实意味着有一个短暂的间隙,在此期间文件根本不存在

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