InfraPlatform

[셀스크립트 응용] ICONV와 SED 를 활용하여 파일의 문자셋(charset)을 변환 하는 방법

IT오이시이 2020. 11. 29. 15:01
728x90

charset_sed_convert.zip
0.01MB

 

[셀스크립트 응용] ICONV와 SED 를 활용하여 파일의 문자셋(charset)을 변환 하는 방법 (EUC-KR to UTF8)

- EUC-KR 파일을 UTF 파일로 변환 하는 방법으로 iconv 라는 명령을 사용 하는 내용입니다.

종종 오래된 프로그램 파일의 인코딩을 바꿔야 하는 경우에 사용하던 방법입니다. 하위 디렉토리 또는 많은 파일을 한꺼번에 처리하기 위해서 예전에 사용했던 방법인데 셀스크립트 작성 기초로 참고 바랍니다.  iconv라는 명령은  파일의 인코딩을 변경하는데 사용하는 간단한 명령인데  iconv 명령을 응용해서 셀스크립트를 작성하d였고 다양한 파일을 처리하기 위한 방법으로 셀스크립트를 작성해 보았습니다.

[셀스크립트 응용] 
ICONV 을 이용한 파일 인코딩(Encoding)
ICONV와 SED 를 활용하여 파일의 문자셋(charset)을 변환 하는 방법

ICONV와 SED 를 이용한 오래된 소스 변환하는 방법입니다.

종종 서버에서 예전 서버를 마이그레이션 하다가 보면 파일의 문자셋 (character set , 이하 문자셋, charset)을 주로 utf8로 통합해야 하는 상황들이 있습니다. 물론 java의 경우 이클립스 같은 도구로 수정은 가능하지만 파일이 많은 경우 개별 파일들이 변환이 필요한지 변환이 잘되었는지 판단은 툴에 의존 해야 합니다.

그리고 리눅스 서버에서 작업하는 경우는 수천개의 파일을 일일이 처리하기 힘듭니다.

다음과 같은 상황에서 사용하시면 좋겠습니다.

1. 오래된 소스들을 통합할때 여러 문자셋으로 작성된 파일을 하나의 문자셋으로 변환하고자 할 경우

2.
문자셋을 처리하고 전체 변환 상태를 확인하고자 할 경우
   ( 전체 소스에서 파일 하나 하나에 대한 처리 상태를 확인 하고 싶은 경우)

3. 파일이 너무 많아서 일일이 상태 점검이 어려운 경우
   ※ 이클립스나 클라이언트 툴로도 가능은 하지만 서버에서 소스 전체를 변환하는 경우 사용 바랍니다.
 (PC에서도 문자를 변환을 하지만 파일하나 하나에 대한 검증이 안되는 경우가 있습니다.)

couplewth@naver.com : DR.choi

 

본 글은 실전에서 사용할수 있는 예제 스크립트 들을 첨부해 둔 파일을 설명하기 위해 중요한 부분의 맥락을 설명하기 위해 작성 되었습니다.

처리하는 중요한 프로세스 단순한 셀스크립트로 프로그램을 짜야 하기 때문에 필요한 함수의 예시는 없습니다만

내용을 보시면 활용되는 방법을 이해할 수 있을 것입니다.

우선 전체적인 프로세스를 개발한 내용을 설명하기 전에 셀스크립트를 이용하여 파일을 처리할때 유의 해야 하는 원칙을 설명 드립니다.

 

[1. 스크립트 설계 원칙]

