【问题标题】:bash - sed query to edit yaml filebash - sed 查询以编辑 yaml 文件
【发布时间】:2017-05-04 00:48:44
【问题描述】:

我有一个 config.yaml 文件,其中包含我想使用 bash 脚本从配置中删除的以下 kafka 代理列表。

kafka.brokers:
    - "node003"
    - "node004"

我目前正在使用以下命令从脚本内部调用 vi

vi $CONF_BENCHMARK/config.yaml -c ":%s/kafka.brokers:\(\n\s*-\s".*"\)*/kafka.brokers:/g" -c ':wq!'

我知道 sed 是完成相同任务的更合适的工具,但是当我尝试将上述正则表达式转换为 sed 时,它不起作用。 p>

sed -i -e "s/kafka.brokers:\(\n\s*-\s".*"\)*/kafka.brokers:/g" $CONF_BENCHMARK/config.yaml

我做错了什么?

【问题讨论】:

  • sed is a more appropriate tool -> 不,YAML 解析器是更合适的工具 :-) YAML 相当复杂,根本不适合使用 shell 脚本等进行临时修改。

标签: bash vim sed


【解决方案1】:

您的 Vim 模式匹配多行,但 sed 逐行工作。 (也就是说,它首先尝试将您的模式与 kafka.brokers: 匹配并失败,然后它尝试匹配 - "node003",等等。)您使用 Vim 以外的东西的直觉是正确的,但 sed 可能不是在这里工作的最佳工具。

This answer 更详细地解决了用 sed 匹配多行模式的问题。

我个人的建议是使用 Python 或 Perl 等脚本语言来处理复杂的模式匹配。例如,您可以使用python -c <command> 运行 Python 命令,就像使用 Vim 一样,或者您可以编写一个从 Bash 脚本调用的小型 Python 脚本。它比 sed one-liner 稍微复杂一些,但它可能会为您节省大量调试工作,并使您的脚本更易于维护和修改。

【讨论】:

  • 我尝试使用 perl 作为perl -pi -e "s/kafka.brokers:\(\n\s*-\s".*"\)*/kafka.brokers:/g" config.yaml,但这似乎也不起作用。我希望 python 对我有用。
  • @andlrc 我正在尝试在文件config.yaml 中就地替换,正如我在上面评论中的代码所示。运行您的建议结果Can't open perl script "s/kafka....": No such file or directory
  • @HaseebJaved perl -p0e '...' 将一口气吞下整个文件。使用-pi -0e 进行就地编辑。
【解决方案2】:

awk 来救援!

sed 是基于行的,这应该可以工作...

$ awk 's{if(/\s*-\s*"[^"]*"/) next; else s=0} /kafka.brokers:/{s=1}1' file

说明

if(/\s*-\s*"[^"]*"/) next 如果模式匹配跳到下一行
s{if(/\s... 如果只设置了 s,则检查模式
/kafka.brokers:/{s=1} 当看到标题设置 s
1 打印行的简写(如果没有跳过)
s{... else s=0} 如果设置了 s 但未找到模式,则重置 s

【讨论】:

  • 您能解释一下这是如何工作的吗?我可能需要稍微修改一下才能使用它。
  • 顺便说一句,我在上面提供的示例中尝试了您的解决方案,但它不起作用。
  • 它不起作用 描述性不是很好...没有打印?什么都没有过滤?删除了输入文件?
  • 它按原样打印内容,即没有做任何更改。
  • Explanation 了解为什么 1 会打印该行。
【解决方案3】:

正如其他人指出的那样,您需要明确地让 sed 使用多行。

真正的答案是使用AWK a beautiful answer is provided by karakfa。但出于教育目的,我将提供一个 sed 答案:

sed  '
  /kafka.brokers/ {
    :a
    $be
    N
    /\n[[:space:]]*-[[:space:]]"[^\n]*"[^\n]*$/ba
    s/\n.*\(\n\)/\1/
    P;D
    :e
    s/\n.*//
  }
' input

kafka.brokers 直到\n[[:space:]]*-[[:space:]]"[^\n]*"[^\n]*$ 不匹配时,sed 基本上会将追加行保留到模式空间。

这将在模式空间中留下一条尾随行,即:

kafka.brokers:\n    - "node003"\n    - "node004"\nother stuff$

用换行符替换所有 \n.*\(\n\) 会留下以下模式空间:

kafka.brokers:\nother stuff$

P;D 将从模式空间打印第一行,然后使用剩余的模式空间重新开始循环。制作输入支持:

kafka.brokers:
    - "node003"
    - "node004"
kafka.brokers:
    - "node005"
more_input

【讨论】:

    【解决方案4】:

    考虑使用yq 而不是sedawk。删除密钥kafka.brokers 然后变得很简单:

    yq d $CONF_BENCHMARK/config.yaml '"kafka.brokers"'
    

    以下 sn-p 演示了yq 删除功能:

    cat <<EOF | yq d - '"kafka.brokers"'    
    some:
      path: value
    kafka.brokers:
      - "node003"
      - "node004"
    EOF
    

    ... 输出结果

    some:
      path: value
    

    【讨论】:

      猜你喜欢
      • 2022-07-12
      • 2020-12-14
      • 2011-05-26
      • 2020-12-22
      • 2015-06-13
      • 2021-12-18
      • 2012-09-23
      相关资源
      最近更新 更多