awk를 사용하여 파일에서 행렬을 읽고 bash 스크립트에 선언된 2D 배열(행렬)에 할당하는 방법

awk를 사용하여 파일에서 행렬을 읽고 bash 스크립트에 선언된 2D 배열(행렬)에 할당하는 방법

echo내 행렬의 요소를 인쇄할 때 문제가 있습니다. 첫 번째 루프에서 주석 처리를 제거하면 echo ${matrix[$i,$j]}프로그램이 제대로 작동하지만 두 번째 루프에서 인쇄하려고 하면 ${matrix[$i,$j]}출력이 null 문자입니다. 목표는 파일에서 행렬을 읽고 스크립트에 선언된 행렬을 내 행렬에 할당하는 것입니다.

function readMatrixFromFile() {
        local file="$1"
        declare -A matrix
        local num_rows=$(awk 'NR==1 {print $3}' $1)
        local num_colums=$(awk 'NR==2 {print $3}' $1)

        for ((i=3;i<=num_rows+2;i++)) do
                for ((j=1;j<=num_colums;j++)) do
                        k=i-2
                        matrix[$k,$j]=$(awk -v row=$i -v col=$j 'NR==row {print $col}' $file)
                        #echo ${matrix[$i,$j]}
                done
        done


        for ((i=1;i<=num_rows;i++)) do
               for ((j=1;j<=num_colums;j++)) do
                       echo ${matrix[$i,$j]}
               done
               echo
        done

}

function Main() {
        readMatrixFromFile Matrix3.txt
}

Main

이것은 Matrix3.txt입니다.

여기에 이미지 설명을 입력하세요.

출력은 다음과 같습니다.

여기에 이미지 설명을 입력하세요.

답변1

#!/bin/bash                                                                                                           

declare -A m

read_matrix() {
    local i=0
    local line
    local j
    # Ignore the first 2 lines containing size of the matrix
    read rows
    read cols
    while read -r line; do
        j=0
        # split on spaces
        for v in `echo $line`; do
            m[$i,$j]="$v"
            j=$((j+1))
        done
        i=$((i+1))
    done
}

read_matrix < matrix.file

echo ${m[1,2]}

답변2

나는 이것이 지역 변수 범위 지정과 전역 변수 범위 지정 문제인 것으로 생각합니다.

데이터를 추출하려고 할 때 유사한 "빈" 배열을 발견했지만 함수 내부에 선언된 배열의 내용은 함수 내에서 정의했기 때문에 함수 내에서만 검색할 수 있다고 판단했습니다(원본 게시물에서는 이것이 정확히 내 상황임을 보여주었습니다).

참고: 스크립트의 MAIN 섹션 앞에 함수를 배치할 수 있으며 그 사용은 아래의 함수 호출과 연결되어 있으므로 문제가 되지 않습니다.

BASH 스크립트의 주요 부분에 있는 루프 내에서 조작할 수 있도록 데이터 테이블을 2D 배열로 로드합니다. 위의 내용이 함수 정의 범위 내에 완전히 포함되어 있으므로 아래의 내용이 위의 내용보다 먼저 실행됩니다.

#!/bin/bash

echo "Let's first define the function before the Main Body of Script"

function DEFINESCOPE {

    for ((Row=1;Row<=num_rows;Row++)) 
    do

      for ((Col=1;Col<=num_columns;Col++)) 
      do

        RowData=`cat $STATSFile | head -${Row} | tail -1 | awk -v c1=$Col -F\, '{print $c1}' | sed -e 's/"//g'`

        matrix[$Row,$Col]=$RowData

        echo "Checking to see if the loaded data can be pulled: Matrix[$Row,$Col] = ${matrix[$Row,$Col]}"

     done

   done
} 

echo "End of Function DEFINESCOPE"

echo "Start of MAIN part of script"

STATSFile="STATSFile"
cat $STATSFile
declare -A matrix

echo "THIS IS THE FUNCTION CALL WHERE THE DATA IS LOADED per the above code"

DEFINESCOPE

echo "NOW TO PULL THE DATA WHILE IN THE MAIN PART OF THE SCRIPT"

echo "In this case I want to start by skipping over the first 3 columns and then walk the rows for each column"

StartRow="1"
StartCol="4"
Row=$StartRow
Col=$StartCol

for ((Col=${StartCol};Col<=num_columns;Col++)) 
do
    Row=$StartRow
    echo "Current Position: Matrix[$Row,$Col] = ${matrix[${Row},${Col}]}"
    ReportType=${matrix[$Row,$Col]}

    echo "============================================="
    echo "Walking NEW Report Type: $ReportType"
    for ((Row=${StartRow};Row<=num_rows;Row++)) 
    do

        echo "Using a CASE statement instead of a bunch of if.then.else.fi..."
        echo "Pull Metric Data for C/H/M/L Severity Row Counts"
        echo "Determine which type of row we're examining and then assign values"

         case "${matrix[$Row,1]}" in
             Critical)
                 Criticals=${matrix[$Row,$Col]}
                 echo "Setting Severity Count for Criticals: $Criticals"
                 ;;
             Highs)
                 Highs=${matrix[$Row,$Col]}
                 echo "Setting Severity Count for Highs: $Highs"
                 ;;
             Mediums)
                 Mediums=${matrix[$Row,$Col]}
                 echo "Setting Severity Count for Mediums: $Mediums"
                 ;;
             Lows)
                 Lows=${matrix[$Row,$Col]}
                 echo "Setting Severity Count for Lows: $Lows"
                 ;;
             *)
                 echo "Case *): Does not match: matrix[Row,1]: ${matrix[$Row,1]}"
                 ;;
         esac
         echo "Current Data Position: matrix[Row,Col]: ${matrix[$Row,$Col]}"
         echo "Current Row Position: matrix[Row,1]: ${matrix[$Row,1]}"
     done
done

echo "Thus, I moved the 'declare' statement to the main part of the bash"
echo "script, prior to the function call, loaded the data in the function," echo "and then I was then able to pull data from the array when in the main part of the script."

echo "Bottom Line: declare your array in the main part of the script, before you call a function/subroutine to load or output array data."

관련 정보