Bash 배열을 사용하여 테이블을 ini 파일로 변환

Bash 배열을 사용하여 테이블을 ini 파일로 변환

다음 형식의 출력 파일("inventory.list")에 문제가 있습니다.

hostname1.env1.domain   | abc  | environment1
hostname2.env1.domain   | abc  | environment1
hostname3.env2.domain   | abc  | environment2
hostname4.env2.domain   | abc  | environment2
hostname5.env1.domain   | def  | environment1
hostname6.env2.domain   | def  | environment2
(6 rows)

다른 형식으로 다른 파일에 씁니다.

[abc.environment1]
hostname1.env1.domain
hostname2.env1.domain

[abc.environment2]
hostname3.env2.domain
hostname4.env2.domain

[def.environment1]
hostname5.env1.domain

[def.environment2]
hostname6.env2.domain

abc역할은 서버에 할당 되며 def각 역할은 여러 서버를 가질 수 있을 뿐만 아니라 이름은 같지만 환경이 다른 역할을 가질 수 있습니다. 각 호스트 이름을 고유한 [role.environment] 그룹으로 나누고 추가적으로 행 개수인 파일의 마지막 줄을 완전히 제거해야 했습니다(파일은 SQL 쿼리의 출력임).

파일을 읽고, 파이프와 공백을 제거하고, 역할/환경 그룹을 할당/출력할 수 있습니다. 문제 없습니다.

#! /bin/bash
while IFS='| ' read -r certname role env; do
  printf '%s\n' "[""$role"".""$env""]"
done < "/tmp/inventory.list"

...역할/환경 그룹 이름을 깔끔하게 제공합니다.

[abc.environment1]
[abc.environment2]
[def.environment1]
[def.environment2]

그러나 각 그룹 이름 아래의 각 역할/환경 그룹에 연결된 호스트 이름을 인쇄하는 방법을 알 수 없으며 내 스크립트가 마지막 줄 수 줄을 무시하도록 만드는 방법도 알 수 없습니다. 내 역할과 환경 필드(두 번째 및 세 번째 필드)를 자체 배열에 추가로 할당한 다음 이를 참조하여 각 고유 그룹에 연결된 호스트 이름을 가져와야 하지만 지금은 어떻게 해야 할지 모르겠습니다. . 누구든지 조언을 해줄 수 있나요?

답변1

텍스트 유틸리티를 사용하여 텍스트를 처리하겠습니다.쉘 루프를 사용하여 텍스트를 처리하는 대신(여기서는 IFS=' |'귀하의 경우에는 잘 작동합니다). 좋다:

awk -F ' *[|] *' '
  NF == 3 {host[$2"."$3] = host[$2"."$3] $1 "\n"}
  END{for (i in host) print "[" i "]\n" host[i]}' < file

출품 순서는 보장되지 않습니다. GNU를 사용하여 키 기반 정렬을 awk추가합니다 .BEGIN{PROCINFO["sorted_in"] = "@ind_str_asc"}


사용 중인 RDBMS에 따라 올바른 형식으로 표시되도록 할 수도 있습니다(예:GROUP_CONCAT존재하다mysql또는string_agg포스트그레스에서).

먼저, RDBMS 쿼리 유틸리티에 출력을 후처리에 더 적합한 형식으로 지정하도록 요청할 수도 있습니다(예: 머리글, 바닥글 제거, 탭으로 구분된 값 사용).

답변2

연관 배열을 사용하여 각 역할 및 환경에 대한 인증서 이름을 저장합니다.

#! /bin/bash

unset -v envs
declare -A envs

while IFS='| ' read -r certname role env; do
    envs["$role.$env"]+="$certname"$'\n' 
done < /tmp/inventory.list

for e in "${!envs[@]}" ; do
    printf '%s\n' "[$e]" "${envs[$e]}"
done

이러한 부분을 정렬하려면 키를 인쇄하고 정렬한 다음 다시 읽고 관련 값을 출력하면 됩니다.

for e in "${!envs[@]}" ; do
    printf '%s\n' "$e"
done | sort | while read -r e ; do
    printf '%s\n' "[$e]" "${envs[$e]}"
done

답변3

펄 매직:

$ perl -lne '@F=split(/\s*\|\s*/); push @{$k{"$F[1].$F[2]"}},$F[0]; 
     END{foreach (keys(%k)){print "[$_]"; print join "\n",@{$k{$_}}} }' file
[abc.environment1]
hostname1.env1.domain
hostname2.env1.domain
[def.environment1]
hostname5.env1.domain
[abc.environment2]
hostname3.env2.domain
hostname4.env2.domain
[def.environment2]
hostname6.env2.domain

답변4

awk를 사용하는 한 가지 방법:

$ sed 's/ //g' file | awk -F"|" '{x="["$2"."$3"]";}!(x in a){print x;a[x];}{print $1}'

관련 정보