[리눅스로 파일을 성공적으로 처리하는 원칙
1. 필요하면 모든 처리 과정을 로그로 남기며 되도록 원본은 그대로 두고 복사본을 통해 작업을 하여
     실패시 백업/원복이 가능하도록 해야 합니다.

2. 항상 처리할 대상을 파일로 만듭니다
  . - 특히 처리할 부분에 대한 목록을 둡으로써 예외 상황을 구분하기 용이합니다
  . - 샘플을 만들어서 정상과 비정상을 구분하여 파일로 목록화 해야 합니다

3.
처리시 성공과 실패를 구분하여 로그를 남겨둡니다
  . - 성공의 원인과 실패의 원인을 쉽게 알수 있도록 적절한 로그가 필요합니다.

4. 처리시작과 종료 상태를 로그로 남깁니다
  . - 종종 처리가 되었는지 처리가 되지 않았는지 판단하기 위해서
      처리 대상의 건수와 처리 완료한 건수를 로그에 남기도록 합니다.

 

 

[2. 스크립트 프로세스 ]

0. 셀스크립트에 필요한 공통 변수를 정리합니다. (0.Conver.env
) - 각 셀스크립트에 필요한 공통 변수를 작성합니다. (디렉토리나 로그파일, 작업 디렉토리명 등
) - fn_find_match : 특정 파일에서 특정 문자가 있는지 확인하고 파일 목록에서 파일 이름을 찾는 함수입니다.
  - fn_sed_change : 파일이름을 입력 받아 처리하는 부분입니다.

1. 처리하고자 하는 디렉토리 목록을 작성하여 둡니다. (     1.Convert.sh)

2. 디렉토리 별로 처리할 파일 목록을 작성하여 둡니다 .     (2.find_file.sh)

3. 위에서 작성해둔 파일 및 디렉토리 목록으로 파일 하나씩 실행 합니다. (3.change.sh)

 

파일을 sed로 하면 파일 원본이 euc-kr 혹은 utf8이면서 시스템의 LANG 과 다른 경우 에러가 발생합니다.

iconv를 통해 파일의 charset를 변경하지만 변경 될수도 있고 변경되지 않을수도 있고 에러가 날수도 있다는 점을 고려하엿습니다.

전체 소스가 길어 보이지만 파일의 charset들이 혼성되어 있는 경우 사용하면 편리합니다.

 

아래 예제는 디렉토리 전체의 파일의 Charset을 변경하는 경우도 가능하도록 구현해 두었습니다.

우선 아래와 같이 sed가 파일을 읽으면서 처리해야 하는 여러가지 Rule을 하나의 파일에 넣고 실행하면 여러가지 Case별 처리를 순차적으로 한꺼번에 수행이 가능해 집니다.

처리 순서는 다음 `sed.fm` 과 같이 우선 적용될 순서로  작성을 하면 됩니다.

 

[첨부 : sed.fm]

s/"\$DOCUMENT_ROOT\//\$_SERVER\['DOCUMENT_ROOT'\] . "\//
s/\$DOCUMENT_ROOT =/\$_SERVER\['DOCUMENT_ROOT'\] =/
s/(\$DOCUMENT_ROOT/(\$_SERVER\['DOCUMENT_ROOT'\]/
s/\$DOCUMENT_ROOT\//\$_SERVER\['DOCUMENT_ROOT'\]\//
s/\$_SERVER\[DOCUMENT_ROOT\]/\$_SERVER\['DOCUMENT_ROOT'\]/
s/\$DOCUMENT_ROOT\./\$_SERVER\['DOCUMENT_ROOT'\]\./

 

[첨부 : 0.Conver.env] 의 구성

파일의 주요 내용 정리
[iconv]
  1) iconv를 통해서 파일의 문자셋을 변환합니다.
  2) diff 명령으로 문자셋 치환 상태를 로그로 남기고
  3) 변환이 성공된 경우 변경 내용으로 원본 파일에 업데이트 합니다.

[sed]
  1) sed는 파일이름을 입력받아 "sed.fm" 에 정의된 형식으로 내용을 치환합니다.
  2) diff로 원본파일과 치환 결과을 비교합니다.
  3) 문자열 치환 성공한 경우 원본으로 업데이트하고 로그를 생성합니다.

 

[첨부 : 0.Conver.env]

# 주요 함수를 파일로 만들어 둡니다.

