CamiloSan

hcl sort

Jan 9th, 2026
5,734
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Awk 2.78 KB | None | 0 0
  1. #!/usr/bin/env -S gawk -f
  2. # https://gist.github.com/yermulnik/7e0cf991962680d406692e1db1b551e6
  3. # Tested with GNU Awk 5.1.0, API: 3.0 (GNU MPFR 4.1.0, GNU MP 6.2.1)
  4. # Usage: /path/to/tf_vars_sort.awk < variables.tf | tee sorted_variables.tf
  5. # Note: "chmod +x /path/to/tf_vars_sort.awk" before use
  6. # No licensing; [email protected], 2021-2024
  7. {
  8.     # skip blank lines at the beginning of file
  9.     if (!resource_type && length($0) == 0) next
  10.  
  11.     # pick only known Terraform resource definition block types of the 1st level
  12.     # https://github.com/hashicorp/terraform/blob/main/internal/configs/parser_config.go#L92-L230
  13.     switch ($0) {
  14.         # ex: block_type {
  15.         case /^[[:space:]]*(import|locals|moved|removed|terraform)[[:space:]]+{/:
  16.             resource_type = $1
  17.             resource_ident = resource_type "|" block_counter++
  18.             break
  19.         # ex: block_type type_label name_label {
  20.         case /^[[:space:]]*(data|ephemeral|resource)[[:space:]]+("?[[:alnum:]_-]+"?[[:space:]]+){2}{/:
  21.             resource_type = $1
  22.             resource_subtype = $2
  23.             resource_name = $3
  24.             resource_ident = resource_type "|" resource_subtype "|" resource_name
  25.             break
  26.         # ex: block_type name_label {
  27.         case /^[[:space:]]*(check|module|output|provider|variable)[[:space:]]+"?[[:alnum:]_-]+"?[[:space:]]+{/:
  28.             resource_type = $1
  29.             resource_name = $2
  30.             resource_ident = resource_type "|" resource_name
  31.             break
  32.     }
  33.     arr[resource_ident] = arr[resource_ident] ? arr[resource_ident] RS $0 : $0
  34. } END {
  35.     # exit if there was solely empty input
  36.     # (input consisting of multiple empty lines only, counts in as empty input too)
  37.     if (length(arr) == 0) exit
  38.     # declare empty array (the one to hold final result)
  39.     split("", res)
  40.     # case-insensitive string operations in this block
  41.     # (primarily for the `asort()` call below)
  42.     IGNORECASE = 1
  43.     # sort by `resource_ident` which is a key in our case
  44.     asort(arr)
  45.  
  46.     # blank-lines-fix each block
  47.     for (item in arr) {
  48.         split(arr[item],new_arr,RS)
  49.  
  50.         # remove multiple blank lines at the end of resource definition block
  51.         while (length(new_arr[length(new_arr)]) == 0) delete new_arr[length(new_arr)]
  52.  
  53.         # add one single blank line at the end of the resource definition block
  54.         # so that blocks are delimited with a blank like to align with TF code style
  55.         new_arr[length(new_arr)+1] = RS
  56.  
  57.         # fill resulting array with data from each resource definition block
  58.         for (line in new_arr) {
  59.             # trim whitespaces at the end of each line in resource definition block
  60.             gsub(/[[:space:]]+$/, "", new_arr[line])
  61.             res[length(res)+1] = new_arr[line]
  62.         }
  63.     }
  64.  
  65.     # ensure there are no extra blank lines at the beginning and end of data
  66.     while (length(res[1]) == 0) delete res[1]
  67.     while (length(res[length(res)]) == 0) delete res[length(res)]
  68.  
  69.     # print resulting data to stdout
  70.     for (line in res) {
  71.         print res[line]
  72.     }
  73. }
  74.  
Advertisement