在cygwin中,下面的代码可以正常工作
$ cat junk
bat
bat
bat
$ cat junk | sort -k1,1 |tr 'b' 'z' > junk
$ cat junk
zat
zat
zat
但是在linux shell(GNU/Linux)中,覆盖似乎不起作用
[41] othershell: cat junk
cat
cat
cat
[42] othershell: cat junk |sort -k1,1 |tr 'c' 'z'
zat
zat
zat
[43] othershell: cat junk |sort -k1,1 |tr 'c' 'z' > junk
[44] othershell: cat junk
两种环境都运行 BASH。
我问这个是因为有时在我进行文本操作之后,由于这个警告,我不得不制作 tmp 文件。但我知道在 Perl 中,你可以在一些操作/操作后给出“i”标志来覆盖原始文件。我只想问一下unix管道有没有万无一失的方法来覆盖我不知道的文件。
最佳答案
这里有四个要点:
- “cat 毫无用处。”不要那样做。
- 您实际上并不是在使用排序 对任何内容进行排序。不要那样做。
- 您的流水线并没有如您所愿。不要那样做。
- 您正试图在读取文件时就地覆盖文件。不要那样做。
您出现不一致行为的原因之一是您正在管道化到一个具有重定向的进程,而不是将管道的输出作为一个整体进行重定向。区别很微妙,但很重要。
你想要的是用Command Grouping创建一个复合命令,这样你就可以重定向整个管道的输入和输出。在您的情况下,这应该可以正常工作:
{ sort -k1,1 | tr 'c' 'z'; } < junk > sorted_junk
请注意,如果没有要排序的内容,您也可以跳过排序 命令。然后你的命令可以运行而不需要命令分组:
tr 'c' 'z' < junk > sorted_junk
保持重定向和管道尽可能简单。它使调试脚本变得更加容易。
但是,如果出于某种原因您仍然想滥用管道,您可以使用 moreutils 包中的 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.
所以,你原来的命令行可以这样重写:
cat junk | sort -k1,1 | tr 'c' 'z' | sponge junk
并且由于在 sponge 从管道接收到 EOF 之前垃圾不会被覆盖,因此您将获得预期的结果。
关于bash - 为什么管道传输到同一个文件在某些平台上不起作用?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10586623/