bash script2023. 9. 4. 08:55

 

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

텍스트 파일에 뭔가 문제가 생겨서 중간에 바이너리(binary) 데이터가 포함된 경우 이를 제거하기 위한 방법이다. 간혹 텍스트 중간에 바이너리 바이트가 일부 삽입되어 있는 희한한 상태로 인하여 다른 부분에서 작업이 안되는 문제가 있어서 고육지책으로 셸 스크립트(shell script)를 만들어서 제거했다.

파일 내용을 한줄씩 읽어서 혹시라도 내용 중간에 바이너리가 있을 경우 이를 제외한 나머지만 모아서 별도의 파일로 다시 저장하도록 했다. 아래와 같이 작업.

# 탭을 변수로 할당
tab=`echo -e "\t"`
# 대상 파일: ~/my_file.txt
target_file=~/my_file.txt
# 결과 파일: ~/my_file.txt.result
res_file=~/my_file.txt.result
# 한줄씩 읽어서 작업
max_num=`cat $target_file | wc -l`
for line_num in `seq 1 $max_num`
do
  cur_line=`sed -n ${line_num}p $target_file`
  # grep으로 한글,영문,수자,기호,공백,탭만 골라서 임시 파일에 저장
  echo "$cur_line" | grep -ao "[]\!{}~\`@#$%^&*()=_+|\\:\";'<>?,./\[A-Za-z0-9${tab}가-힣 -]\{1,\}" > $target_file.tmp
  # 임시파일 $target_file.tmp의 내용을 다시 한줄로 복원해서 res_line 변수에 저장
  res_line=`cat $target_file.tmp | tr -d '\n'`
  echo "$res_line" >> $res_file
  # 임시 파일 삭제
  rm $target_file.tmp
done

골치 아팠던 점은 한줄을 읽어서 grep 명령으로 한글/영문/수자/기호/공백/탭 등만 추려서 출력하는 인자(argument)를 정규표현식(regular expression)으로 만드는 것이었다. 위의 예시에서 볼 수 있듯이 느낌표(!), 역따옴표(`), 역슬래시(\), 따옴표("), 대괄호([) 등은 앞에 역슬래시(\)를 붙여서 셸에서 해석하지 못하도록 해 주고, 빼기(-) 기호는 문자의 범위를 지정할 때 사용되는 경우가 아님을 명확히 하기 위해 공백 다음에 위치시켰다. 탭은 별도의 변수 tab에 할당하여 정규표현식에 추가. 정규표현식 바로 다음에 \{1,\} 부분은 1개 이상 연속될 경우 출력하라는 의미이다.

 

문자열 중간에 바이너리 데이터가 있을 경우 grep의 -o 옵션에 따라 줄바뀜이 발생하므로, 임시 파일에 저장된 결과를 다시 한줄로 바꾸기 위해 tr 명령에서 -d 옵션으로 줄바꿈(\n)을 제거.

 

echo "$cur_line" | grep... 명령의 결과에 유효한 문자열 출력이 없을 경우 임시 파일에 이전 임시파일의 내용이 그대로 유지될 수도 있으므로 결과 처리후 항상 임시 파일은 삭제하도록 했다.

한줄씩 읽어서 작업하기 때문에 파일이 클 경우 시간이 상당히 걸릴 수 있다는 문제가 있지만, 당장에 딱히 좋은 방법이 생각나지 않아서 그냥 이런 식으로 처리했다 -_-;

728x90
Posted by 반달가면