function fn_sed_change() {
   filename="${1}"
   if [ -a "$1" ]
   then
    ## ICONV ######################
    # 중요 함-----------------------------
    # - iconv로 파일의 변환 결과를 "-o /tmp/a.iconv" 로 저장합니다.
    # -  ICONV 로 문자셋 변경을 하고 성공을 하면 문자변환이 필요한 파일이라고 인식하고
    # -  ICONV 실행이 실패하면 문자변환을 하지 않아도 되는 파일로 인식하는 부분입니다.
    echo " EXEC : iconv -feuc-kr -tutf8 -o /tmp/a.iconv $filename "
    iconv -feuc-kr -tutf8 -o /tmp/a.iconv $filename >> $ConvertLog;

    Ret_iconv=$?    # 실행결과를 0은 성공 ~0 은 실패 

   if [ "$Ret_iconv" -eq 0 ]
   then
       # 변환된 -o /tmp/a.iconv 파일과 원본을 비교해서 변환 상태를 확인 합니다.
 
       echo " ICONV.DIFF : $filename **************** >> " >> $ConvertLog;
       diff /tmp/a.iconv $filename >> $ConvertLog;
       Ret_diff=$?

       # 중요 함-----------------------------
       # Ret_diff: diff 를 한결과임 (1 은 성공)
       # Ret_iconv=$? iconv를 한 결과임 (0 은 성공)
       # 문자셋을 치환할때 같은 문자셋으로 치환하면 오류가 나는 원리를 이용하여
       #         ICONV 치환이 성공하면 다른 문자셋이라고 판단합니다.
       # - euc-kr -> utf8 은 성공 0
       # - utf8 -> utf8은 에러가 발생함을 착안함.

       ## may File is converted
       if [ "$Ret_diff" -eq 1 ]
       then
           cat /tmp/a.iconv $filename
           ResultStat="ok"
           echo " ICONV.DIFF.ok : $file_name euc-kr->utf8 iconv:[$Ret_iconv] dif:[$Ret_diff] "
       else
           ResultStat="nok"
       fi
       echo " ICONV.DIFF.$ResultStat : $file_name euc-kr->utf8 iconv:[$Ret_iconv] dif:[$Ret_diff] " >> $ProcLog
       echo " ICONV.DIFF.$ResultStat : $file_name euc-kr->utf8 iconv:[$Ret_iconv] dif:[$Ret_diff] " >> $ConvertLog
   fi

   #### SED ########################################
   # SED 명령으로 "sed.fm" 파일에 정의된 특정 문자열을 치환하는 작업을 할 수 있습니다.
   # - 주의 사항으로 SED의 결과를  /tmp/phpa.tmp 로 저장하여 원본 유실을 방지합니다.
   echo " >>>> EXEC : sed -f $SED_FILE $file_name "
   sed -f $SED_FILE $filename > /tmp/phpa.tmp
   Ret=$?
   # 중요 함-----------------------------
   # Ret : sed 수행 결과임
   
   ## DIFF ######################
   # - 원본과 변환된 파일이 같은지 확인합니다.
   echo " SED.DIFF : $filename ++++++++++++++++ " >> $ConvertLog;
   diff $filename /tmp/phpa.tmp >> $ConvertLog;
   RetChk=$?

   # 중요 함-----------------------------
   # 변경된 부분이 있다면 RetChk = 1
   # 변경 되지 않으면 0
   # 파일이 없거나 에러이면 -1 이다

   if [ "$RetChk" -eq 1 ]
   then
      # 파일이 변경이 되었다면 변환된 파일로 원본의 내용을 변경합니다.
      echo " SED.DIFF.ok>> cat /tmp/phpa.tmp > $filename ";
      cat /tmp/phpa.tmp > $file_name
      echo " SED.DIFF.okk |sed:[$Ret] diff:[$RetChk] cat /tmp/phpa.tmp > $filename " >> $ConvertLog;

   else
      echo " SED.DIFF.nok |sed:[$Ret] diff|[$RetChk] ++++++++++++++++++++ $filename " >> $ConvertLog;
   fi

   ls -1 $filename >> $ConvertLog;

 else
    echo " SED.CHANGE.fail [fn_sed_change] $1 file not Found ~~!"
    echo " SED.CHANGE.fail | [$RetChk] $filename file Not Found !! " >> $ConvertLog;
    Ret="No File"
 fi
 
 echo " >>fn_sed_change :${2}|$filename | [$Ret] change:$RetChk "
 echo " >>fn_sed_change :${2}|$filename | [$Ret] change:$RetChk " >> $ProcLog
}

 

[첨부 : 1.Convert.sh] 의 구성

[1.Convert.sh ]는 작업을 처리하기 전에 전체 파일 목록과 처리 상태를 사전 저장하기 위해 로그를 생성하는 파일입니다.
1.  파일을 찾을 디렉토리 목록을 생성합니다. 
   - 확장자 '*./(js|lucene|imag|img|log4php|lost)'은  제외합니다.
   - 디렉토리 목록은 $DataBASE/1.convert.dir 라는 파일로 저장합니다.
