【问题标题】:AWK print block that does NOT contain specific text不包含特定文本的 AWK 打印块
【发布时间】:2021-03-23 06:17:54
【问题描述】:

我有以下数据文件:

variable "ARM_CLIENT_ID" {
  description = "Client ID for Service Principal"
}

variable "ARM_CLIENT_SECRET" {
  description = "Client Secret for Service Principal"
}

# [.....loads of code]

variable "logging_settings" {
  description = "Logging settings from TFVARs"
}

variable "azure_firewall_nat_rule_collections" {
  default = {}
}

variable "azure_firewall_network_rule_collections" {
  default = {}
}

variable "azure_firewall_application_rule_collections" {
  default = {}
}

variable "build_route_tables" {
  description = "List of Route Table keys that need direct internet prior to Egress FW build"
  default = [
    "shared_services",
    "sub_to_afw"
  ]
}

我想做两件事:

  • 打印不带引号的变量名
  • 仅在代码块不包含 default 时打印变量名称

我知道我可以像这样打印变量名称:awk '{ gsub("\"", "") }; (/variable/ && $2 !~ /^ARM_/) { print $2}'

我知道我可以打印代码块:awk '/variable/,/^}/',结果:

# [.....loads of code output before this]

variable "logging_settings" {
  description = "Logging settings from TFVARs"
}
variable "azure_firewall_nat_rule_collections" {
  default = {}
}
variable "azure_firewall_network_rule_collections" {
  default = {}
}
variable "azure_firewall_application_rule_collections" {
  default = {}
}
variable "build_route_tables" {
  description = "List of Route Table keys that need direct internet prior to Egress FW build"
  default = [
    "shared_services",
    "sub_to_afw"
  ]
}

但是,我不知道如何打印代码块“如果”它们不包含default。我知道我需要使用 if 语句,也许还有一些变量,但我不确定如何使用。

此代码块不应出现在我为其获取变量名的输出中:

variable "build_route_tables" {
  description = "List of Route Table keys that need direct internet prior to Egress FW build"
  default = [
    "shared_services",
    "sub_to_afw"
  ]
}

最终输出不应包含那些具有default:

# [.....loads of code output before this]
expressroute_settings
firewall_settings
global_settings
peering_settings
vnet_transit_object
vnet_shared_services_object
route_tables
logging_settings

最好我想保留一个单独的 AWK 命令或文件,没有管道。我对此有一些不喜欢管道的用途。

EDIT:更新理想输出(遗漏了一些带有default的示例)

【问题讨论】:

  • 为什么azure_firewall_application_rule_collections 在输出中?代码块有default = {}
  • 如果记录与正则表达式不匹配,条件!/regexp/将为真。
  • @Barmar;好的,我如何使用它来消除我不想要的块?
  • 如果您只打印满足该条件的块,您将消除其他块。
  • 请更新预期输出以匹配样本输入(例如,expressroute_settings 不在样本输入中,但在预期输出中...??

标签: bash awk


【解决方案1】:

使用 GNU awk:

awk -v RS="}" '/variable/ && !/default/ && !/ARN/ { var=gensub(/(^.*variable ")(.*)(".*{.*)/,"\\2",$0);print var }' file

将记录分隔符设置为“}”,然后检查包含“变量”、不包含默认值和不包含“ARM”的记录。使用 gensub 根据正则表达式将字符串拆分为三段,并将变量 var 设置为第二段。打印 var 变量。

输出:

logging_settings

【讨论】:

  • 最后 3 行不应出现在输出中,因为它们有 default
  • 我不认为他想要 ARM 条目,所以它只是 logging_settings
【解决方案2】:
$ awk -v RS= '!/default =/{gsub(/"/,"",$2); print $2}' file

ARM_CLIENT_ID
ARM_CLIENT_SECRET
[.....loads
logging_settings

当然输出与您的不匹配,因为它与输入数据不一致。

【讨论】:

    【解决方案3】:

    OP 的问题和 cmets 的假设和笔记收集:

    • 所有变量定义块在新行的第一列以右大括号 (}) 结尾
    • 我们只显示variable 名称(不包括双引号)
    • 如果变量定义的主体包含字符串default,我们不会显示variable 名称
    • 如果variable 名称以字符串ARM_ 开头,我们不会显示它

    一个(有点冗长)awk 解决方案:

    注意:我已将示例输入数据复制到我的本地文件variables.dat

    awk -F'"' '                                              # use double quotes as the input field separator
    /^variable / && $2 !~ "^ARM_"  { varname = $2            # if line starts with "^variable ", and field #2 is not like "^ARM_", save field #2 for later display
                                     printme = 1             # enable our print flag
                                   }
    /variable/,/^}/                { if ( $0 ~ "default" )   # within the range of a variable definition, if we find the string "default" ...
                                        printme = 0          # disable the print flag
                                     next                    # skip to next line
                                   }
    printme                        { print varname           # if the print flag is enabled then print the variable name and then ...
                                     printme = 0             # disable the print flag
                                   }
    ' variables.dat
    

    这会生成:

    logging_settings
    

    【讨论】:

    • 昨晚忘了说“谢谢”,这对我很有帮助,让我对 awk 功能有了更深入的了解
    【解决方案4】:

    awk 的另一个变体使用skip 变量来控制保存变量名称的数组索引:

    awk '
        /^[[:blank:]]*#/ { next }
        $1=="variable"   { gsub(/["]/,"",$2); vars[skip?n:++n]=$2; skip=0 } 
        $1=="default"    { skip=1 }
        END { if (skip) n--; for(i=1; i<=n; i++) print vars[i] }
    ' code
    

    第一条规则只是跳过注释行。如果你想跳过"ARM_"变量,那么你可以在$2上添加一个测试。

    使用/输出示例

    使用code 中的示例代码,所有没有default 的变量都是:

    $ awk '
    >     /^[[:blank:]]*#/ { next }
    >     $1=="variable"   { gsub(/["]/,"",$2); vars[skip?n:++n]=$2; skip=0 }
    >     $1=="default"    { skip=1 }
    >     END { if (skip) n--; for(i=1; i<=n; i++) print vars[i] }
    > ' code
    ARM_CLIENT_ID
    ARM_CLIENT_SECRET
    logging_settings
    

    【讨论】:

      【解决方案5】:

      这是另一个可能更短的解决方案。

      $ awk -F'"' '/^variable/&&$2!~/^ARM_/{v=$2} /default =/{v=0} /}/&&v{print v; v=0}' file
      logging_settings
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2015-11-29
        • 2020-06-24
        • 1970-01-01
        • 2021-06-05
        • 2015-03-25
        • 2013-10-15
        • 2023-04-09
        • 1970-01-01
        相关资源
        最近更新 更多