파일 업로드
  1. base64hub
  2. 코드로 다루는 Base64
  3. Bash
코드

Bash에서 Base64 사용하기

실제 작업은 base64 명령이 하고, Bash는 데이터를 파이프로 넘길 뿐입니다. Linux의 GNU coreutils와 macOS의 BSD 도구는 옵션이 서로 다릅니다. 아래 Linux 출력은 GNU coreutils 9.7 기준입니다.

문자열 인코딩과 디코딩

printf '%s' 'héllo wörld' | base64          # aMOpbGxvIHfDtnJsZA==
printf '%s' 'aMOpbGxvIHfDtnJsZA==' | base64 -d   # héllo wörld

base64는 바이트를 인코딩하므로 결과는 터미널의 문자 인코딩을 따릅니다. 요즘 Linux나 macOS 환경이라면 UTF-8입니다.

가장 흔한 실수는 줄 바꿈을 덧붙이는 echo입니다.

echo 'héllo wörld' | base64      # aMOpbGxvIHfDtnJsZAo=   (note the "o=")
echo -n hi | base64              # aGk=

echo -n은 Bash에서는 동작하지만 모든 sh에서 동작하지는 않습니다. printf '%s'는 이식성이 있습니다. here-string(base64 <<< "text")도 줄 바꿈을 붙입니다. 누군가 보낸 Base64가 Cg==나 o=로 끝난다면 끝에 줄 바꿈이 들어 있을 가능성이 높습니다. Base64 디코더에 붙여넣어 확인해 보세요.

GNU(Linux)와 BSD(macOS)의 옵션 차이

작업GNU coreutils (Linux)macOS
디코딩-d, --decode-D, --decode (최근 버전은 -d도 가능)
줄 바꿈 없음-w 0기본값
N자에서 줄 바꿈-w N (기본값 76)-b N
입력 파일base64 filebase64 -i file 또는 base64 < file
출력 파일리디렉션 >-o file 또는 리디렉션
디코딩 시 잡음 무시-i, --ignore-garbage없음

두 -i 옵션은 의미가 다릅니다. macOS에서는 입력 파일을 지정하고, Linux에서는 잡음을 무시합니다. 이식성 있는 스크립트는 stdin에서 읽고 stdout으로 써야 합니다.

base64 < in.bin | tr -d '\n' > out.b64     # same output on Linux and macOS
base64 --decode < out.b64 > in-copy.bin

GNU base64는 기본적으로 76자에서 줄을 바꾸는데, 이 때문에 헤더와 환경 변수가 깨집니다.

head -c 60 /dev/zero | tr '\0' x | base64 -w 0
# eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4

-w 0이 없으면 첫 줄이 76자이고 나머지는 두 번째 줄로 넘어갑니다. MIME 형식의 줄이 필요하다면 기본 줄 바꿈이 바로 원하는 동작입니다.

URL-safe Base64

GNU coreutils 8.31 이상에는 Base64URL을 지원하는 basenc가 들어 있습니다. 패딩은 유지합니다.

printf '%s' '<<???>>' | basenc --base64url      # PDw_Pz8-Pg==
printf '%s' 'PDw_Pz8-Pg' | basenc --base64url -d   # <<???>>

macOS나 오래된 Linux에서는 tr로 문자를 바꿉니다.

printf '%s' '<<???>>' | base64 | tr '+/' '-_' | tr -d '='   # PDw_Pz8-Pg

디코딩할 때는 반대로 바꾸고, 엄격한 디코더를 위해 패딩도 되돌려 놓아야 합니다.

