bash:sed不会将管道结果写入原始文件

bash:sed不会将管道结果写入原始文件,bash,sed,pipe,Bash,Sed,Pipe,我在一个简单的管道里面对这种奇怪的行为: me$ echo "AAA" > tmp.txt me$ cat tmp.txt | sed 's/A/B/g' > tmp.txt me$ cat tmp.txt 结果是一个空文件,而不是tmp.txt中所需的“BBB” 不过,如果我选择不同的文件作为输出,它也可以工作。一些想法?提前谢谢 您可以这样写: sed 's/A/B/g' tmp.txt > tmp2.txt mv tmp2.txt tmp.txt 第一行将文件内容以及

我在一个简单的管道里面对这种奇怪的行为:

me$ echo "AAA" > tmp.txt
me$ cat tmp.txt | sed 's/A/B/g' > tmp.txt
me$ cat tmp.txt
结果是一个空文件,而不是tmp.txt中所需的“BBB” 不过,如果我选择不同的文件作为输出,它也可以工作。一些想法?提前谢谢

您可以这样写:

sed 's/A/B/g' tmp.txt > tmp2.txt
mv tmp2.txt tmp.txt

第一行将文件内容以及相关字符串替换写入新文件。第二行将新文件移动到旧文件的位置,覆盖旧文件。

要更改文件,请使用
sed-i

$ echo "AAA" > tmp.txt
$ sed -i 's/A/B/g' tmp.txt
$ cat tmp.txt
BBB
上面使用GNU
sed
语法。如果您正在使用Mac OSX(BSD),请使用:

讨论

从这个问题,考虑这一行代码:

cat tmp.txt | sed 's/A/B/g' > tmp.txt
cat tmp.txt
尝试读取
tmp.txt
。但是,当shell看到
>tmp.txt
时,它会将
tmp.txt
截断为空文件,以准备输入。这样的结果是不可靠的

相比之下,
sed-i
被明确设计用于处理这种情况。它完全避免了冲突

如果愿意,
sed-i
可以创建原始文件的备份。使用GNU
sed
,使用:

sed -i.bak 's/A/B/g' tmp.txt
使用BSD(Mac OSX)
sed
,添加一个空格:

sed -i .bak 's/A/B/g' tmp.txt

为什么不喜欢“就地”编辑而不是cat或重命名

sed 's/A/B/g' -i tmp.txt

不是重复的-看我的答案,它提供了一种不同的解决方案。@La comadreja,我不同意;这个答案(写入和重命名)已经在另一篇文章中给出,作者是Etan。@La comadreja,……此外,如果(通常情况下)正在使用的目录可由其他用户写入,则您使用的方法(使用固定的临时文件名,而不是由
mktemp
生成的文件名)会出现安全漏洞(如
/tmp
所述)。在这种情况下,写入同一目录的恶意用户可以创建一个符号链接到他们无权访问但运行脚本的帐户可以访问的位置,从而触发对该帐户所拥有的任意文件的覆盖。这也足以成为BashPitts列表中的常见问题:
sed 's/A/B/g' -i tmp.txt