簡體   English   中英

AWK 多次更改字段分隔符

[英]AWK change field separator multiple times

我在下面有以下示例代碼; 為了便於測試,我將幾個文件的文本合並為一個。 通常此腳本會使用find命令過濾每個子目錄以查找versions.tf並在每個子目錄上運行 AWK。

terraform {
  required_providers {
    azurerm = {
      source  = "hashicorp/azurerm"
      version = "> 2.0.0"
    }
  }
  required_version = ">= 0.13"
}


terraform {
  required_providers {
    luminate = {
      source  = "terraform.example.com/nbs/luminate"
      version = "1.0.8"
    }
    azurerm = {
      source  = "hashicorp/azurerm"
      version = "2.40.0"
    }
    random = {
      source = "hashicorp/random"
    }
    template = {
      source = "hashicorp/template"
    }
  }
  required_version = ">= 0.13"
}

terraform {
  required_providers {
    azurerm = {
      source  = "hashicorp/azurerm"
      version = ">=2.38.0, < 3.0.0"
    }
    luminate = {
      source  = "terraform.example.com/nbs/luminate"
      version = "1.0.8"
    }
    random = {
      source  = "hashicorp/random"
      version = "3.0.0"
    }
    null = {
      source  = "hashicorp/null"
      version = "3.0.0"
    }
  }
  required_version = ">= 0.13"
}

我原來的 AWK 腳本如下所示:

/^[[:space:]]{2,2}required_providers/,/^[[:space:]]{2,2}}$/ {
    gsub("\"", "")
    if ($0 ~ /[[:alpha:]][[:space:]]=[[:space:]]\{/) {
        pr = $1
    }
    if ($0 ~ /version[[:space:]]=[[:space:]]/) {
        printf("%s %s\n", pr, $3)
    }
}

這將打印出以下內容:

azurerm >           # note this
luminate 1.0.8
azurerm 2.40.0
azurerm >=2.38.0,   # note this
luminate 1.0.8
random 3.0.0
null 3.0.0

當人們向 repo 提交代碼時, versions行通常不會在"之間包含空格,我會很好,但最近情況並非如此。因此我的腳本在上面提到的兩行上搞砸了。

我在一本書中注意到我一直在閱讀可以在腳本中多次更改字段分隔符的地方 ( https://www.packtpub.com/product/learning-awk-programming/9781788391030 ):

Now, to switch between two different FS, we can perform the following:

$ vi fs1.awk
{
if ($1 == "#entry")
{ FS=":"; }
else if ($1 == "#exit")
{ FS=" "; }
else
{ print $2 }
}

我已經在我的腳本中嘗試過這個,但它不起作用。 我只能假設這是因為我試圖在嵌套函數中執行切換?

/^[[:space:]]{2,2}required_providers/,/^[[:space:]]{2,2}}$/ {
    if ($0 ~ /[[:alpha:]][[:space:]]=[[:space:]]\{/) {
        FS = " "
        pr = $1
    }
    if ($0 ~ /version[[:space:]]=[[:space:]]/) {
        FS = "\""
        printf("%s %s\n", pr, $2)
    }
}

輸出如下:

azurerm =
luminate =
azurerm =
azurerm =
luminate =
random =
null =

任何人都可以建議用於捕獲/打印 output 的修復/解決方法,因此它看起來像:

azurerm > 2.0.0
luminate 1.0.8
azurerm 2.40.0
azurerm >=2.38.0, < 3.0.0
luminate 1.0.8
random 3.0.0
null 3.0.0

更改FS不會立即生效,請考慮如果file.txt內容是

1-2-3
4-5-6

然后

awk '(NR==1){FS="-"}{print NF}' file.txt

output

1
3

如您所見,從下一行開始應用了新的FS 如果您需要像FS那樣在當前行中拆分,請考慮使用拆分function,例如對於與上述相同的文件輸入

awk '{split($0,arr,"-");print arr[1],arr[2],arr[3]}' file.txt

output

1 2 3
4 5 6

(在 gawk 4.2.1 中測試)

一個更簡單的解決方案是將您提取的值標准化。 您已經在使用正則表達式; 把它拉遠一點。

/^[[:space:]]{2}required_providers/,/^[[:space:]]{2}}$/ {
    gsub("\"", "")
    if ($0 ~ /[[:alpha:]][[:space:]]=[[:space:]]\{/) {
        pr = $1
    }
    if ($0 ~ /version[[:space:]]*[<>=]+[[:space:]]*/) {
        ver = $0;
        sub(/^[[:space:]]*version[[:space:]]*(=[[:space:]]*)?/, "", ver);
        print pr, ver
    }
}

切線地,請注意我是如何放寬空格要求的,並將{2,2}替換為等效但更簡潔的{2}

僅使用您顯示的示例,您能否嘗試以下操作。 在 GNU awk中編寫和測試。

awk '
!NF{
  found1=found2=0
  val=""
}
/required_providers/{
  found1=1
  next
}
found1 && /^[[:space:]]+[[:alpha:]]+ = {/{
  sub(/^ +/,"",$1)
  val=$1
  found2=1
  next
} found2 && /version/{
  match($0,/".*"/)
  print val,substr($0,RSTART+1,RLENGTH-2)
  found2=0
}
'  Input_file

說明:為上文添加詳細說明。

awk '                        ##Starting awk program from here.
!NF{                         ##checking condition if NF is NULL then do following.
  found1=found2=0            ##Setting found1 and found2 to 0 here.
  val=""                     ##Nullifying val here.
}
/required_providers/{        ##Checking if line has required_providers then do following.
  found1=1                   ##Setting found1 to 1 here.
  next                       ##next will skip all further statements from here.
}
found1 && /^[[:space:]]+[[:alpha:]]+ = {/{  ##Checking if found1 is set and line has spaces and alphabets followed by = { then do following.
  sub(/^ +/,"",$1)           ##Substituting initial spaces with NULL here in first field.
  val=$1                     ##Setting $1 to val here.
  found2=1                   ##Setting found2 here.
  next                       ##next will skip all further statements from here.
} found2 && /version/{       ##Checking condition if found2 is set and line has version in it.
  match($0,/".*"/)           ##Using match to match regex from " to till " here.
  print val,substr($0,RSTART+1,RLENGTH-2)  ##Printing val and sub string of matched values.
  found2=0                   ##Setting found2 to 0 here.
}
' Input_file                 ##Mentioning Input_file name here. 

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM