2017-05-12 2 views
4

파일을 구문 분석하여 각 행에 다차원 배열을 채우는 Awk/Gawk 스크립트를 작성하고 있습니다. 첫 번째 열은 마침표로 구분 된 문자열이며 각 값은 다음 수준의 배열 키에 대한 참조입니다.다차원 awk 배열을 동적으로 채우기

data["personal"]["name"]["first"]  = "John" 
data["personal"]["name"]["last"]  = "Doe" 
data["personal"]["other"]["dob"]  = "05/07/87" 
data["personal"]["contact"]["phone"] = "602123456" 
data["personal"]["contact"]["email"] = "[email protected]" 
data["employment"]["jobs"]["1"]  = Company One 
data["employment"]["jobs"]["2"]  = Company Two 
data["employment"]["jobs"]["3"]  = Company Three 
: 구문 분석 후, 필자는 그것을 기대

$ echo -e "personal.name.first\t= John\npersonal.name.last\t= Doe\npersonal.other.dob\t= 05/07/87\npersonal.contact.phone\t= 602123456\npersonal.contact.email\t= [email protected]\nemployment.jobs.1\t= Company One\nemployment.jobs.2\t= Company Two\nemployment.jobs.3\t= Company Three" 
personal.name.first  = John 
personal.name.last  = Doe 
personal.other.dob  = 05/07/87 
personal.contact.phone = 602123456 
personal.contact.email = [email protected] 
employment.jobs.1  = Company One 
employment.jobs.2  = Company Two 
employment.jobs.3  = Company Three 

과 같은 구조를 가지고 : 제 2 열은 같은 여기에 콘텐츠를 구문 분석되고 무엇의 예 보입니다의 값

입니다

내가 붙어있는 부분은 동적으로 다차원 배열을 구조화하는 동안 키를 채우는 방법입니다.

나는 처음에는 내가 필요에 따라 작동하는 것처럼 보였던 SUBSEP 변수를 사용하여 해결 된 유사한 문제를 다루고 this SO thread을 찾았지만, 몇 가지 테스트 후에는 arr["foo", "bar"] = "baz"처럼 취급되지 않습니다 보인다 실제 배열은 arr["foo"]["bar"] = "baz"과 같습니다. 내가 그 무슨 뜻의 예는 배열의 모든 수준의 값을 계산 할 수 없다는 것 : arr["foo", "bar"] = "baz"; print length(arr["foo"]) 단순히 인쇄 것 0 (영)

나는 아마도 오른쪽 나를 가리키는 조금 도움이 this SO thread 발견 방향. 언급 된 스레드에서 코드 조각에서

:

BEGIN { 
    x=SUBSEP 

    a="Red" x "Green" x "Blue" 
    b="Yellow" x "Cyan" x "Purple" 

    Colors[1][0] = "" 
    Colors[2][0] = "" 

    split(a, Colors[1], x) 
    split(b, Colors[2], x) 

    print Colors[2][3] 
} 

은 아주 가까이,하지만 지금 데 문제가 키 (예 : Red, Green 등)이 있다는 사실이다 지정해야 동적으로 하나 이상의 키가있을 수 있습니다. 기본적으로

는 어떻게

BEGIN { 
    x=SUBSEP 

    # How can I take these strings... 
    a_keys = "Red.Green.Blue" 
    b_keys = "Yellow.Cyan.Purple" 

    # .. And populate the array, just as this does: 
    a="Red" x "Green" x "Blue" 
    b="Yellow" x "Cyan" x "Purple" 

    Colors[1][0] = "" 
    Colors[2][0] = "" 

    split(a, Colors[1], x) 
    split(b, Colors[2], x) 

    print Colors[2][3] 
} 

어떤 도움을 주시면 감사하겠습니다 ..의 a_keysb_keys 문자열을 .별로 분할하고,? 다차원 배열로 ab 변수를 채울 수 있습니다, 감사합니다!

답변

1

당신이 필요가 :

BEGIN { FS="\t= " } 
{ 
    split($1,d,/\./) 
    data[d[1]][d[2]][d[3]] = $2 
} 

봐 :

