【问题标题】:Find and Replace string in all files recursive using grep and sed [duplicate]使用grep和sed递归查找和替换所有文件中的字符串[重复]
【发布时间】:2013-04-01 23:10:15
【问题描述】:

我得到了一个

sed: -e expression #1, char 22: unterminated `s' command 

我的脚本有问题吗? “oldstring”也有特殊字符

#!bin/bash
oldstring='<script>"[oldscript]"</script>'
newstring='<script>"[newscript]"</script>'
grep -rl $oldstring /path/to/folder | xargs sed -i s/$oldstring/$newstring/g

【问题讨论】:

  • 方括号可能需要转义。还要双引号 sed 模式。
  • 您的模式中的/ 也会有问题。他们应该逃脱。或者您可以为您的s 命令使用另一个分隔符(例如@)。

标签: linux bash recursion sed grep


【解决方案1】:

sed表达式需要加引号

sed -i "s/$oldstring/$newstring/g"

【讨论】:

    【解决方案2】:

    正如@Didier 所说,您可以将分隔符更改为/ 以外的其他内容:

    grep -rl $oldstring /path/to/folder | xargs sed -i s@$oldstring@$newstring@g
    

    【讨论】:

    • 鉴于 oldstring 或 newstring 的许多可能内容,上述内容会以许多有趣的方式失败。
    • @EdMorton,你能举个例子说明它是如何失败的吗?我知道你在下面发布了传统的做法,但只是说它可能会失败,留下如何做的问题。然后我可以理解为什么我应该你的解决方案。这些解决方案似乎更容易。谢谢
    • 在任一字符串变量中使用任何 shell 通配符或 @ 尝试上述操作。 globbing 字符可以/将匹配您目录中的文件名,如果不是今天,那么在您最后一次期望它的未来某天,@ 将终止您的 sed 命令。如果 oldstring 在各个位置包含空格,它也会失败,更不用说任何一个字符串是否包含换行符。 OP 特别提到了the "oldstring" has special characters,所以这是一个很大的提醒,我刚刚描述的任何事情都可能发生。
    • 还要注意,在某些环境中,尤其是 Darwin/MacOSX,您需要提供明确的备份扩展名,例如“sed -i .bak”。
    • @thoni56 "尤其是 Darwin/MacOSX" 也称为 BSD...
    【解决方案3】:

    当 GNU 人将递归文件搜索引入 grep 时,他们真的搞砸了。 grep 用于在文件中查找 RE 并打印匹配行(g/re/p 还记得吗?)不是用于查找文件。有一个非常好的工具,用于查找文件的名称非常明显。 UNIX 口号“做好一件事并做好”到底发生了什么?

    无论如何,以下是使用传统 UNIX 方法(未经测试)做你想做的事情的方法:

    find /path/to/folder -type f -print |
    while IFS= read -r file
    do
       awk -v old="$oldstring" -v new="$newstring" '
          BEGIN{ rlength = length(old) }
          rstart = index($0,old) { $0 = substr($0,rstart-1) new substr($0,rstart+rlength) }
          { print }
       ' "$file" > tmp &&
       mv tmp "$file"
    done
    

    并不是说通过使用 awk/index() 而不是 sed 和 grep,您无需转义可能出现在旧字符串或新字符串中的所有 RE 元字符,并找出用作 sed 分隔符的字符不能出现在您的旧字符串或新字符串中,并且您不需要运行 grep 因为替换只会发生在包含您想要的字符串的文件中。说了这么多,如果您不希望文件时间戳在不修改文件的情况下更改,那么只需在执行 mv 之前对 tmp 和原始文件进行 diff 或在 fgrep -q 之前抛出啊。

    警告:以上内容不适用于包含换行符的文件名。如果您有这些,请告诉我们,我们可以向您展示如何处理它们。

    【讨论】:

    • +1 当有人谈到使用sedgrep 时,他们很有可能只使用sed 或切换到awk。顺便说一句,如果您在查找中使用了 -print0,并且(在 BASH 中)使用 -d\0 应该注意文件名中包含新行。
    • @DavidW。正确的。当您开始谈论转义 RE 元字符以使 sed 或 grep 不会这样对待它们时,您需要切换到 awk/index() 或 fgrep 以便您可以查找字符串而不是 RE。
    • @josten grep-r 参数是使用 find 而不使用 awk 的替代方法。您可以使用awkfind+xargs 而不是grep+sed,结果通常会更简洁高效。使用awk 肯定不会导致您创建巨大的错综复杂的单行代码。
    【解决方案4】:
    grep -rl $oldstring . | xargs sed -i "s/$oldstring/$newstring/g"
    

    【讨论】:

    • 因此,复杂的是,名称中带有空格的文件将不会被拾取。如果你有“/files/File Two.txt”,sed 会尝试“/files/File”和“Two.txt”。
    【解决方案5】:
    grep -rl SOSTITUTETHIS . | xargs sed -Ei 's/(.*)SOSTITUTETHIS(.*)/\1WITHTHIS\2/g'
    

    【讨论】:

      猜你喜欢
      • 2011-09-04
      • 2014-04-28
      • 2020-11-15
      • 1970-01-01
      • 2014-01-13
      • 2018-02-24
      • 1970-01-01
      • 2017-05-14
      • 2013-03-23
      相关资源
      最近更新 更多