카테고리 보관물: Language

특수 문자(Special Character) 문제(&#65279)

개요

Windows 환경에서 작성한 설정 파일이나 소스 코드를 Linux 서버에 배포할 때 특수 문자 문제가 발생하는 경우가 있습니다. 대표적으로 UTF-8 BOM(Byte Order Mark)과 Windows 개행문자(CRLF)가 눈에 보이지 않기 때문에 원인 파악이 어렵습니다.

XML 파싱 또는 Hazelcast 세션 연동 환경에서 특수 문자(Special Character)가 포함된 데이터 처리 중 예기치 않은 오류가 발생하는 경우가 있습니다. 대표적으로 Unicode BOM 문자인 (U+FEFF, Zero Width No-Break Space)가 파일 앞에 숨겨져 있거나 XML 내에 포함되어 파싱 실패로 이어지는 케이스입니다. 이 글에서는 해당 문자로 인한 오류 패턴과 해결 방법을 정리합니다.

cvc-complex-type.2.3 오류

09:52:06,504 WARNING [com.hazelcast.web.ClusteredSessionService] (default task-1) Cannot connect to Hazelcast server: cvc-complex-type.2.3: Element 'near-cache' cannot have character [children], because the type's content type is element-only. 
09:52:06,962 WARNING [com.hazelcast.web.HazelcastHttpSession] (default task-1) Unexpected error occurred.: java.lang.NullPointerException 
 at com.hazelcast.web.ClusteredSessionService.updateAttributes(ClusteredSessionService.java:285) 
 at com.hazelcast.web.HazelcastHttpSession.sessionDeferredWrite(HazelcastHttpSession.java:300) 
 at com.hazelcast.web.WebFilter.doFilter(WebFilter.java:303) 
 at io.undertow.servlet.core.ManagedFilter.doFilter(ManagedFilter.java:61) 
 at io.undertow.servlet.handlers.FilterHandler$FilterChainImpl.doFilter(FilterHandler.java:131) 
 at io.undertow.servlet.handlers.FilterHandler.handleRequest(FilterHandler.java:84) 
 at io.undertow.servlet.handlers.security.ServletSecurityRoleHandler.handleRequest(ServletSecurityRoleHandler.java:62) 
 at io.undertow.jsp.JspFileHandler.handleRequest(JspFileHandler.java:32) 
 at io.undertow.servlet.handlers.ServletChain$1.handleRequest(ServletChain.java:68) 
 at io.undertow.servlet.handlers.ServletDispatchingHandler.handleRequest(ServletDispatchingHandler.java:36) 
 ...
  • 일반적인 오류 해결법
  1. XML 태그 정보 누락 여부 재확인
<?xml version="1.0" encoding="UTF-8" ?>
  1. IDE 문제 – 이클립스 또는 STS 재기동
  2. 오타 여부 재확인 – 특수문자의 오기입 또는 오탈자로 인해 발생 가능 합니다.
  • 그게 아니면…..
  1. UTF-8 인코딩의 BOM(Byte Order Mark) 문제….
  2. UTF-8, UTF-16 등의 유니코드 인코딩 방식을 알리기 위한 사인(Signature)으로 사용하기 위한 용도 입니다.
  3. UTF-8은 BOM 없이도 인코딩 인식이 가능하지만 노트패드등의 윈도우 환경의 일부 에디터가 BOM을 자동으로 추가 하게 되며 눈에 보이지 않는 특수 문자(여백 문자)가 추가 되게 됩니다. 이로 인해 UNIX 환경에서 예상치 않은 cvc-complex-type.2.3 오류가 발생할 수 있습니다.
  • 해결 방안
  1. Notepad++, Ultraeditor, EditPlus 등의 에디터를 이용해 ‘UTF-8 without BOM’ (BOM 없는 UTF-8) 으로 저장
  2. 개인적으로는 BOM 없는 UTF-8로 저장이 안되어서 태그 앞의 여백 부분을 모두 삭제하여 해결 하였습니다.
  3. 윈도우에서 코드를 저장할 때는 항상 인코딩에 주의를 해야할 듯 합니다. 🙂

출처

http://blog.wystan.net/2007/08/18/bom-byte-order-mark-problem

https://ko.wikipedia.org/wiki/%EB%B0%94%EC%9D%B4%ED%8A%B8_%EC%88%9C%EC%84%9C_%ED%91%9C%EC%8B%9D

Linux에서 BOM 문자 감지 및 제거

Windows에서 작성된 파일을 Linux 서버에 배포할 때 BOM 문자가 포함된 경우, XML/JSON 파싱 오류나 쉘 스크립트 실행 오류가 발생합니다. Linux에서 BOM 문자를 감지하고 제거하는 방법은 다음과 같습니다.

# 파일에 BOM이 있는지 확인 (UTF-8 BOM = EF BB BF)
hexdump -C target.xml | head -2
# 첫 줄이 "ef bb bf"로 시작하면 BOM 포함

# file 명령으로도 확인 가능
file target.xml
# "UTF-8 Unicode (with BOM) text" 출력 시 BOM 존재

# sed로 BOM 제거 (파일 덮어쓰기)
sed -i '1s/^//' target.xml

# Python으로 BOM 제거
python3 -c "
import codecs
with codecs.open('target.xml', 'r', 'utf-8-sig') as f:
    content = f.read()
with codecs.open('target.xml', 'w', 'utf-8') as f:
    f.write(content)
print('BOM removed')
"

Visual Studio Code, IntelliJ IDEA 등 현대적인 IDE는 파일 저장 시 BOM 포함 여부를 선택할 수 있습니다. VS Code에서는 우측 하단의 인코딩 표시(예: UTF-8)를 클릭하면 “UTF-8 with BOM”과 “UTF-8” 중 선택할 수 있습니다. 팀 공용 저장소라면 .editorconfigcharset = utf-8을 지정하여 BOM 없는 UTF-8을 표준으로 적용합니다.

참고

참고 문서: Unicode BOM FAQ · XML 1.0 문자 집합 명세

^M 개행문자로 인한 Shell Script 오류

개요

Windows 환경에서 작성하거나 FTP(Binary 모드)로 전송한 Shell Script를 Linux에서 실행할 때 ^M 개행문자 오류(bad interpreter)가 발생하는 경우가 있습니다. Windows의 줄바꿈 문자는 CRLF(\r\n), Linux는 LF(\n)이며, 변환 없이 전송하면 각 줄 끝에 \r(^M)이 남아 인터프리터 경로가 깨집니다. vim 치환 기능이나 sed 명령으로 간단하게 해결할 수 있습니다.

증상 — Shell Script bad interpreter error

Shell Script를 Linux 환경에서 실행하면 아래와 같이 /bin/bash^M: bad interpreter 에러가 발생합니다.

[root@localhost ~]# ./temp.sh
-bash: ./temp.sh: /bin/bash^M: bad interpreter: No such file or directory

원인 — CRLF vs LF 개행문자 차이

결론적으로 Windows와 Linux의 개행문자 차이로 인해 발생합니다. Binary 타입으로 Windows 에디터에서 저장하거나 FTP로 전송하면 Windows 개행문자 ”
“이 Linux의 ”
“으로 변환되지 않아 각 줄 끝에
(^M)이 남습니다.

LF : Line Feed 커서를 한칸 아래로 이동 = 새로운 행 추가(new line feed)
CR : Carriage Return 커서를 맨왼쪽으로 이동 = 시작위치로 복귀(return)

vim -b(Binary 모드)로 파일을 열면 줄 끝의 ^M 문자를 직접 확인할 수 있습니다.

[root@localhost ~]# vim -b temp.sh

!/bin/bash^M
^M
ls -lh^M

해결 방법

단순히 ^M만 삭제해도 해결되지만 수백 줄 이상의 스크립트에서는 vim 치환 기능이나 sed 명령을 사용합니다. 개행문자 ^M은 “Shift+6”, “Shift+m”이 아닌 “Ctrl+v+m”으로 입력해야 합니다.

방법 1: vim -b 모드에서 :%s 치환 사용

[root@localhost ~]# vim -b temp.sh

:%s/^M//g

방법 2: vim Last Line Mode에서 fileformat 설정 후 저장

[root@localhost ~]# vim temp.sh

:set fileformat=unix
:wq

방법 3: sed 명령 사용 (vim을 사용하기 어려운 환경)

[root@localhost ~]# sed -i -e 's/
$//' temp.sh

# 또는 (^M은 Ctrl+v+m 입력)
[root@localhost ~]# sed -i -e 's/^M$//' temp.sh

dos2unix 유틸리티 사용

vim이나 sed 대신 dos2unix 유틸리티를 사용하면 CRLF → LF 변환을 가장 간단하게 처리할 수 있습니다. 대부분의 리눅스 배포판에서 패키지로 제공되며, 여러 파일을 한 번에 처리하거나 디렉토리 전체를 변환하는 데 유리합니다.

# 설치 (RHEL/CentOS)
yum install dos2unix -y

# 단일 파일 변환 (CRLF → LF)
dos2unix temp.sh

# 여러 파일 일괄 변환
dos2unix *.sh

# 변환 전 파일 타입 확인
file temp.sh
# "ASCII text, with CRLF line terminators" — 변환 필요
# "ASCII text" — 이미 LF, 변환 불필요

반대로 Linux 파일을 Windows 형식(LF → CRLF)으로 변환할 때는 unix2dos 명령을 사용합니다. Git을 사용하는 환경이라면 .gitattributes 파일에 * text=auto를 설정하여 체크아웃 시 자동으로 개행문자를 변환할 수 있습니다.

사전 예방

저장하거나 전송할 때 미리 파일 포맷(Unix LF)을 선택하면 이 문제를 예방할 수 있습니다. Notepad++나 VS Code 같은 Windows 에디터에서 줄바꿈 형식을 LF로 설정하거나, FTP 클라이언트에서 ASCII 모드로 전송하면 자동 변환됩니다.

참고

참고 문서: sed(1) Linux man page · Vim 검색·치환 명령어 문서