2. 저장된 디렉토리 목록을 읽어서 각 디렉토리별로 파일 목록을 생성합니다. 
   - 링크와 파일을 분리하여 목록을 작성함으로써 링크파일에 중복 처리를 하지 않도록 합니다.
3. 각 작업에 대한 처리시작시간과 종료 시간을 별도 파일로 로깅합니다.

 

[첨부: 1.Convert.sh]

# 공통 변수화 함수를 로딩합니다.  ( . ~파일명)
. 0.Conver.env


echo " STEP 1.1 make Folder List +++++++++++++++++++++"

# 파일 목록 생성을 위해 필요한 가공을 합니다. 
#find $WebBASE -maxdepth 1 -type d | sort | egrep -v -e './(js|lucene|imag|img|log4php|lost)' | grep  '/' | cut -d '/' -f2- > $DataBASE/convert.dir
find $WebBASE -maxdepth 1 -mindepth 1 -type d | sort | egrep -v -e './(js|lucene|imag|img|log4php|lost)' > $DataBASE/1.convert.dir
DIR_LST=`cat $DataBASE/1.convert.dir`

echo " >>> [ $DIR_LST] ";

#rm -rf  /wwwdata/apps/www/convert_data/files.bak 
#mv /wwwdata/apps/www/convert_data/files /wwwdata/apps/www/convert_data/files.bak
#mkdir -p "/wwwdata/apps/www/convert_data/files/"
rm -rf  $FILE_files.bak
mv $FILE_files   $FILE_files.bak
mkdir -p "$FILE_files"

echo " STEP 1.2 make filelist+++++++++++++++++++++"
for dname in $DIR_LST
do
    cTime=`date "+%Y-%m-%d %H:%M:%S"`

    echo  "$dname | $SECONDS | $cTime START " 
    #lst_file=` echo $dname |  sed -e 's/\/wwwdata\/apps\/www\/nwww\.mixsh\.com\///' `
    lst_file=` basename $dname `
    
    ####### FILE LIST
    #DataFileList="/wwwdata/apps/www/convert_data/files/${lst_file}.files"
    DataFileList="$FILE_files/${lst_file}.files"
    find -H $dname -type f  > $DataFileList

    ####### LOGGING 
    # 처리 확인을 위해서 : 파일 목록 처리 시간과 처리 대상 파일 갯수를 로그로 저장합니다.
    DataCnt=`wc -l $DataFileList`
    echo  "$dname | $SECONDS | $cTime | $DataCnt" 
    echo  "$dname | $SECONDS | $cTime | $DataCnt" >> $ProcLog

    ####### LINK LIST : 링크 파일과 같은 예외 상황을 별도 관리합니다.
    #DataFileList="/wwwdata/apps/www/convert_data/files/${lst_file}.links"
    DataFileList="$FILE_files/${lst_file}.links"
    find -H $dname -type l  > $DataFileList

    ####### LOGGING 
    DataCnt=`wc -l $DataFileList`
    echo  "$dname | $SECONDS | $cTime | $DataCnt" 
    echo  "$dname | $SECONDS | $cTime | $DataCnt" >> $ProcLog

done

echo " [$0] END  $ProcLog check !!"

 

 

참고: 

couplewith.tistory.com/entry/Bash-Shellscript-%EA%B8%B0%EB%B3%B8%EB%8B%A4%EC%A7%80%EA%B8%B0-awk-cut-sort-%ED%99%9C%EC%9A%A9

 

[Bash Shellscript 기본다지기] awk, cut, sort 활용 :

[Bash Shellscript 기본다지기] awk, cut, sort 활용 : 중상급 과제 cat >a <

couplewith.tistory.com

https://couplewith.blog.me/222157608911

 

[셀스크립트 응용]ICONV와 SED 를 활용하여 파일의 문자셋(charset)을 변환 하는 방법

[셀스크립트 응용]ICONV와 SED 를 활용하여 파일의 문자셋(charset)을 변환 하는 방법 couplewth@n...

blog.naver.com

 

728x90
반응형