【问题标题】:What does the following Makefile/shell/sed line do?下面的 Makefile/shell/sed 行是做什么的?
【发布时间】:2012-11-01 12:26:50
【问题描述】:

这条线直接来自 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 命令(用于打印?)做什么?

【问题讨论】:

    标签: shell sed makefile fullcalendar


    【解决方案1】:

    这真是一块牛黄。

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

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

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

    sed 's/${DEMO_RE}//'
    

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

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

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

    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 表示将每一行 除了 第一行附加到保留空间。记住-n;在 sed 执行花括号中的命令组之前不会打印任何内容,这只会在读入最后一行输入时发生。所以:

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

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

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

    【讨论】:

    • “前导”分号实际上是花括号和以下命令之间的行分隔符。 GNU sed 不需要它,但几乎所有其他 sed 实现都需要它。为便于携带,应始终包含它。
    • 哦,对了,我也 +1。 :-)
    【解决方案2】:

    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
    

    到那时,所有这些都变成了功能性的东西。

    【讨论】:

      猜你喜欢
      • 2015-07-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-02-07
      • 2011-09-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多