bash script2023. 10. 11. 20:01

 

반달가면 이글루에서 백업 - http://bahndal.egloos.com/631090

댓글로 질문을 받았던 문제인데, 답변이 길어서 별도의 게시물로 작성.

문제는 대략 아래와 같다. 간단한 예시로 설명한다.

my_data.txt 파일에 3개의 항목(a, b, c)들 사이의 상관 관계가 기록되어 있는데, 형식은 아래와 같다.

# my_data.txt 내용
cat my_data.txt
a b#, c:
b a#
c a, b:

각 행의 첫번째 항목(field)은 항목 명칭이다.

각 행의 두번째 항목 이후는 첫번째 항목에 대한 상관 관계 자료다. 연관성 종류에 따라 "#" 또는 ":" 기호가 추가될 수 있다. 이 자료를 2차원 테이블로 표현하는 것이 목표다. 위의 예시를 표현하면 아래와 같이 만드는 것이 결과물이다.
 
    a   b   c
   -------
a| na  #   :
b| #   na  n
c| 0   :   na

행과 열이 같은 값인 위치는 "na", 상관관계는 있으나 추가 기호가 없는 경우는 "0", 상관관계가 없는 경우는 "n"으로 표시하였다.

2차원 연관 배열(associative array)를 사용한다면 테이블의 위치를 인덱스로 사용해서 할당할 수 있을 것이다.

# 첫번째 행
x[a,a]="na"; x[a,b]="#"; x[a,c]=":"
# 두번째 행
x[b,a]="#"; x[b,b]="na"; x[b,c]="n"
...

문제는 항목의 수가 100개일 경우다. 수작업은 불가능하고 자동화해야 하는데, 아래와 같이 스크립트를 만들어 볼 수 있겠다.

# 연관 배열(associative array) a_arr 선언
declare -A a_arr

# 대상 파일 지정: my_data.txt
src_file="my_data.txt"

# a_arr의 값을 모두 "n"으로 초기화
col_names=`cat "$src_file" | cut -d' ' -f1 | tr '\n' ' '`
for init_first_idx in `echo "$col_names"`
do
  for init_second_idx in `echo "$col_names"`
  do
    a_arr[$init_first_idx,$init_second_idx]="n"
  done
done

# 파일을 한줄씩 읽어서 처리
while read -r rline
do
  first_idx=`echo "$rline" | cut -d' ' -f1`
  # 행과 열의 값이 같을 경우 "na" 설정
  a_arr[$first_idx,$first_idx]="na"
  # 상관관계 자료 처리
  for data_val in `echo "$rline" | cut -d' ' -f2-`
  do
    # the second idx 값을 알기 위해 "#", ":", "," 기호 제거(sed 활용)
    second_idx=`echo "$data_val" | sed 's/[#:,]//g'`
    # 연관 배열에 값 할당 ("#", ":", "0")
    if [[ `echo "$data_val" | grep "#" | wc -l` -eq 1 ]]
    then
      a_arr[$first_idx,$second_idx]="#"
    elif [[ `echo "$data_val" | grep ":" | wc -l` -eq 1 ]]
    then
      a_arr[$first_idx,$second_idx]=":"
    else
      a_arr[$first_idx,$second_idx]="0"
    fi
  done
done < "$src_file"

# 결과 출력
for arr_key in `echo "${!a_arr[*]}" | tr ' ' '\n' | sort`
do
  echo "a_arr[$arr_key]: ${a_arr[$arr_key]}"
done
echo " "

# 테이블 형태로 결과 출력
echo "   $col_names"
echo " -------------"
for init_first_idx in `echo "$col_names"`
do
  echo -n "$init_first_idx| "
  for init_second_idx in `echo "$col_names"`
  do
    echo -n "${a_arr[$init_first_idx,$init_second_idx]} "
  done
  echo " "
done


위 스크립트에 대한 이해에 도움이 될 만한 이전 게시물들은 아래와 같다.

텍스트 파일을 한줄씩 읽어서 작업하기

리눅스 bash 스크립트에서 연관 배열 사용하기

리눅스 bash 스크립트에서 연관 배열의 인덱스/키 출력하기

728x90
Posted by 반달가면