$ cat tst.awk 
BEGIN { FS="\t= " } 
{ 
    split($1,d,/\./) 
    data[d[1]][d[2]][d[3]] = $2 
} 
END { 
    for (x in data) 
     for (y in data[x]) 
      for (z in data[x][y]) 
       print x, y, z, "->", data[x][y][z] 
} 

$ awk -f tst.awk file 
personal other dob -> 05/07/87 
personal name first -> John 
personal name last -> Doe 
personal contact email -> [email protected] 
personal contact phone -> 602123456 
employment jobs 1 -> Company One 
employment jobs 2 -> Company Two 
employment jobs 3 -> Company Three 

위는 둔한 특정 물론 다른 AWK는 진정한 멀티 차원 배열을 지원하지 않기 때문에이다. 인덱스가 동일한 깊이 (예를 들어, 상기 3)의 경우 항상하지

이 다차원 어레이를 채우기 위해 오히려 더 복잡 :

########## 
$ cat tst.awk 
function rec_populate(a,idxs,curDepth,maxDepth,tmpIdxSet) { 
    if (tmpIdxSet) { 
     delete a[SUBSEP]    # delete scalar a[] 
     tmpIdxSet = 0 
    } 
    if (curDepth < maxDepth) { 
     # We need to ensure a[][] exists before calling populate() otherwise 
     # inside populate() a[] would be a scalar, but then we need to delete 
     # a[][] inside populate() before trying to create a[][][] because 
     # creating a[][] below creates IT as scalar. SUBSEP used arbitrarily. 

     if (!((idxs[curDepth] in a) && (SUBSEP in a[idxs[curDepth]]))) { 
      a[idxs[curDepth]][SUBSEP] # create array a[] + scalar a[][] 
      tmpIdxSet = 1 
     } 
     rec_populate(a[idxs[curDepth]],idxs,curDepth+1,maxDepth,tmpIdxSet) 
    } 
    else { 
     a[idxs[curDepth]] = $2 
    } 
} 

function populate(arr,str,sep, idxs) { 
    split(str,idxs,sep) 
    rec_populate(arr,idxs,1,length(idxs),0) 
} 

{ populate(arr,$1,",") } 

END { walk_array(arr, "arr") } 

function walk_array(arr, name,  i) 
{ 
    # Mostly copied from the following URL, just added setting of "sorted_in": 
    # https://www.gnu.org/software/gawk/manual/html_node/Walking-Arrays.html 
    PROCINFO["sorted_in"] = "@ind_str_asc" 
    for (i in arr) { 
     if (isarray(arr[i])) 
      walk_array(arr[i], (name "[" i "]")) 
     else 
      printf("%s[%s] = %s\n", name, i, arr[i]) 
    } 
} 

.실제 multidim 배열없이

########## 
$ cat file 
a uno 
b,c dos 
d,e,f tres_wan 
d,e,g tres_twa 
d,e,h,i,j cinco 

########## 
$ awk -f tst.awk file 
arr[a] = uno 
arr[b][c] = dos 
arr[d][e][f] = tres_wan 
arr[d][e][g] = tres_twa 
arr[d][e][h][i][j] = cinco 
+0

나랑 같이 일해. 감사! – Justin

+0

그러면 내가 게시 한 두 번째 솔루션이 필요합니다. 명백한 진술 - 실제 데이터에 여러 등급의 세그먼트가있는 경우 샘플 입력 역시 포함되어야합니다. –

0

, 당신은 좀 더 부기를 할 수

awk -F'\t= ' '{split($1,k,"."); 
       k1[k[1]]; k2[k[2]]; k3[k[3]]; 
       v[k[1],k[2],k[3]]=$2} 
      END {for(i1 in k1) 
       for(i2 in k2) 
        for(i3 in k3) 
        if((i1,i2,i3) in v) 
         print i1,i2,i3," -> ",v[i1,i2,i3]}' file 


personal other dob -> 05/07/87 
personal name first -> John 
personal name last -> Doe 
personal contact email -> [email protected] 
personal contact phone -> 602123456 
employment jobs 1 -> Company One 
employment jobs 2 -> Company Two 
employment jobs 3 -> Company Three 
내가 키가 항상 정확히 3 개의 세그먼트하지 않을 수 있음을 언급 잊어 버린 수 있습니다 ..하지만이 충분히에 대한 시작할 좋은