macOS Base64 encode script

I am working on macOS and I wanted to base64 encode a snippet of json text. For example I have the following JSON snippet.

{
  "array": [
    1,
    2,
    3
  ],
  "boolean": true,
  "color": "gold",
  "null": null,
  "number": 123,
  "object": {
    "a": "b",
    "c": "d"
  },
  "string": "Hello World"
}

I want to run a command to encode this as base64 text. I need this because I am working with AWS Kinesis and I want to insert a new event into the stream (put-record). That means I need to turn this snippet into the following format

aws kinesis put-record \
    --stream-name samplestream \
    --data sampledatarecord_in_base64 \
    --partition-key samplepartitionkey

Looking into the man pages of macOS and I find base64 command tool. Problem solved or so I thought until checking the man page.

BINTRANS(1)                                               General Commands Manual                                              BINTRANS(1)

NAME
     bintrans, uuencode, uudecode, b64encode, b64decode, base64 – encode / decode a binary file

SYNOPSIS
     bintrans [algorithm] [...]
     uuencode [-m] [-r] [-o output_file] [file] name
     uudecode [-cimprs] [file ...]
     uudecode [-i] -o output_file
     b64encode [-r] [-w column] [-o output_file] [file] name
     b64decode [-cimprs] [file ...]
     b64decode [-i] -o output_file [file]
     base64 [-h | -D | -d] [-b count] [-i input_file] [-o output_file]

This command expects input/output files and I want to do copy/paste text like linux standard tool uses which is available if you want to use the homebrew version here. However I am not going to do that because I am going to write a script overlay instead to practice some bash scripting.

I want to call a script like this to-base64.sh '<input json here>' and get out the base64 text.

That means from the above sample json first I flatten it into a single line that looks like this { "array": [ 1, 2, 3 ], "boolean": true, "color": "gold", "null": null, "number": 123, "object": { "a": "b", "c": "d" }, "string": "Hello World" } and then call the script to-base64.sh to get this output

eyAiYXJyYXkiOiBbIDEsIDIsIDMgXSwgImJvb2xlYW4iOiB0cnVlLCAiY29sb3IiOiAiZ29sZCIsICJudWxsIjogbnVsbCwgIm51bWJlciI6IDEyMywgIm9iamVjdCI6IHsgImEiOiAiYiIsICJjIjogImQiIH0sICJzdHJpbmciOiAiSGVsbG8gV29ybGQiIH0K

Therefore my script needs to take the first argument and convert that text into base64

  • Create an input temp_input_file
  • Put contents of command line argument into temp_input_file
  • Create a temp_output_file
  • Run the base64 command with -i temp_input_file -o temp_output_file
  • Use cat command to put contents of temp_output_file to standard output
  • Caveat make sure to handle unexpected hang or interrupts in script to clear temporary files with bash trap handler to cleanup and delete temp files.

Here is the final script. I also made sure to use the calling users bash instead of the #!/bin/bash which could be the system or some indeterminate bash.

#!/usr/bin/env bash
# Use the users bash to be consistent

tmp_input_file=$(mktemp)
tmp_output_file=$(mktemp)

[ "$?" -eq 0 ] || {
    printf "error: mktemp had non-zero exit code.\n" >&2
    exit 1
}

[ -f "$tmp_input_file" ] || {
    printf "error: tempfile does not exist.\n" >&2
    exit 1
}

trap 'rm -f "$tmp_input_file"' SIGTERM SIGINT EXIT
trap 'rm -f "$tmp_output_file"' SIGTERM SIGINT EXIT

cat > "$tmp_input_file" << eof
$1
eof

base64 -i "$tmp_input_file" -o "$tmp_output_file"

cat "$tmp_output_file"