【问题标题】:bash: sed does not write the pipe result to origin file [duplicate]bash:sed 不会将管道结果写入原始文件 [重复]
【发布时间】:2015-04-27 19:06:13
【问题描述】:

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

me$ echo "AAA" > tmp.txt
me$ cat tmp.txt | sed 's/A/B/g' > tmp.txt
me$ cat tmp.txt

结果是一个空文件,而不是 tmp.txt 中所需的“BBB” 如果我选择不同的文件进行输出,它仍然有效。一些想法?提前谢谢!

【问题讨论】:

  • 不是重复的 - 请参阅我的答案,它提供了一种不同的解决方案。
  • @La-comadreja,我不同意;该答案(写入并重命名)已在 Etan 的另一篇文章中给出。
  • @La-comadreja, ...另外,如果(通常是case) 正在使用的目录可由其他用户写入(如/tmp 的情况)。在这种情况下,对同一目录进行写入的恶意用户可以创建指向他们无权访问但运行脚本的帐户可以访问的位置的符号链接,从而触发任意覆盖后一个帐户拥有的文件。
  • 这也足以成为 BashPitfalls 列表中的常见问题解答:mywiki.wooledge.org/…

标签: bash sed pipe


【解决方案1】:

你可以这样写:

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

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

【讨论】:

    【解决方案2】:

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

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

    【讨论】:

      【解决方案3】:

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

      $ echo "AAA" > tmp.txt
      $ sed -i 's/A/B/g' tmp.txt
      $ cat tmp.txt
      BBB
      

      以上使用 GNU sed 语法。如果您使用的是 Mac OSX (BSD),请使用:

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

      讨论

      从问题出发,考虑这行代码:

      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
      

      【讨论】:

        猜你喜欢
        • 2017-06-26
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-07-02
        • 2021-12-24
        相关资源
        最近更新 更多