为什么命令 shuf file > file 会留下一个空文件,而类似的命令却不会?

为什么命令 shuf file > file 会留下一个空文件,而类似的命令却不会?

我知道这有点像另一个问题的重复(为什么这个排序命令给我一个空文件?)但我想根据给出的答案来扩展这个问题。

命令

shuf example.txt > example.txt

返回一个空白文件,因为 shell 在打乱文件之前截断了该文件,只留下一个空白文件进行打乱。然而,

cat example.txt | shuf > example.txt

将按预期生成一个打乱的文件。

为什么管道方法可以工作,而简单重定向却不起作用?如果在运行命令之前文件被截断,那么第二种方法是否也应该留下一个空文件?

答案1

问题是在开始读取> example.txt该文件之前开始写入该文件。shuf example.txt因此,由于还没有输出,example.txt因此为空,shuf读取空文件,并且shuf在这种情况下没有输出,因此最终结果保持为空。

您的其他命令可能会遇到同样的问题。可能会在开始读取文件> example.txt之前杀死该文件;cat example.txt这取决于 shell 执行这些操作的顺序,以及cat实际打开文件所需的时间。

为了完全避免此类问题,您可以使用shuf example.txt > example.txt.shuf && mv example.txt.shuf example.txt.

或者你也可以选择一起去shuf example.txt --output=example.txt

答案2

套餐更多实用程序有一个命令sponge

   sponge  reads  standard input and writes it out to the specified file.
   Unlike a shell redirect, sponge soaks up all its input before  opening
   the output file. This allows constricting pipelines that read from and
   write to the same file.

用这种方式你可以这样做:

shuf example.txt | sponge example.txt

不幸的是,moreutils 包还有一个名为 util 的工具parallel,它的用处远不如 gnu parallel。我删除了parallelmoreutils安装的

答案3

你只是很幸运地跑步

cat example.txt | shuf > example.txt

example.txt不像这个命令那样清空。

shuf example.txt > example.txt

重定向是由 shell 在执行命令和同时执行管道组件之前执行的。

使用-o/--output选项将是最好的解决方案,shuf但如果您喜欢承担(非常轻微的)风险,这里有一种非传统的方法来避免处理的文件在读取之前被截断:

shuf example.txt | (sleep 1;rm example.txt;cat > example.txt)

感谢 Ole 的建议,这个更简单、更快:

(rm example.txt; shuf > example.txt) < example.txt

答案4

您可以在 Ex 模式下使用 Vim:

ex -sc '%!shuf' -cx example.txt
  1. %选择所有行

  2. !运行命令

  3. x保存并关闭

相关内容