使用管道时修改文件的最佳方法?

use*_*956 9 bash shell pipe

我经常有shell编程任务,我遇到这种模式:

cat file | some_script > file
Run Code Online (Sandbox Code Playgroud)

这是不安全的 - 在some_script开始写入之前,cat可能没有在整个文件中读取.我真的不想把结果写到一个临时文件中(它很慢,而且我不希望增加复杂性来考虑一个独特的新名称).

也许,有一个标准的shell命令会缓冲整个流,直到达到EOF为止?就像是:

cat file | bufferUntilEOF | script > file
Run Code Online (Sandbox Code Playgroud)

想法?

cha*_*cus 6

你在找海绵

  • @Julinao - 问题不是海绵,而是外壳 i) 海绵 < file > file ,导致文件被截断。同理cat文件| 乙 | | | 海绵 > 文件,也会被截断。Bash 在海绵看到输入之前截断文件。ii) cat 文件 | 海绵文件,工作正常。 (3认同)
  • 我不推荐海绵。如果管道中的任何命令(海绵除外)失败(例如,由于语法错误、无效参数等),它会擦除​​文件,并且您将在没有原始文件和目标文件的情况下结束。 (2认同)

R S*_*hko 6

像许多其他人一样,我喜欢使用临时文件。我使用 shell 进程 ID 作为临时名称的一部分,这样如果脚本的多个副本同时运行,它们就不会发生冲突。最后,如果脚本成功,我只会覆盖原始文件(使用布尔运算符短路 - 它有点密集但对于简单的命令行非常好)。把所有这些放在一起,它看起来像:

some_script < file > smscrpt.$$ && mv smscrpt.$$ file
Run Code Online (Sandbox Code Playgroud)

如果命令失败,这将保留临时文件。如果要清理错误,可以将其更改为:

some_script < file > smscrpt.$$ && mv smscrpt.$$ file || rm smscrpt.$$
Run Code Online (Sandbox Code Playgroud)

顺便说一句,我摆脱了 cat 的不良使用,并用输入重定向替换了它。

  • @stuartreynolds - 其他人发布了关于海绵的帖子,你拒绝了,因为它不标准。没有什么标准可以做你想要的。 (2认同)
  • @stuartreynolds - 如果你想要一些标准的东西,那么是的,你需要临时文件。我不同意缓冲是基本的,因为您可以通过临时文件获得必要的行为(并且鉴于命令行的工作方式,临时文件更好,因为如果出现错误,您可以保留原始文件)。最后,如果 Cygwin 被破坏以至于文件重命名太慢,这就是应该修复的问题。 (2认同)

Jul*_*ano 5

在这里使用临时文件是正确的解决方案。当您使用“>”之类的重定向时,它将由外壳程序处理,无论您的管道中有多少命令,外壳程序都可以在执行任何命令之前(在管道安装过程中)自由删除和覆盖输出文件。


Bro*_*ate 5

另一种选择是将文件读入变量:

file_contents=$(cat file)
echo "$file_contents" | script1 | script2 > file
Run Code Online (Sandbox Code Playgroud)


Joh*_*don 1

在我看来,使用临时文件比尝试缓冲管道中的数据更好。

它几乎违背了管道缓冲它们的目的。