为什么 sed 的行为会因输出文件而异?

ash*_*gpu 5 linux pipe sed

如果我运行:

cat messages.txt | sed -e 's/a/a/g' > messages.txt
Run Code Online (Sandbox Code Playgroud)

在一个大文件(2500 多行)上,我发现生成的文件在 cygwin 中的命令之后只有大约 900 行,并且在 gentoo 中没有行。但是,如果我跑

cat messages.txt | sed -e 's/a/a/g' > other_messages.txt
Run Code Online (Sandbox Code Playgroud)

它保留了所有应有的行。

我的问题是为什么,除了

cat messages.txt | sed -e 's/a/a/g' > other_messages.txt
rm messages.txt
mv other_messages.txt messages.txt
Run Code Online (Sandbox Code Playgroud)

Ste*_*n D 11

使用 sed 时,fschmitt 的答案是最好的;然而,在更一般的意义上,这种反模式:

cat infile | filter > infile
Run Code Online (Sandbox Code Playgroud)

很可能会给你带来很多问题。例如,如果我有一个名为的文件infile,如下所示:

Hello
World
Run Code Online (Sandbox Code Playgroud)

并运行此命令:

cat infile | tr "[:upper:]" "[:lower:]"
Run Code Online (Sandbox Code Playgroud)

我得到

hello
world
Run Code Online (Sandbox Code Playgroud)

但是如果我运行,cat infile | tr "[:upper:]" "[:lower:]" > infile我会得到一个空文件。为什么?

好吧,当您使用输出重定向运算符时,>您是在说“将我的标准输出放入此文件中,如果该文件存在则覆盖它”。现在您可能认为这应该可行,因为您的过滤器将返回原始文件的所有行。但是,通常最终会发生的是,shell 会在读取任何行之前破坏您的文件。然后,您的过滤器命令将从一个空文件中读取行,查找无,因此返回无。在某些地方,您可能会“幸运”到在文件被破坏之前读取一些行,但最好完全避免这种模式。

要解决此特定问题,您有几种选择。一种是简单地执行以下操作:

cat infile | filter > tmpfile; mv tmpfile infile
Run Code Online (Sandbox Code Playgroud)

如果您需要确保您的临时文件不会破坏其他文件或发生其他令人讨厌的事情,您应该查看mktemp. (见man mktempinfo coreutils mktemp

另一种选择是使用spongefrom moreutils

此外,其中许多示例都是cat 无用用途的示例。


fsc*_*itt 10

你为什么不写

sed -i -e 's/a/a/g' messages.txt
Run Code Online (Sandbox Code Playgroud)

-i 的意思是“就地”