我知道这有点像另一个问题的重复(为什么这个排序命令给我一个空文件?)但我想根据给出的答案来扩展这个问题。
命令
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。我删除了parallel
moreutils安装的)
答案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
%
选择所有行!
运行命令x
保存并关闭