当我想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
有些命令可以选择修改文件(例如, perl
和sed
都有-i
选项(注意sed的-i
选项的语法可以不同),但是这些选项是通过创建临时文件来实现的,这只是在内部完成的。
Bash在读取管道时打开一个新的空文件,然后调用排序。
在第二种情况下,在排序已经读取内容之后,tee打开文件。
重定向有更高的优先级。 所以在第一种情况下,> file1首先执行并清空文件。
第一个命令不起作用( sort file1 > file1
),因为当使用重定向操作符( >
或>>
)时,在调用sort
命令之前shell会创建/截断文件,因为它具有更高的优先级。
第二个命令工作( sort file1 | tee file1
),因为sort
从文件中首先读取行,然后将排序后的数据写入标准输出。
所以当使用其他类似的命令时,应该避免在读写同一个文件时使用重定向操作符,但是应该使用相关的就地编辑器(例如ex
, ed
, sed
),例如:
ex '+%!sort' -cwq file1
或者使用其他的应用程序,如sponge
。
幸运的是,有一个将结果写入文件的-o
参数(正如@Jonathan所建议的那样 ),所以解决方法很简单: sort -o file1 file1
。
你可以使用这个方法
sort file1 -o file1
这将排序并存回原始文件。 另外,您可以使用此命令删除重复的行:
sort -u file1 -o file1