Skip to content

Instantly share code, notes, and snippets.

@rsvp
Created June 17, 2012 03:26
Show Gist options
  • Save rsvp/2943293 to your computer and use it in GitHub Desktop.
Save rsvp/2943293 to your computer and use it in GitHub Desktop.
jason.sh : pretty print json for key-value processing line-by-line. The goal is a readable and grepable output.
#!/usr/bin/env bash
# bash 4.1.5(1) Linux Ubuntu 10.04 Date : 2012-06-16
#
# _______________| jason : pretty print json for key-value processing by line.
#
# Usage: jason [file] [ident=5] [delim='__:']
#
# Examples: % jason foo.json 0 ': '
# # ^typical json key-value separator.
# # ^ident of 0 for just newline.
# % jason foo.json
# # ^try this first for readability and grep.
#
# Dependencies: Python json module
# CHANGE LOG LATEST version available: https://bitbucket.org/rsvp/gists/src
#
# 2012-06-16 Use json.loads() instead of json.JSONDecoder().decode().
# 2012-06-15 Start using Python json module instead of awk.
# Note that json module since 2.6 is simplejason.
#
# 2012-02-26 Handle errors and those daggling braces.
# 2012-02-25 First experimental version to parse json file.
# It will be IMPERFECT because the structure of a
# particular json file will generally vary.
#
# A json file is NOT easily readable especially in
# compact form without spaces and without newlines.
#
# The goal is a readable and grepable output,
# which can be further refined by awk.
# _____ PREAMBLE_v2: settings, variables, and error handling.
#
LC_ALL=POSIX
# locale means "ASCII, US English, no special rules,
# output per ISO and RFC standards."
# Esp. use ASCII encoding for glob and sorting characters.
shopt -s extglob
# ^set extended glob for pattern matching.
set -e
# ^errors checked: immediate exit if a command has non-zero status.
set -u
# ^unassigned variables shall be errors.
# Example of default VARIABLE ASSIGNMENT: arg1=${1:-'foo'}
jsonf="$1"
indent=${2:-'5'}
delim=${3:-'__:'}
program=${0##*/} # similar to using basename
memf=$( mktemp /dev/shm/88_${program}_tmp.XXXXXXXXXX )
cleanup () {
# Delete temporary files, then optionally exit given status.
local status=${1:-'0'}
rm -f $memf
[ $status = '-1' ] || exit $status # thus -1 prevents exit.
} #--------------------------------------------------------------------
warn () {
# Message with basename to stderr. Usage: warn "message"
echo -e "\n !! ${program}: $1 " >&2
} #--------------------------------------------------------------------
die () {
# Exit with status of most recent command or custom status, after
# cleanup and warn. Usage: command || die "message" [status]
local status=${2:-"$?"}
cleanup -1 && warn "$1" && exit $status
} #--------------------------------------------------------------------
trap "die 'SIG disruption, but cleanup finished.' 114" 1 2 3 15
# Cleanup after INTERRUPT: 1=SIGHUP, 2=SIGINT, 3=SIGQUIT, 15=SIGTERM
#
# _______________ :: BEGIN Script ::::::::::::::::::::::::::::::::::::::::
[ -e "$jsonf" ] || die "non-existent file: $jsonf" 113
{ python <<EOHereDoc
import json
# >>> # 2012-04-30 PRETTY PRINT using Python's json module:
# >>> print json.dumps({'4': 5, '6': 7}, sort_keys=True, indent=5)
# {
# "4": 5,
# "6": 7
# }
with open( "$jsonf", 'rb' ) as f:
# ^binary
data = json.loads( f.read() )
# ^convert json string into its Python representation.
print json.dumps( data, sort_keys=True, indent = $indent )
# If indent is a non-negative integer (it is None by default),
# then JSON array elements and object members will be
# pretty-printed with that indent level. An indent level of 0
# will only insert newlines. None is the most compact representation.
EOHereDoc
} | sed -e 's/, *$//' -e 's/{$//' > $memf
# ^delete leading brace, but not the line.
# ^delete trailing commas
# since newline will become field separator.
# # sample output with indent set at 5 before sed:
# {
# "130.12.1.34": {
# "area_code": 0,
# "country_code": "CA",
# "country_code3": "CAN",
# "country_name": "Canada",
# "dma_code": 0,
# "latitude": 44.233299255371101,
# "locality": "Kingston",
# "longitude": -76.483299255371094,
# "postal_code": "",
# "region": "ON"
# },
# "67.169.73.113": {
# "area_code": 415,
# "country_code": "US",
# "country_code3": "USA",
# "country_name": "United States",
# "dma_code": 807,
# "latitude": 37.758701324462898,
# "locality": "San Francisco",
# "longitude": -122.438102722168,
# "postal_code": "94114",
# "region": "CA"
# }
# }
# Elaborate way to eliminate first open brace, and last closing brace:
lines=$( cat $memf | wc -l )
line1=$(( lines - 1 ))
line2=$(( lines - 2 ))
tail -n $line1 $memf | head -n $line2 \
| sed -e 's/"//' -e "s/\": /$delim/"
# sed unquotes the key, and then substitutes delim.
cleanup
# _______________ EOS :: END of Script ::::::::::::::::::::::::::::::::::::::::
# vim: set fileencoding=utf-8 ff=unix tw=78 ai syn=sh :
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment