【问题标题】:Is it possible to pass a backreference to a function from inside sed?是否可以从 sed 内部将反向引用传递给函数?
【发布时间】:2021-01-28 23:21:19
【问题描述】:

TL;DR 这是不可能的,因为“在运行 sed 之前,命令替换中的反向引用不是也不会由 sed 解析,而是由 shell 解析”(请参见下面的答案)。

我想用一个大文本文件 (>50MB) 中的相应字符替换国际音标的 unicode 值。

我的 test.txt 输入示例:

<CHARSET c="T">02C8;</CHARSET>ku:p<CHARSET c="T">0252;</CHARSET>n] noun<BR>

预期结果:

<CHARSET c="T">ˈ</CHARSET>ku:p<CHARSET c="T">ɒ</CHARSET>n] noun<BR>

我可以使用这个命令(例如)转换给定的 unicode:

echo -e "\u02C8"

但是我在 sed 命令中的转义失败了。我想到了从here 创建一个函数,如下所示:

codeToChar() { $( echo -e "\u$1"); }
sed -r -i 's#(<CHARSET c="T">)(....)#\1'"$(codeToChar \\2)"'#g' test.txt

但似乎 "\2" 反向引用没有传递给函数:

codeToChar() { $( echo -e "\u$1"); }
sed -r -i 's#(<CHARSET c="T">)(....)#\1'"$(codeToChar \\2)"'#g' test.txt
++ codeToChar '\2'
+++ echo -e '\u\2'
++ '\u\2'
./replace.sh: line 2: \u\2: command not found
+ sed -r -i 's#(<CHARSET c="T">)(....)#\1#g' test.tx

【问题讨论】:

  • 我建议选择其他工具。像python,perl。 sed 用于简单的流编辑器,它不像您可以根据行动态执行外部代码。抱歉,即使第一行 codeToChar() { $( echo -e "\u$1"); } 也是无效的 - 为什么要执行 echo 的执行结果?我相信重新阅读关于 shell 的良好介绍将有助于更好地理解 shell 的工作原理。
  • @KamilCuk:我想使用 echo 转换 Unicode 值。这是在这里建议的:code-examples.net/en/q/93320。我认为使用函数会使转义更容易。
  • 是的,对于 one unicode 值。不适用于从文件中提取的某些模式,该模式匹配某些内容,然后替换为写回文件的值。这是编程语言的任务,而不是 sed。

标签: function sed escaping backreference


【解决方案1】:

如何正确转义 sed 中的反向引用以将其传递给函数?

提供的代码正确处理反向引用。命令替换中的反向引用在运行sed 之前不会也不会由sed 解析,而是由shell 解析。程序的参数必须在运行程序之前展开。

您可能会使用 sed 的 GNU 扩展 - e 标志到 s 命令通过 /bin/sh 解释执行替换模式。强烈建议不要使用此标志,并且很难使用,因为很难确定正确的引用和转义 - 它在非常简单的情况下“有效”。因为输入字符串有 ; &lt; &gt;" 特殊的 shell 字符我怀疑这是可能的。

我建议选择一种成熟的编程语言,如 python、perl 或其他语言来解决您的任务。 sed 不是根据文件内容动态执行操作的实用程序,它是一个简单的流替换实用程序。

sed 中,可以构建要替换的静态字符串列表,如下所示:

sed -r '
     s/(<CHARSET c="T">)02C8/\1'"$(echo -e "\u02C8")"/
     s/(<CHARSET c="T">)0252/\1'"$(echo -e "\u0252")"/
     .... one s/// command for each character to replace ...
'

【讨论】:

  • 感谢您的深入回答。 “命令替换中的反向引用不会也不会被 sed 解析”:您介意解释为什么(链接的)示例函数有效吗? stackoverflow.com/questions/19365068/…
  • 是哪个例子?
  • 添加 set -x 并亲自查看。它会生成一个 sed 脚本,例如:sed -r 's/(.) (.) (.)/x\2y\2z/',然后运行它。它确实\2替换为反向引用,然后运行bash函数,它以相反的方式执行 - 运行输出x\2y\2z的函数,然后运行sed。跨度>
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-05-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多