为什么"sort file1> file1"不起作用?

dig*_*123 16 unix linux shell redirect pipe

当我尝试对文件进行排序并保存已排序的输出时,就像这样

sort file1 > file1;
Run Code Online (Sandbox Code Playgroud)

file1的内容完全被删除,而当我试图用'tee'这样的命令做同样的事情时

sort file1 | tee file1;
Run Code Online (Sandbox Code Playgroud)

它工作正常[编辑:"工作正常"仅适用于幸运时间的小文件,会导致大数据丢失或无用的进程调度],即它会覆盖file1的排序输出本身并在标准输出上显示它.

有人可以解释为什么第一个案例不起作用?

Jon*_*ler 18

正如其他人所解释的那样,问题是I/O重定向是在sort执行命令之前完成的,因此文件会被截断,然后sort才有机会读取它.如果你想一点,原因很明显 - shell处理I/O重定向,并且必须在运行命令之前执行此操作.

sort命令具有'always'(因为至少版本7 UNIX)支持一个-o选项,可以安全地输出到其中一个输入文件:

sort -o file1 file1 file2 file3
Run Code Online (Sandbox Code Playgroud)

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


小智 14

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

  • 这并不是“避免在重定向到文件之前将排序的整个输出保留在内存中”,也不是“bash”所特有的。`>` 定义的优先级意味着它在执行程序之前被评估,就这么简单,在所有 shell 中。 (2认同)

Kei*_*son 5

依赖这些命令中的任何一个以您期望的方式工作是不明智的。

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

sort file1 > file1.tmp && mv file1.tmp file1
Run Code Online (Sandbox Code Playgroud)

这避免了在文件被部分修改后读取文件的问题,这可能会弄乱结果。它还可以优雅地处理错误;如果文件长 N 字节,而文件系统上只有 N/2 字节可用空间,则可以检测到创建临时文件的失败,而不是进行重命名。

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

mv file1 file1.bak && sort file1.bak > file1
Run Code Online (Sandbox Code Playgroud)

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

  • 不错 - 但 `sort -o file1 file1` 更简单、更安全。 (3认同)