Need help with your JSON?
Try our JSON Formatter tool to automatically identify and fix syntax errors in your JSON. JSON Formatter tool
Shell Script Wrappers for JSON Formatting Tools
Working with JSON data is a ubiquitous task for developers. Whether you're debugging API responses, parsing configuration files, or processing logs, JSON is everywhere. While many command-line tools exist to help format and process JSON (like
, jq
, or json_pp
), their commands can sometimes be lengthy, difficult to remember, or inconsistent depending on the specific tool or task.python -m json.tool
This is where shell script wrappers come in. A simple wrapper script can abstract away the complexities of these tools, provide a consistent interface, and automate common tasks, making your workflow much more efficient.
Why Wrap JSON Tools?
Wrapping command-line JSON tools in shell scripts offers several benefits:
- Simplified Commands: Turn complex commands with multiple flags into short, memorable aliases (e.g.,
instead offmtjson
orjq .
).python -m json.tool
- Consistency: Use the same wrapper command regardless of which underlying tool is available or preferred on a given system.
- Handling Input: Easily handle input from stdin (piped data), files, or even the system clipboard.
- Adding Features: Integrate extra steps like colorization, diffing against another file, or extracting specific fields by default.
- Automation: Combine multiple steps (like fetching data, formatting, and filtering) into a single command.
Basic Wrapper Example: Pretty-Printing
Let's start with a simple wrapper to pretty-print JSON. This script will try to use
if available, falling back to jq
or python -m json.tool
.json_pp
fmtjson
script:
fmtjson
#!/bin/bash # Simple JSON formatter wrapper # Tries jq, then python -m json.tool, then json_pp # Check for input from pipe or file if [ -p /dev/stdin ]; then # Input is from pipe (stdin) JSON_INPUT=$(cat) elif [ -n "$1" ] && [ -f "$1" ]; then # Input is from a file provided as the first argument JSON_INPUT=$(cat "$1") else echo "Usage: $0 [file] < JSON_data" >&2 echo " Provide JSON via pipe or file argument." >&2 exit 1 fi # Try jq first if command -v jq &>/dev/null; then echo "$JSON_INPUT" | jq . exit 0 fi # If jq not found, try python -m json.tool if command -v python &>/dev/null; then echo "$JSON_INPUT" | python -m json.tool exit 0 fi # If python not found, try json_pp if command -v json_pp &>/dev/null; then echo "$JSON_INPUT" | json_pp exit 0 fi # If none found echo "Error: No JSON formatting tool found (need jq, python, or json_pp)." >&2 exit 1
Save this as
in your fmtjson
and make it executable ($PATH
).chmod +x fmtjson
Now you can use it like this:
# From a string (using echo and pipe)
echo '{"name": "Alice", "age": 30}' | fmtjson
# From a file
fmtjson config.json
# Example API call piped into fmtjson
curl -s "https://rickandmortyapi.com/api/character/1" | fmtjson
Handling Different Inputs (Files vs. Stdin)
The basic example already handles both piped input and a file argument. Let's refine this pattern. A common technique is to check if stdin is connected to a terminal (`-t 0`) or if there's a file argument.
Input Handling Pattern:
#!/bin/bash # Determine input source if [ -t 0 ]; then # Stdin is connected to a terminal, expect file argument if [ -z "$1" ]; then echo "Usage: $0 <json_file> [options]" >&2 exit 1 fi INPUT_SOURCE="$1" # Shift arguments if file is used, so options are $1, $2, etc. shift else # Input is from pipe (stdin) INPUT_SOURCE="/dev/stdin" fi # Now use INPUT_SOURCE with your JSON tool # Example using jq: if command -v jq &>/dev/null; then jq "$@" "$INPUT_SOURCE" else echo "jq not found!" >&2 exit 1 fi
In this pattern,
passes along any additional arguments provided to the wrapper script (like $@
filters).jq
Usage with this pattern:
# With a file and jq filter
my_jq_wrapper config.json '.users[] | .name'
# With piped input and jq filter
cat log.json | my_jq_wrapper '.errors | length'
Integrating Clipboard (macOS & Linux)
A very common use case is formatting JSON that you've copied to your clipboard. You can extend your wrapper to read from and write to the clipboard using OS-specific commands like
/pbcopy
(macOS) or pbpaste
/xclip
(Linux).xsel
Wrapper with Clipboard Support:
#!/bin/bash # JSON formatter with clipboard support # Usage: fmtjson [file] -> Format file content # ... | fmtjson -> Format piped content # fmtjson -p -> Format content from pasteboard (clipboard) # fmtjson -p | pbcopy # or xclip -selection clipboard -> Format clipboard and copy back INPUT_SOURCE="/dev/stdin" # Default to stdin USE_CLIPBOARD=false # Check for pasteboard flag (-p) if [ "$1" == "-p" ]; then USE_CLIPBOARD=true shift # Remove -p from arguments fi # Determine input source (file or stdin) if not using clipboard if ! $USE_CLIPBOARD; then if [ -t 0 ]; then # Stdin is terminal, expect file argument if [ -z "$1" ]; then echo "Usage: $0 [-p] <json_file> [options]" >&2 echo " ... | $0 [options]" >&2 echo " $0 -p [options]" >&2 exit 1 fi INPUT_SOURCE="$1" shift # Remove file from arguments fi fi # Get the JSON input if $USE_CLIPBOARD; then # Read from clipboard if command -v pbpaste &>/dev/null; then JSON_INPUT=$(pbpaste) elif command -v xclip &>/dev/null; then JSON_INPUT=$(xclip -selection clipboard -o) elif command -v xsel &>/dev/null; then JSON_INPUT=$(xsel -b -o) else echo "Error: Clipboard paste tool not found (need pbpaste, xclip, or xsel)." >&2 exit 1 fi elif [ "$INPUT_SOURCE" = "/dev/stdin" ]; then # Read from stdin (pipe) JSON_INPUT=$(cat) else # Read from file JSON_INPUT=$(cat "$INPUT_SOURCE") fi # --- Formatting Logic (using jq as example) --- # Use jq on the JSON_INPUT variable, passing remaining arguments if command -v jq &>/dev/null; then echo "$JSON_INPUT" | jq "$@" else echo "Error: jq not found. Cannot format JSON." >&2 exit 1 fi
This script adds a
flag to read from the clipboard. The output is printed to stdout, so you can pipe it back to the clipboard tool to format in place:-p
# Format JSON currently in clipboard (macOS)
fmtjson -p | pbcopy
# Format JSON currently in clipboard (Linux using xclip)
fmtjson -p | xclip -selection clipboard
Handling Files with Specific Extensions
You might want your wrapper to behave differently or use different tools based on the file extension, though for pure JSON this is less common than for other formats like YAML or XML. However, you could extend the idea to process
(JSON Lines) differently than standard .jsonl
..json
More Advanced Concepts
Error Handling:
Robust wrappers should include error checking, like ensuring the input is valid JSON before attempting to process it (though the tools themselves usually handle this). You can add checks for the presence of required commands (like
as shown) and provide informative error messages to the user via command -v jq
(standard error).>&2
Configuration:
Allow users to configure preferred tools or default options using environment variables. For example,
could tell the script to use the Python tool first.JSON_FORMATTER="python"
Parameterization:
Design your wrapper to accept arguments that are passed directly to the underlying tool, as shown in the input handling example passing
to $@
. This maintains the power of the tool while providing the wrapper's convenience.jq
Conclusion
Shell script wrappers are a powerful way to customize and simplify your command-line workflow for common tasks like JSON formatting. By abstracting tool specifics and handling different input methods, you can create convenient, consistent, and efficient commands tailored to your needs. Start with a simple pretty-printer and expand your wrapper as you discover more recurring JSON tasks.
Need help with your JSON?
Try our JSON Formatter tool to automatically identify and fix syntax errors in your JSON. JSON Formatter tool