#!/bin/bash # # Author: Georg Voell - georg.voell@standby.cloud # Version: @(#)norm-json 3.1.1 07.09.2023 (c)2023 Standby.cloud # Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/ # # This script can be used free of charge. Use it as is or customize as needed. It is not guaranteed to be # error free and you will not be reimbursed for any damage it may cause. # #@ Normalize JSON records and pretty print them. #@ #@Usage: norm-json [options] #@ Options: '-h, --help' : Displays helptext. #@ '-v, --version' : Displays the version of the script. #@ '-q, --quiet' : Just write error message to LOGFILE. #@ '-r, --raw' : Don't convert hyphens e.g. lifecycle-state to lifecycleState #@ '-s, --select' : Select only the nth JSON record (starting with 0 for the first record). #@ '-f, --filename' : JSON file to read from - if not specified, read from stdin. # # Exit codes: # 01: Unknown or wrong parameter. # 02: No **jq** or wrong version of **jq**. This script needs **jq** to format "json". # 03: Error in JSON file or no input. # 04: JSON file contains less then 2 lines. # 05: JSON file doesn't contain records. # 06: JSON file doesn't contain specified record. # 99: User interrupt. # # Update history: # # V 3.0.0 10.01.2021 New version # V 3.0.1 21.03.2021 New paramater "--quiet" # V 3.0.2 24.03.2021 Strip comments beginning lines with // # V 3.1.0 05.06.2023 New copyright # V 3.1.1 07.09.2023 Check if sed is capable of writing Camel Case # script=${0} # Name of this script progstr=`basename "$script"` # Basename of the script progdir=`dirname "$script"` # Dirname of the script # Find executable bash library and source it lib=`which lib.bash 2>/dev/null | sed 's|^no 'lib.bash' in .*||'` if [ "$lib" != "" ]; then source "$lib" else if [ -r "${progdir}/lib.bash" ]; then source "${progdir}/lib.bash" else echo "Unexpected error: Unable to locate bash library 'lib.bash'." exit 1 fi fi # Set PATH to something useful if [ "$WORKPATH" != "" ]; then PATH="$WORKPATH" fi # Presets raw=0 qopt="" number="" param="" filename="" # Loop until all parameters are used up while [ $# -gt 0 ]; do pname=${1} case "$1" in -f | --filename) shift if [ "$1" != "" ]; then filename="$1" if [ ! -r "$filename" ]; then errstr="Can't read filename '$filename'." fi shift else errstr="Please specify a filename after parameter '$pname'." fi ;; -s | --select) shift if [ "$1" != "" ]; then number="$1" range=`echo "$number" | grep '^[0123456789]*$'` if [ "$range" = "" ]; then errstr="Invalid number after parameter '$pname'." fi shift else errstr="Please specify a number after parameter '$pname'." fi ;; -r | --raw) shift raw=1 ;; -v | --version) shift showversion=1 ;; -h | --help) shift showhelp=1 ;; -q | --quiet) shift qopt="$pname" ;; *) errstr="Unknown parameter: '$1'." shift esac done # Display help or error message DisplayHelp # Set defaults # Check if he have jq in path and the right version jqversok=`check-version jq --min 1.5 | cut -d' ' -f3` # Check if we can convert dashes to Camel Case sedok=`echo "my-test" | sed 's|-\(.\)|\U\1|g'` if [ "$sedok" = "myTest" ]; then sedok="ok" fi if [ "$jqversok" != "ok" -o "$sedok" != "ok" ]; then # At least jq version 1.5 is needed for 'first(inputs)', 'keys_unsorted' and 'nth(0)' and we need gnu sed errormsg $qopt 2 "($progstr) No 'jq' od 'sed' in '$PATH' or not the required version." ClearSTDIN exit 2 else # Read from stdin or file if [ "$filename" != "" ]; then # Strip lines beginning with // and empty lines and check json syntax cat $filename | sed 's|^//.*$||' | grep . | jq -M . > $scratchfile 2>&1 stat=$? else if [ ! -t 0 ]; then # Strip lines beginning with // and empty lines and check json syntax cat /dev/stdin | sed 's|^//.*$||' | grep . | jq -M . > $scratchfile 2>&1 stat=$? else errormsg $qopt 3 "($progstr) No filename specified and stdin seems to be empty." exit 3 fi fi if [ $stat -gt 0 ]; then errrsn=`head -n 2 $scratchfile` errormsg $qopt 3 "($progstr) Tool 'jq' detected an error in JSON input." "$errrsn" filecheck -rm $scratchfile exit 3 else result=`filecheck -sl $scratchfile` if [ "$result" != "" ]; then # "data" is being used by "oci cli","result" is used by "opc cli" and "items" is used by aci api headstr=`head -n 2 $scratchfile | tr -d '\n' | tr -s ' ' | sed 's| \[]$| \[|' | sed 's| {}$| {|'` if [ "$headstr" = '{ "data": [' -o "$headstr" = '{ "result": [' -o "$headstr" = '{ "items": [' ]; then if [ $raw -eq 0 -o "$headstr" != '{ "items": [' ]; then mv $scratchfile ${scratchfile}.cp cat ${scratchfile}.cp | jq -M .[] > $scratchfile filecheck -rm ${scratchfile}.cp fi else if [ "$headstr" = '{ "data": {' -o "$headstr" = '{ "result": {' -o "$headstr" = '{ "items": {' ]; then if [ $raw -eq 0 -o "$headstr" != '{ "items": {' ]; then mv $scratchfile ${scratchfile}.cp cat ${scratchfile}.cp | jq -M .[] | grep -v '^"' > $scratchfile filecheck -rm ${scratchfile}.cp fi else # Identity Domain JSON if [ "$headstr" = '{ "schemas": [' ]; then if [ $raw -eq 0 -o "$headstr" != '{ "items": {' ]; then mv $scratchfile ${scratchfile}.cp cat ${scratchfile}.cp | jq -M .Resources[] | grep -v '^"' > $scratchfile filecheck -rm ${scratchfile}.cp fi fi fi fi if [ "$number" != "" ]; then headstr=`head -n 1 $scratchfile` if [ "$headstr" != "[" ]; then errormsg $qopt 5 "($progstr) JSON file doesn't contain records." filecheck -rm ${scratchfile}.cp filecheck -rm $scratchfile exit 5 else mv -f $scratchfile ${scratchfile}.cp cat ${scratchfile}.cp | jq -M 'nth('$number')' > $scratchfile result=`filecheck -sl $scratchfile` if [ "$result" = "" ]; then errormsg $qopt 6 "($progstr) JSON file doesn't contain specified record (number $number)." filecheck -rm ${scratchfile}.cp filecheck -rm $scratchfile exit 6 fi fi fi if [ $raw -eq 0 ]; then while IFS=':' read -r key value; do if [ "$key" != "" -a "$value" != "" ]; then # key=`echo "$key" | sed 's|-\(.\)|\U\1|g' | sed 's|Tb|TB|g' | sed 's|Gb|GB|g' | sed 's|Mb|MB|g'` key=`echo "$key" | sed 's|-\(.\)|\U\1|g' | sed 's|\([MGT]\)b\([s]*\)"|\1B\2"|g'` printf "%s:%s\n" "$key" "$value" else printf "%s\n" "$key" fi done < $scratchfile else cat $scratchfile fi else # Check if we have a string like in GetNamepace result=`grep '"' $scratchfile` if [ "$result" != "" ]; then result=`echo "$result" | cut -d'"' -f2` printf '{\n' printf ' "data": "%s"\n' "$result" printf '}\n' else errormsg $qopt 4 "($progstr) JSON file contains less then 2 lines." filecheck -rm $scratchfile exit 4 fi fi fi fi # Cleanup and exit Cleanup exit $exitcode