이 글에서는 리눅스 Bash/Shell 환경에서 printf 명령어를 실제로 활용할 수 있는 다양한 예제를 소개합니다.
printf 명령어는 echo 명령어처럼 텍스트를 출력하지만, 출력 형식을 훨씬 더 세밀하게 제어할 수 있다는 점이 큰 차이입니다.
특히 변수를 텍스트에 삽입하거나, 줄바꿈을 포함하거나, 텍스트를 정렬하고 서식을 지정하는 등 나만의 형식화된 출력을 만들 때 매우 유용한 도구입니다.
printf 명령어 문법
printf 명령어는 다음과 같은 문법 구조를 가집니다:
printf [-v var] format [arguments]...
각 요소를 살펴보면:
- -v 옵션은 결과를 화면에 출력하는 대신 var라는 변수에 저장하도록 지시합니다.
- format은 세 가지 요소가 조합된 문자열입니다:
- 그대로 출력되는 일반 문자
- 출력 전에 해석되는 백슬래시 이스케이프 문자
- 지정된 변환 규칙에 따라 해당 인수로 대체되는 변환 지정자(변수와 비슷하게 생각하면 됩니다)
- arguments(인수)는 format에 전달되어 정의된 변환에 사용됩니다.
- 인수가 변환 지정자보다 많으면, 모든 인수가 소진될 때까지 format 문자열이 반복 적용됩니다.
- 인수가 부족하면 숫자형 지정자는 0으로, 문자열 지정자는 null로 설정됩니다.
printf의 이스케이프 문자, 변환 지정자, 플래그
printf는 텍스트를 무수히 다양한 방식으로 서식화할 수 있는 방대한 옵션들을 제공합니다. 아래 예제들을 통해 실질적인 활용법을 확인해 보세요.
여기서 모든 옵션을 일일이 나열하기보다는, 시스템에서 다음 명령어를 실행하면 printf 명령어의 전체 사용자 매뉴얼을 확인할 수 있습니다:
man printf
printf Bash/Shell 실전 예제
그렇다면 이 모든 것이 실제로 어떤 용도로 쓰일까요?
숫자를 반올림하여 표시하기
먼저 간단한 시나리오부터 시작해 보겠습니다. 숫자를 소수점 둘째 자리까지 표시하고 싶다면:
printf "%.2f" 4.21423557
실행 결과:
4.21
지정한 형식 %.2f는 printf에게 숫자를 소수점 둘째 자리까지 표현하라고 지시합니다. 이는 형식 문자열의 .(마침표)로 표현되는 precision(정밀도) 지시자를 통해 이루어집니다.
이때 주의할 점은, 숫자가 잘리는(truncate) 것이 아니라 반올림(round)된다는 것입니다. 부동소수점 수의 반올림은 의외로 까다롭기 때문에 반드시 출력 결과를 확인하세요!
반올림의 기묘함
이 기묘함을 설명하기 위해 다음 예제를 살펴보겠습니다:
printf "%.2f" 4.215
결과가 4.22가 되어야 할 것 같죠? 하지만 아닙니다. zsh의 printf 구현에서는 다음과 같이 반올림됩니다:
4.21
숫자가 실제로 반올림되고 있는지 확인하려면 다른 값을 테스트해 볼 수 있습니다:
printf "%.2f" 4.216
실행 결과:
4.22
… 즉, printf에 전달된 숫자는 분명 반올림되고 있습니다.
그렇다면 왜 4.215의 반올림 결과가 어긋난 걸까요? 간단히 말하면, 부동소수점 수 특성상 화면에 표시되는 값과 컴퓨터가 계산에 사용하는 실제 값 사이에 미세한 불일치가 존재하기 때문입니다.
이 문제를 해결하는 방법들도 있지만, 이 글의 범위를 벗어나므로 별도의 글에서 다루겠습니다.
진수 변환하기 (10진수, 16진수, 8진수)
흔히 마주치는 상황 중 하나는, 다른 프로그램이나 스크립트에서 받은 숫자를 다른 진법으로 표시해야 하는 경우입니다. printf는 변환 지정 문법을 사용해 이를 손쉽게 처리할 수 있습니다:
printf "Decimal: %d\nHexadecimal: %x\nOctal: %o\n" 64 64 64
실행 결과:
Decimal: 64 Hexadecimal: 40 Octal: 100
숫자 64가 세 번 전달되어 세 가지 서로 다른 형식으로 표시되었습니다.
보기 좋은 출력 만들기
아래 예제는 printf를 사용해 서식이 갖춰진 표를 출력합니다. 코드 내 주석으로 단계별로 설명했으니 흐름을 따라가 보세요:
#/bin/bash
# 헤더 텍스트의 형식을 정의합니다
# 줄바꿈(\n) 다음에 왼쪽 정렬된 15자 문자열(%-15s), 오른쪽 정렬된 15자 문자열(%15s),
# 오른쪽 정렬된 10자 문자열(%10s), 그리고 또 하나의 줄바꿈이 이어집니다
header_format="\n %-15s %15s %10s\n"
# 각 행 데이터의 형식을 정의합니다
# 앞의 두 항목은 헤더와 동일하지만, 마지막 항목은 소수점 둘째 자리까지 표시하는 부동소수점 수(%11.2f)입니다
row_format=" %-15s %15s %11.2f\n"
# printf 명령어로 헤더를 출력합니다
# 형식을 지정하고, 표의 열 이름이 담긴 인수를 함께 전달합니다
# printf는 header_format을 받아 각 인수 값을 지정된 서식에 맞게 삽입한 뒤 출력합니다
printf "$header_format" "CAR BRAND" "COLOUR" "TOP SPEED"
# 표 헤더 아래에 가로줄을 출력합니다
# 여기서 printf는 등호(=) 기호를 출력하는 데 사용됩니다.
# 중괄호 확장(brace expansion)은 셸 스크립팅의 단축 문법으로, 1부터 50까지의 각 숫자에 대해
# printf 명령을 실행해 기호를 50번 반복 출력함으로써 선을 만듭니다
printf '=%.0s' {1..50}
# row_format을 사용해 각 행의 데이터를 출력합니다.
# 각 줄(백슬래시와 줄바꿈으로 표시)에는 자동차 브랜드, 색상, 최고 속도의 세 값이 들어갑니다
# 공백이 포함된 값은 따옴표로 감싸야 합니다. 값들이 공백으로 구분되기 때문에
# printf가 한 값이 어디서 끝나고 다음 값이 어디서 시작하는지 구분할 수 없기 때문입니다
printf "$row_format" \
Toyota Blue 100 \
Ford "Light Green" 78.3875 \
"General Motors" Purple 15.96
이 스크립트를 실행하면 다음과 같은 결과가 출력됩니다:
CAR BRAND COLOUR TOP SPEED ================================================== Toyota Blue 100.00 Ford Light Green 78.39 General Motors Purple 15.96
printf가 데이터를 어떻게 서식화했는지 자세히 살펴보세요. 헤더와 각 행에 대해 특정 문자 길이를 지정했기 때문에 텍스트가 깔끔하게 정렬됩니다. 최고 속도는 소수점 둘째 자리까지 서식화되어 올바른 위치에 배치되었습니다. 첫 번째 열을 제외한 나머지 텍스트는 오른쪽으로 정렬됩니다.
비교적 적은 양의 문법만으로 읽기 어려운 데이터가 유용한 정보로 탈바꿈했습니다.
무궁무진한 활용 가능성
printf를 활용할 이유는 스스로 찾게 될 것입니다. 스크립트용으로 보기 좋은 메뉴가 있는 명령줄 인터페이스를 만들거나, 데이터베이스 쿼리 결과를 표 형태로 정리하는 등 다양하게 쓸 수 있습니다. 서식 없는 텍스트를 그냥 화면에 뿌리는 대신, 세련된 셸 스크립트로 사람들의 눈길을 끌고 싶다면 꼭 익혀둘 만한 강력한 도구입니다.
또한 리눅스에서 printf는 다른 텍스트 처리 명령어들과 조합하여 사용할 수도 있습니다.