s=PDw_Pz8-Pg
s=$(printf '%s' "$s" | tr -- '-_' '+/')
while [ $(( ${#s} % 4 )) -ne 0 ]; do s="$s="; done
printf '%s' "$s" | base64 -d        # <<???>>

--는 tr이 -_를 옵션으로 읽지 않게 막습니다. JWT에도 똑같은 변환이 필요하며, JWT 디코더가 이를 대신 처리합니다. 자세한 내용은 Base64와 Base64URL 비교에 있습니다.

파일 인코딩과 디코딩

base64 -w 0 hello.txt              # aGVsbG8K
base64 -d <<< 'aGVsbG8K' > copy.txt
base64 -d payload.b64 > payload.pdf

base64는 블록 단위로 읽고 쓰는 스트리밍 방식이라 파일 크기는 문제가 되지 않습니다. 이미지로 Data URI를 만들려면 다음과 같이 합니다.

printf 'data:image/png;base64,%s' "$(base64 -w 0 logo.png)"

HTTP Basic Auth 헤더는 이렇게 만듭니다.

printf 'Basic %s' "$(printf '%s' 'user:pass' | base64)"   # Basic dXNlcjpwYXNz

Basic Auth 헤더 생성기를 쓰면 셸 기록에 비밀번호를 남기지 않고 같은 결과를 얻을 수 있습니다.

검증, 오류, 종료 코드

GNU base64 -d는 잘못된 문자를 만나면 stderr에 base64: invalid input을 출력하고 상태 1로 종료합니다. 그래도 그 지점까지 디코딩한 내용은 모두 쓰므로, 디코딩에 실패하면 일부만 쓰인 파일이 남을 수 있습니다.

printf 'aGk=!!' | base64 -d        # prints "hi", then: base64: invalid input
echo $?                            # 1 (without a pipe after it)
printf 'aGk=!!' | base64 -d -i     # hi   (garbage ignored, exit 0)

coreutils 9.7에서의 결과:

입력결과
aGkhi, 종료 코드 0 (패딩 누락 허용)
"aGVs\nbG8K"hello, 종료 코드 0 (줄 바꿈 무시)
aGl=hi 다음에 invalid input, 종료 코드 1
ainvalid input, 종료 코드 1
PDw_Pz8-Pg==일부 출력, invalid input, 종료 코드 1

종료 상태로 검증하고, 실패해도 멀쩡한 데이터를 덮어쓰지 않도록 임시 파일에 디코딩하세요.

if printf '%s' "$b64" | base64 -d > /tmp/out.bin 2>/dev/null; then
  mv /tmp/out.bin result.bin
else
  echo "invalid Base64" >&2
fi

파이프라인에서 $?는 마지막 명령의 상태입니다. base64 -d가 마지막이 아니라면 set -o pipefail을 추가하세요. 로그나 이메일에서 가져온 문자열이 디코딩되지 않으면 Base64 복구가 따옴표, 공백, 접두사를 제거해 줍니다. 각 실패 원인은 오류 가이드에서 설명합니다.

명령줄에서 쓸 수 있는 다른 도구

  • openssl base64는 거의 모든 시스템에 있고 Linux와 macOS에서 똑같이 동작합니다. OpenSSL로 Base64 다루기를 참고하세요.
  • coreutils가 없는 곳에서는 python3 -m base64 -d file과 python3 -m base64 file을 쓸 수 있습니다. 출력은 76자에서 줄 바꿈됩니다.
  • Kubernetes에서는 kubectl get secret x -o jsonpath='{.data.password}' | base64 -d가 흔한 패턴이며, Kubernetes 시크릿 디코더를 써도 됩니다.

자주 묻는 질문

echo hello | base64 결과가 온라인 도구와 다른 이유는 무엇인가요?

echo가 줄 바꿈을 붙이므로 hello(aGVsbG8=)가 아니라 hello\n(aGVsbG8K)을 인코딩하게 됩니다. printf '%s' hello나 echo -n hello를 사용하세요.

base64 출력이 줄 바꿈되지 않게 하려면 어떻게 하나요?

Linux에서는 base64 -w 0을 씁니다. macOS는 기본적으로 줄을 바꾸지 않습니다. 양쪽에서 똑같이 동작하는 명령이 필요하면 tr -d '\n'으로 파이프하세요.

'base64: invalid input'은 무슨 뜻인가요?

GNU base64 -d가 알파벳에 없는 문자나 잘못된 패딩을 만났다는 뜻입니다. 그때까지 디코딩한 바이트를 출력한 뒤 오류를 표시하고 상태 1로 종료합니다. 흔한 원인은 URL-safe 문자 -와 _, 따옴표, data: 접두사입니다.

macOS의 base64 -d는 Linux와 같나요?

예전 macOS는 -D(또는 --decode)만 알았고, 최근 버전은 -d도 받습니다. 양쪽에서 돌아가야 하는 스크립트에는 --decode를 쓰세요.

계속 읽기