为什么不“sortingfile1> file1”工作?

当我想sorting文件,并保存sorting的输出本身,就像这样

sort file1 > file1; 

file1的内容完全被擦除,而当我试图像这样做“tee”命令

 sort file1 | tee file1; 

它工作得很好[编辑:“工作正常”,只有对于有幸运的时间的小文件,会导致大数据丢失或无用的进程调度] ,即它覆盖文件1的sorting输出本身,并显示在标准输出。

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

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

正如其他人解释的那样,问题是I / O重定向是在执行sort命令之前完成的,所以在sort有机会读取文件之前,文件会被截断。 如果你想一下,理由很明显 – shell处理I / O重定向,并且在运行命令之前必须这样做。

sort命令具有“始终”(至少版本7 UNIX)支持-o选项,以便安全地输出到其中一个输入文件:

 sort -o file1 file1 file2 file3 

tee的技巧取决于时间和运气(可能是一个小的数据文件)。 如果你有一个或更大的文件,我希望它会被tee命令破坏,至少是部分的。 也就是说,如果文件足够大, tee命令将打开文件输出并在sort完成读取之前截断它。

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

修改文件的方法是将修改后的版本写入新文件,然后将新文件重命名为原始名称:

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

这样可以避免在文件被部分修改后读取文件的问题,这可能会导致结果混乱。 这也使得有可能妥善处理错误; 如果文件长度为N个字节,并且文件系统上只有N / 2个字节的可用空间,则可以检测到创建临时文件的失败,而不进行重命名。

或者您可以重命名原始文件,然后读取并写入同名的新文件:

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

有些命令可以选择修改文件(例如, perlsed都有-i选项(注意sed的-i选项的语法可以不同),但是这些选项是通过创建临时文件来实现的,这只是在内部完成的。

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

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

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

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

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

所以当使用其他类似的命令时,应该避免在读写同一个文件时使用重定向操作符,但是应该使用相关的就地编辑器(例如exedsed ),例如:

 ex '+%!sort' -cwq file1 

或者使用其他的应用程序,如sponge

幸运的是,有一个将结果写入文件的-o参数(正如@Jonathan所建议的那样 ),所以解决方法很简单: sort -o file1 file1

你可以使用这个方法

 sort file1 -o file1 

这将排序并存回原始文件。 另外,您可以使用此命令删除重复的行:

 sort -u file1 -o file1