bash - 为什么管道传输到同一个文件在某些​​平台上不起作用?

标签 bash pipeline overwrite io-redirection in-place

在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管道有没有万无一失的方法来覆盖我不知道的文件。

最佳答案

这里有四个要点:

  1. cat 毫无用处。”不要那样做。
  2. 您实际上并不是在使用排序 对任何内容进行排序。不要那样做。
  3. 您的流水线并没有如您所愿。不要那样做。
  4. 您正试图在读取文件时就地覆盖文件。不要那样做。

您出现不一致行为的原因之一是您正在管道化到一个具有重定向的进程,而不是将管道的输出作为一个整体进行重定向。区别很微妙,但很重要。

你想要的是用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/

相关文章:

regex - 将重复的正则表达式模式捕获为一组,在 bash 脚本中使用 sed

python - python 上的 bash 扩展模块

linux - 在 FOR 循环中查找时如何从名称中删除扩展名

windows - 如何使 Windows START 命令通过管道接受标准输入并将其传递给它调用的命令?

bash - 如何使用 ssh 直接连接到远程 docker 容器

python - 失败的 Airflow DAG 任务是否可以使用更改的参数重试

MySQL 导出到 outfile 并覆盖

python - 覆盖以前提取的文件而不是创建新文件

javascript - 更改模板上的日期格式

linux - 从 bash 脚本返回错误的 BASH 变量