【问题标题】:Optimally replacing multi-line substring in bash for non-greedy matching?以最佳方式替换 bash 中的多行子字符串以进行非贪婪匹配?
【发布时间】:2018-01-09 05:28:07
【问题描述】:

有很多不同的单行字符串替换解决方案,但我很好奇什么最有效的方法是只使用 bash 内置函数来执行多行替换。

我正在使用以下解决方案,使用 bash 的内置正则表达式,如果只有一个匹配项,它可以正常工作:

read -r -d '' to_search <<'EOF'
1
2
3
-
1
2
3
-
1
2
3
EOF

read -r -d '' to_find <<'EOF'
1
2
3
EOF

read -r -d '' to_replace <<'EOF'
a
b
c
EOF

[[ $to_search =~ (.*)($to_find)(.*) ]] &&
   echo "${BASH_REMATCH[1]}$to_replace${BASH_REMATCH[3]}"

如果我想替换所有匹配项,这也可以工作,因为我可以循环直到没有匹配项。但它没有提供非贪婪的解决方案,因为 bash 的内置正则表达式不支持 ? 运算符。

例如,因为匹配是贪心的,所以输出只会考虑最后一个匹配,而不是在第一个匹配。例如:

1
2
3
-
1
2
3
-
a
b
c

一种解决方案可能是将输入和匹配字符串拆分为数组,然后在循环中逐步遍历它们以找到匹配项,但这可能不是最佳的。

我欢迎其他解决方案供参考,但具体问题是仅使用 bash 内置函数来解决此问题。这可以通过将字符串传递给 Python 或 Perl 来解决,但这不是我想要的。

欢迎使用常用工具 (sed/grep/awk) 的替代方案的答案作为参考和比较,但不会被接受,因为它没有回答这个特定问题。适用于不提供正则表达式工具的旧 bash 环境的解决方案的额外加分。

请注意,这对于 sed 和 grep 来说一开始可能看起来很容易,但是这两个工具都只在单个行上执行匹配,不适合多行匹配。

【问题讨论】:

  • 错了! sed 确实能够处理多行匹配,尽管您不会经常看到这样的用法。请参阅带有大写字母heresed 命令。

标签: string bash replace split


【解决方案1】:

如果它涉及纯文本搜索或 glob 模式,那么 BASH 的字符串替换可以正常工作:

echo "${to_search//$to_find/$to_replace}"

a
b
c
-
a
b
c
-
a
b
c

编辑:根据您编辑的包含 glob 字符 * 的示例,您可以使用 index 函数使用此 awk 搜索循环:

read -r -d '' to_search <<'EOF'
*
1
2
3
*
1
2
3
*
1
2
3
EOF

read -r -d '' to_find <<'EOF'
*
1
2
3
EOF

read -r -d '' to_replace <<'EOF'
a
b
c
EOF

awk -v s="$to_search" -v f="$to_find" -v r="$to_replace" 'BEGIN {
   while(p=index(s, f)) s = substr(s, 1, p-1) r substr(s, p+length(f)); print s}'

a
b
c
a
b
c
a
b
c

PS:请注意,以下bash 模式替换也可以通过转义每个*来工作:

echo "${to_search//${to_find//\*/\\*}/$to_replace}"

a
b
c
a
b
c
a
b
c

【讨论】:

  • 只匹配第一个,使用:echo "${to_search/$to_find/$to_replace}"
  • 当我将* 作为字符串的一部分引入时,我得到了一个奇怪的结果。它替换所有相邻的实例并合并它们:pastebin.com/uziCUK9q
  • 预期输出不应合并结果。我已经修改了我的 pastebin 链接。如果我使用其他字符,例如-,它会按预期工作。
  • 成功答案的要求是“仅使用 bash 内置函数来解决这个问题”。
  • 接受这一点,因为它确实回答了问题和其他要求,例如涉及通配符和其他未经测试的输入的复杂性超出了范围。感谢您的耐心等待。
猜你喜欢
  • 2021-07-02
  • 1970-01-01
  • 2013-06-09
  • 1970-01-01
  • 2021-09-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多