2011-10-28 29 views
16

当我试图理清一个文件并保存排序输出本身,这样为什么“sort file1> file1”不起作用?

sort file1 > file1; 

的文件1的内容得到完全消除,而当我试图做“三通”一样这样命令

sort file1 | tee file1; 

它工作正常 [ED:“正常工作”仅用于与幸运定时小文件,将造成路数或无益的进程调度丢失的数据],即,它覆盖排序file1的输出本身并在标准outp上显示UT。

有人可以解释为什么第一个案件不工作?

+0

的Dup的(http://superuser.com/q/142504/7542) – outis

回答

13

它不起作用,因为'>'重定向意味着截断,并且为了避免在重定向到文件之前将sort的整个输出保留在内存中,bash在运行前截断并重定向输出sort。因此,file1文件的内容将被截断,然后sort将有机会读取它。

+0

在重新引导到文件之前,并不是“避免将整个输出排序在内存中”,它不是'bash'特有的。定义的'>'的优先级意味着它在执行程序之前被评估,因此在所有shell中都是如此。 – EJP

1

Bash在读取管道时打开一个新的空文件,然后调用排序。

在第二种情况下,tee在排序已经读取内容后打开文件。

+0

“三通”打开它的文件在一些相对于'sort'打开文件的不确定时间。有时你很幸运,有时候你不幸。 “排序”没有必要读取所有内容,只是它已经首先打开文件。 – EJP

1

重定向具有更高的优先级。所以在第一种情况下,> file1首先执行并清空文件。

4

依靠这些命令中的任何一种来按预期方式工作是不明智的。

修改位置的文件的方法是修改后的版本写入到一个新的文件,然后将新的文件重命名为原来的名称:

sort file1 > file1.tmp && mv file1.tmp file1 

这避免了读取文件时,它的后问题已经部分修改,这可能会弄乱结果。它还可以正确处理错误;如果文件长度为N字节,并且文件系统上只有N/2个字节的可用空间,则可以检测到创建临时文件时发生的故障,而不执行重命名。

或者,你可以重命名原始文件,然后阅读并写入到一个新的文件具有相同名称:

mv file1 file1.bak && sort file1.bak > file1 

有些命令选项到位,修改文件(例如,perlsed都有-i选项(注意,sed的的-i选项的语法可能有所不同),但这些选项通过创建临时文件的工作;它只是在内部做

+3

不错 - 但'sort -o file1 file1'更简单也更安全。 –

16

正如其他人所解释的,问题是I/O重定向完成之前的sort c ommand被执行,因此在sort有机会阅读它之前截断该文件。如果你想一下,理由很明显 - shell处理I/O重定向,并且必须在运行该命令之前执行该操作。

sort命令有“总是”(因为至少第7版UNIX)支持的-o选项,以使之安全输出到输入文件之一:

sort -o file1 file1 file2 file3 

tee诀窍取决于时机和运气(可能是一个小数据文件)。如果你有一个兆字节或更大的文件,我预计它会被tee命令破坏,至少部分是破坏性的。也就是说,如果文件足够大,tee命令将打开文件以输出,并在sort完成读取之前将其截断。

+2

+1。它总是支付阅读手册 –

1

第一个命令不工作(sort file1 > file1),使用重定向操作符(>>>)时,因为壳创建/截断文件,甚至调用sort命令之前,因为它具有更高的优先级。

第二个命令有效(sort file1 | tee file1),因为sort先从文件读取行,然后将排序数据写入标准输出。

因此,使用任何其他类似的命令时,你应该避免进行读取和写入同一个文件时使用重定向操作符,但你应该使用相关就地编辑为(例如exedsed),例如:

ex '+%!sort' -cwq file1 

或使用其他utils的诸如sponge

幸运的是sort存在-o参数,将结果写入到该文件(由@Jonathan所建议的),因此该解决方案是直接的:sort -o file1 file1

-2

您可以使用此方法

sort file1 -o file1 

这将整理并回存到原始文件。此外,您还可以使用此命令来删除重复的行:[?SORT清空我的档案]

sort -u file1 -o file1 
+0

多年前已经提到。 –

+0

并没有回答实际的问题。 – EJP