3

此行直接来自 FullCalendar(一个 jQuery 插件)Makefile。我无法理解它,尤其是带有美元符号的部分。我不知道 make、shell 或 sed 是否“处理”它。我也不清楚其他(显然?) sed 命令。

DEMO_RE = (<script[^>]*_loader\.js[^>]*><\/script>|<!--\[\[|\]\]-->)[^<]*
DEMO_SED = sed -nE '1h;1!H;$${;g;s/${DEMO_RE}//g;p;}'
  1. 1h有什么作用?
  2. 美元符号和括号在哪里以及如何解释?
  3. 第一个 g 命令和最后一个 p 命令(打印?)做什么?
4

2 回答 2

8

那是相当牛黄。

DEMO_RE是一个正则表达式。粗略地说,这意味着它是对另一个字符序列的描述。任何给定的字符序列要么匹配此正则表达式,要么不匹配。

DEMO_SED是一个 sed 命令。在这个阶段,它只是一个 Make 变量,一个字符序列,但稍后可以将其传递给 shell(在 Make 变量扩展之后),shell 会将其解释为 sed 命令。

我不完全理解这个 sed 命令,但这是我最好的尝试。从中间开始:

sed 's/${DEMO_RE}//'

Make 将扩展${DEMO_RE}为第一行中的 gobbledegook 字符串,查找与正在考虑的任何文本行的匹配,并将匹配的文本更改为空(即删除它)。

sed 's/${DEMO_RE}//g'

命令的g修饰符s意味着对所有匹配项进行替换(在本例中为删除),而不仅仅是找到的第一个匹配项。

sed -nE 's/${DEMO_RE}//g;p'

-n方法默认情况下不打印结果。该p方法打印模式空间的内容,因此目前这些更改相互抵消。该E方法将正则表达式解释为扩展的正则表达式,而不是基本的正则表达式。

sed -nE '{s/${DEMO_RE}//g;p}'

花括号将这些命令分组。

sed -nE '${;g;s/${DEMO_RE}//g;p;}'

现在事情变得复杂了。Sed 有第二个缓冲区,称为保持空间。该g命令将保持空间的内容复制到模式空间(这是人们通常使用的缓冲区,也是大多数人知道的唯一一个)。在我们考虑将把东西放入保持空间的其他命令之前,这没有多大意义。这$意味着仅当 sed 到达输入的最后一行时才应应用此命令(大括号的内容)。我认为前导分号没有任何用途,但我不敢说它绝对没有任何作用。现在,为了便于阅读,我将省略替换命令。

sed -nE '$${;g;p;}'

由于 Make 尝试扩展以 开头的内容$,并且我们想将 '$' 原封不动地传递给 sed,因此我们用另一个 '$' 对其进行转义。Make 将扩展$$$传递${...给 shell(它将传递给 sed)。

sed -nE '1h;1!H;$${;g;p;}'

1h意味着将输入的第一行复制到保持空间。该方法将除第一行之外1!H的每一行附加到保留空间。记住; 在 sed 执行花括号中的命令组之前不会打印任何内容,这只会在读入最后一行输入时发生。所以:-n

sed -nE '1h;1!H;$${;g;s/${DEMO_RE}//g;p;}'

“将所有输入读入保留空间,不打印任何内容,然后在最后将其全部拉回,切除与(可能扩展的)匹配的所有内容,并打印剩下的所有内容。”

这个答案变得很长;我可以给你一个正则表达式的粗略翻译,但是以一种不会混淆这个媒介的方式这样做是一种痛苦。它似乎想要匹配任何被script标签 or<!--[[包围的东西]]-->,以及所有这些都跟随到下一个标签。

于 2012-10-31T05:09:17.130 回答
3

Beta 在分解 sed 脚本方面做得非常出色,一个逻辑块一个逻辑块。sed 脚本从输入文本中删除某些 JavaScript 块。他的最终总结可能就是你所需要的。如果你想要一个更短的答案,那就去吧。

你提到的令人困惑的部分是美元符号。

        ┌ Double $ is actually just an "escaped" $ character
        │       ┌ Starts a variable reference
        │       │
'1h;1!H;$${;g;s/${DEMO_RE}//g;p;}'
          │     │        │      │
          │     └variable┘      │
          └ Stuff run at EOF ───┘

第一对美元符号构成一个美元符号,sed 将其解释为“在文件末尾”。因此,外部大括号之间的内容在 EOF 处运行。内部大括号采用 的形式${VARNAME},这是 Make 引用变量的方式。它看起来像一个 shell 变量引用,但它不是。

在这种情况下,因为 Make 变量赋值实际上并没有执行任何操作,所以您的DEMO_SED变量被分配了其中的内容DEMO_RE。具有讽刺意味的是,将其拆分为两个变量的原因是为了使整个过程更具可读性。:-)

请注意,这些实际上都不会执行任何操作(即 sed)。它只分配变量。稍后在您的 Makefile 中,您可能有一个目标,其中一行可能类似于:

${DEMO_SED} path/to/file.html.orig > path/to/file.html

正是在这一点上,所有这些都变成了功能性的东西。

于 2012-11-01T04:26:50.183 回答