Created
June 17, 2012 03:26
-
-
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.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/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