如何使用Bash Regex Lookbehind跨越Terraform文件中的空白?

20jt8wwn  于 2023-02-10  发布在  其他
关注(0)|答案(3)|浏览(147)

我正在编写一个bash脚本来解析一堆(十几个或更多)庞大的Terraform文件,这些文件包含大量的google_bigquery_dataset资源及其关联的IAM访问块,该脚本应该获取每个数据集资源并将其复制到另一个以数据集本身命名的文件中。
除了从资源的"dataset_id"字段中提取数据集的名称之外,所有这些都是很好的。如果不是因为这些数据集资源中的一些资源拥有包含"dataset_id"值的授权视图块,这将是非常容易的。
以下是此类资源的示例:

resource "google_bigquery_dataset" "project-bigquery-dataset-RESOURCE_NAME" {
  access {
    role          = "WRITER"
    special_group = "projectWriters"
  }

  access {
    role          = "READER"
    special_group = "projectReaders"
  }

  access {
    role          = "WRITER"
    user_by_email = "user1@project.iam.gserviceaccount.com"
  }

  access {
    role          = "OWNER"
    special_group = "projectOwners"
  }

  access {
    view {
      dataset_id = "DO_NOT_WANT"
      project_id = "project"
      table_id   = "table1"
    }
  }

  access {
    view {
      dataset_id = "DO_NOT_WANT"
      project_id = "project"
      table_id   = "table2"
    }
  }

  access {
    view {
      dataset_id = "DO_NOT_WANT"
      project_id = "project"
      table_id   = "table3"
    }
  }

  dataset_id                      = "THIS_IS_WHAT_I_WANT"
  default_partition_expiration_ms = "0"
  delete_contents_on_destroy      = "false"

  labels = {
    application-name = "app-name"
  }

  location = "US"
  project  = "project"
}

在我意识到授权的视图块也有一个dataset_id字段之前,我使用这个字段来尝试获取我想要的值,假设startIndexendIndex只是表示一个完整数据集资源块的开始和结束行号,如上所示:

fileName=$( sed -n ${startIndex},${endIndex}p $bigFile | grep "dataset_id" | cut -d\" -f2)

仅当不存在包含其他dataset_id值的授权视图块时才起作用。
然后,我尝试使用消极的后视:

fileName=$( sed -n ${startIndex},${endIndex}p $bigFile | grep '(?<!view {]n)dataset_id' | cut -f1 -d\"

这不起作用。我不确定是因为换行符还是因为view {结尾和dataset_id = "DO_NOT_WANT"开头之间的空格。
我尝试过它的变体,比如(?<!view\s{\s)\s*dataset_id,但没有成功。
有没有办法只捕获不在视图块中的dataset_id
几个注意事项:
1.我可以保证view {在块中始终位于dataset_id之前,没有换行符。
1.我不能保证顺序,我尝试捕获的dataset_id可能出现在view块之前,之后,甚至在它们之间的某个地方。
1.上述示例的所需输出仅为THIS_IS_WHAT_I_WANT。如有任何帮助,将不胜感激。

vdgimpew

vdgimpew1#

对于您展示的示例,请尝试以下awk代码。在GNU awk中编写和测试。

awk -v RS= -v FS="\n" '
/^[[:space:]]+dataset_id[[:space:]]+/{
  split($1,arr,"\"")
  print arr[2]
}
'  Input_file

***说明:***完整代码的简单说明如下:

  • awk程序中将RS(记录分隔符)设置为段落模式。
  • 然后将FS(字段分隔符)设置为新行。
  • 然后在主块检查条件中,如果行从1个或多个空格开始,然后是dataset_id,再然后是1个或多个空格,如果此条件为TRUE,则:
  • 使用awksplit函数将$1(第一个字段)拆分到一个名为arr的数组中,分隔符为"。这基本上创建了一个名为arr的数组,索引为1 2 3 4,依此类推,具体取决于它根据分隔符拆分了多少个元素。
  • 然后打印OP需要输出的数组arr的第2个元素。
68bkxrlz

68bkxrlz2#

如果您的grep支持-P(PCRE)选项,请尝试以下操作。它已通过您所示的示例进行了测试。

grep -Poz '(?:^|\n)(?:(?!view).)*\n\s*dataset_id\s*=\s*"\K[^"]+' input_file

输出:

THIS_IS_WHAT_I_WANT
    • 假设**
  • 如果view {先于dataset_id,则这两个字跨越连续的两行。
    • 解释**
  • 由于我们需要检查跨行的模式匹配,因此-z选项被置于grep,以将输入视为行序列。
  • 正则表达式(?:^|\n)(?:(?!view).)*\n\s*dataset_id\s*=\s*"\K[^"]+匹配(至少)包含dataset_id的行之前的前一行中不包含单词view的两行。
  • (?:^|\n)定位线的起点,因为多行选项(?m)由于-z选项而不起作用。
  • 由于lookbehindAssert不允许可变长度匹配,我们需要使用(?:(?!view).)*作为(?<!view.*)的替代。
  • 以下\n\s*dataset_id确保viewdataset_id之间至少存在一个换行符。否则,正则表达式匹配仅包含dataset_id的单行,从而导致过度检测。
  • \K丢弃先前匹配的子字符串以将其排除在输出之外。
628mspwn

628mspwn3#

我不能保证能和你的hcl一起工作,但是可以先尝试转换成json

$ cat foo.tf | 
yj -c | 
jq  -r '.resource[].google_bigquery_dataset[][][].dataset_id'
THIS_IS_WHAT_I_WANT
THIS_IS_WHAT_I_WANT

相关问题