인프라

[문제 해결] echo 와 printf

하루이2222 2024. 12. 11. 19:45

라즈베리 파이 USB HID 설정 실패 : echoprintf

라즈베리 파이를 이용해 USB 가젯, 특히 키보드나 마우스 같은 HID 장치를 만드는 프로젝트 진행 중, 모든 단계를 올바르게 따라 했음에도 장치가 PC에서 인식되지 않는 "먹통" 현상을 겪는 경우가 있음.

이 문제의 주범은 기본적인 명령어 echo -ne의 오용일 가능성이 높음.

문제의 코드: echo -ne를 이용한 Report Descriptor 작성

USB HID 장치 설정의 핵심은 **리포트 디스크립터(Report Descriptor)**를 시스템 파일에 기록하는 과정임. 이 디스크립터는 장치가 어떤 데이터를 어떻게 전송할지 정의하는 '설명서'이기에, 반드시 바이너리 데이터 형태로 작성되어야 함.

온라인에서 흔히 발견되는 문제의 코드는 다음과 같음.

# 🔴 문제가 발생할 가능성이 높은 코드
echo -ne "\\x05\\x01\\x09\\x06\\xA1\\x01...\\xC0" | sudo tee functions/hid.usb0/report_desc

위 코드의 본래 의도는 \x05 같은 16진수 이스케이프 시퀀스를 실제 바이트 값으로 변환하여 report_desc 파일에 쓰는 것이지만, 이 코드는 종종 의도대로 동작하지 않음.

실패 원인

echo 명령어는 가장 기본적인 유틸리티지만, 그 동작 방식은 사용하는 셸에 따라 일관되지 않음.

  1. 셸 의존성: echo -e 옵션은 백슬래시 이스케이프를 해석하라는 의미지만, 이는 POSIX 표준 기능이 아님. 즉, 모든 셸이 이 옵션을 동일하게 지원한다고 보장할 수 없음.
  2. bash vs dash: 일반적으로 사용하는 bash 셸은 \xHH (16진수 바이트) 같은 확장 시퀀스를 잘 해석함. 하지만 Raspberry Pi OS를 포함한 데비안 계열 리눅스의 기본 시스템 셸(/bin/sh)은 dash임. dashecho\xHH 형식을 해석하지 못함.
  3. 결과: 손상된 디스크립터: dash 셸 환경에서 위 코드가 실행되면, \x05하나의 바이트(0x05)가 아닌, 네 개의 문자('\', 'x', '0', '5')로 파일에 기록됨.
    • 의도한 데이터 (정상): 05 01 A1 01 ... (바이너리 값)
    • 실제 기록된 데이터 (손상): \x05\x01\xA1\x01... (텍스트 문자열)

이처럼 텍스트로 손상된 '설명서'는 USB 호스트(PC)가 해석할 수 없으므로, 결국 장치 인식 실패로 이어지게 됨.

해결책: printf 사용

이 문제를 가장 확실하고 올바르게 해결하는 방법은 echo 대신 printf를 사용.

  • printf란?: printf는 포맷팅된(formatted) 출력을 위해 설계된 표준 유틸리티, \xHH를 포함한 다양한 이스케이프 시퀀스를 처리하는 방식이 모든 표준 셸에서 일관되게 동작함.

올바른 코드는 다음과 같음.

# 🟢 안정적이고 올바른 코드
printf "\x05\x01\x09\x06\xA1\x01...\\xC0" | sudo tee functions/hid.usb0/report_desc

여기서 더 나아가, sudo 권한과 파일 리디렉션(>) 문제를 가장 확실하게 해결하는 방법은 bash를 명시적으로 호출하는 것임.

# ✅ 가장 확실하고 권장되는 방법
sudo bash -c 'printf "\x05\x01\x09\x06\xA1\x01...\\xC0" > functions/hid.usb0/report_desc'

이 방식은 현재 사용 중인 셸의 종류와 관계없이, printf를 올바르게해석하는 bash를 루트 권한으로 실행하여 명령을 처리하므로 신뢰성이 보장됨.

결론

셸 스크립트에서 단순 텍스트를 출력할 때는 echo를 사용해도 무방하지만, \n, \t 또는 \xHH와 같은 이스케이프 시퀀스가 포함된 데이터를 다룰 때는 printf를 사용하는 것이 좋음.