【问题标题】:Using AWK to match the first expression, if it exists find next pattern, then insert使用 AWK 匹配第一个表达式,如果存在则查找下一个模式,然后插入
【发布时间】:2021-10-28 03:12:12
【问题描述】:

我有以下 sn-p 文件,dbScripts/product.js:

db.ShoppingCart.update(
    { 'identifier': 'COFFEE' },
    {
      'name': 'Coffee',
      'identifier': 'COFFEE',
      'category': 'Beverages',
      'type': [
        {
          'name': 'Rage',
          'identifier': 'COFFEE_RAGE',
          'desc':
            'Coffee by Rage'
        },
        {
            'name': 'Sleepy Owl',
            'identifier': 'COFFEE_SLEEPY_OWL',
            'desc':
              'Coffee by Sleepy Owl'
        }
      ]
    },
    { upsert: true }
); 

我希望先匹配 {'identifier': 'COFFEE'},如果存在,然后再寻找下一个后续模式 'type': [

如果两个条件都满足,代码应该为其他咖啡品牌插入类似的对象。但是,如果输入的标识符不是咖啡,它将为其创建整个结构。 【后半部分已经完成】。

FILE_PATH="./dbScripts/products.js"
# example, COFFEE
echo "Enter product"
read -r PRODUCT_NAME

DESCRIPTION="Coffee by Nescafe"
IDENTIFIER="COFFEE_NESCAFE"

FOUND=$(awk -v ITEM="{ \'identifier\': \'${PRODUCT_NAME}\' }" 'BEGIN {FOUND=0}/ITEM/{++FOUND} END {print FOUND+0}' "${FILE_PATH}")
        echo ${FOUND}
        if [ ${FOUND} -eq 1 ]; then
            SCRIPT_TEMPLATE="./AutomationUtil/object.tpl"
            local SCRIPT=$(eval "echo \"$(cat "${SCRIPT_TEMPLATE}")\"")
            awk -v text="${SCRIPT}" '1;/'type': | 'types': /{printf text}' "${FILE_PATH}" > "${FILE_PATH}_tmp" && mv "${FILE_PATH}_tmp" "${FILE_PATH}"
        fi

我正在尝试使用 awk-variable FOUND 作为标志来检查是否找到了模式。当且仅当 FOUND=1

时,继续下一个模式

对象.tpl

{'name': '${PRODUCT_NAME}','identifier': '${PRODUCT_IDENTIFIER}','desc':'${DESCRIPTION}'},

因此,如果找到两个后续模式,则将评估并插入上述模板。如果没有,来自 dbScripts/product.js 的整个对象结构将在文件末尾创建,例如,用户输入 Tea 而不是 Coffee。

在下面的示例中,用户输入 COFFEE 作为标识符,它与我们的第一个模式 {'identifier': 'COFFEE'} 匹配,然后它找到行,'type': [,并在其下方插入评估的 Object.tpl .

预期输出:

    db.ShoppingCart.update(
            { 'identifier': 'COFFEE' },
            {
              'name': 'Coffee',
              'identifier': 'COFFEE',
              'category': 'Beverages',
              'type': [
                {
                  'name': 'Nescafe',
                  'identifier': 'COFFEE_NESCAFE',
                  'desc':
                    'Coffee by Nesafe'
                },
                {
                  'name': 'Rage',
                  'identifier': 'COFFEE_RAGE',
                  'desc':
                    'Coffee by Rage'
                },
                {
                    'name': 'Sleepy Owl',
                    'identifier': 'COFFEE_SLEEPY_OWL',
                    'desc':
                      'Coffee by Sleepy Owl'
                }
              ]
            },
            { upsert: true }
        );

  db.ShoppingCart.update(
            { 'identifier': 'NOODLES' },
            {
              'name': 'Noodles',
              'identifier': 'NOODLES',
              'category': 'Instant Food',
              'type': [
                {
                  'name': 'Ramen',
                  'identifier': 'NOODELS_RAMEN',
                  'desc':
                    'Noodles by Ramen'
                }
               ]
           }, {upsert: true}
         );

我从理论上想出了这个,但似乎无法让它发挥作用。我总是得到 FOUND=0。

我敢肯定,这段代码非常愚蠢,但感谢任何帮助。同样,为了插入对象,应该找到这两种模式。

注意:格式由 prettier 处理,因此在插入新文本时应忽略间距

我不想使用 SED,因为 MacOS 不附带 GNU-SED。

awk 版本 20200816

【问题讨论】:

  • 关于spacing can be ignored - 如果我们必须解决所有可能的空白问题,那么工作会变得更加困难,所以说间距可以被忽略是错误的思考方式这。要么间距必须被忽略,要么间距可以被依赖。哪个是正确的?
  • 考虑用足够的细节更新问题,以便我们可以在自己的环境中重现工作;特别是,提供所有$variables 的值、*tpl 文件的内容(要插入;如果文件是“大”,那么文件的较小样本就足够了),以及预期的结果;另外,请使用在您的系统上运行 awk --version 的输出更新问题
  • @EdMorton 注意到了! Prettier 正在根据其配置格式化代码。所以间距应该被忽略。
  • @markp-fuso 我已尝试详细说明并添加上下文,如果仍然缺少,请告诉我
  • 再次 - spacing should be ignored 是否意味着您需要一个不依赖于问题中间距的脚本(例如,所有输入都可能是一行)?

标签: bash macos awk


【解决方案1】:

当前代码存在一些问题,但由于主要问题似乎是分配给 (bash) 变量 FOUND 的值错误,所以我将只关注这个问题...

主要问题是测试存储在awk 变量ITEM 中的搜索模式;一个修复:

/ITEM/    {...}            # wrong
$0 ~ ITEM {...}            # fix

将其合并到 OP 的代码中,并为 INPUTFILE_PATH 插入一些值,我们得到:

FOUND=$(awk -v ITEM="{ 'identifier' : '${INPUT}' }" '$0 ~ ITEM {++FOUND} END {print FOUND+0}' product.js)
$ echo "${FOUND}"
1

注意事项:

  • 不需要转义的单引号(定义awk 变量ITEM
  • awk 变量的初始值为 0,因此不需要 BEGIN{}
  • 此解决方案假定输入具有与awk 变量ITEM 中定义的完全相同的空白

至于剩下的问题……

  • OP 的第二个awk 脚本正在寻找字符串item:items:,但示例输入中不存在这样的字符串,所以我不希望任何内容被“插入”;目前无法判断这是建议的awk 代码的错字/问题还是错误的示例输入
  • 样本Object.tpl 文件显示了一个单行元素定义,但预期输出显示此插入为多行;这个结果肯定不会由提议的(第二个)awk 脚本生成,所以不确定 OP 是否也在寻找插入换行符的awk 解决方案或...??
  • 整个 FOUND=$(awk ...); if ... awk ...;fi 代码块可能可以替换为单个 awk 脚本
  • OP 的awk 版本 (awk version 20200816) 看起来有点奇怪,所以不确定awk 的真正风格/版本或awk 的上述版本可能有什么限制(例如,OP 的@ 987654348@ 版本支持-i inplace 允许awkproduct.js 文件执行“就地”更新?)

【讨论】:

  • 到目前为止,我了解您所提到的内容。不过我想补充一下,product.js 到目前为止只有 COFFEE。但是假设它有更多的产品,所以一个完整的 db.ShoppingCart.update({'identifier': 'NOODLES'}) 或更多产品。因此,如果模式匹配标识符:COFFEE,我希望添加 object.tpl 以在 COFFEE 对象中键入。
  • 当然,我理解那部分(在COFFEE 部分下添加*tpl),但此时有很多未知数,这感觉更像是编写一个完整的脚本,而不是SO 的真正用途是……用当前代码解决特定的技术问题
  • 我明白了,不过还是谢谢你。我有一个替代选项,如果匹配“标识符:咖啡”,则在该行的第 6 行插入代码。你能指导我解决各种问题吗?这也将完成
  • 1.所以这是我的错,“项目”应该是“类型”。 2. object.tpl 是避免 \n 语法问题的一种衬里,但后来被格式化为更漂亮的格式,从而产生预期的输出。
  • awk version 20200816 是 BSD awk 所以没有 -i inplace
猜你喜欢
  • 2014-05-21
  • 2022-10-17
  • 2013-12-01
  • 2023-01-31
  • 1970-01-01
  • 2020-03-06
  • 1970-01-01
  • 1970-01-01
  • 2015-06-18
相关资源
最近更新 更多