json-config-loader

JSON & Config Loader

Safety Notice

This listing is imported from skills.sh public index metadata. Review upstream SKILL.md and repository scripts before running.

Copy this and send it to your AI assistant to learn

Install skill "json-config-loader" with this command: npx skills add vamseeachanta/workspace-hub/vamseeachanta-workspace-hub-json-config-loader

JSON & Config Loader

Patterns for loading, parsing, and generating configuration files in bash scripts. Supports key=value files, JSON with jq, and associative array management. Extracted from workspace-hub's configuration scripts.

When to Use This Skill

✅ Use when:

  • Loading configuration from files into bash scripts

  • Parsing key=value or INI-style configuration files

  • Working with JSON data using jq

  • Generating JSON reports from bash

  • Managing configuration with associative arrays

❌ Avoid when:

  • Complex nested configuration (consider Python instead)

  • Real-time configuration changes (use a daemon)

  • Configuration with complex validation rules

Core Capabilities

  1. Key=Value Configuration Parsing

Parse simple key=value configuration files:

#!/bin/bash

ABOUTME: Parse key=value configuration files

ABOUTME: Supports comments, empty lines, and quoted values

CONFIG_FILE="${1:-config.conf}"

Declare associative array for config

declare -A CONFIG

Parse configuration file

parse_config() { local file="$1"

if [[ ! -f "$file" ]]; then
    echo "Error: Config file not found: $file" >&2
    return 1
fi

while IFS= read -r line || [[ -n "$line" ]]; do
    # Skip comments and empty lines
    [[ "$line" =~ ^[[:space:]]*# ]] && continue
    [[ -z "${line// /}" ]] && continue

    # Parse key=value pairs
    if [[ "$line" =~ ^([^=]+)=(.*)$ ]]; then
        local key="${BASH_REMATCH[1]}"
        local value="${BASH_REMATCH[2]}"

        # Trim whitespace
        key="${key#"${key%%[![:space:]]*}"}"
        key="${key%"${key##*[![:space:]]}"}"
        value="${value#"${value%%[![:space:]]*}"}"
        value="${value%"${value##*[![:space:]]}"}"

        # Remove surrounding quotes if present
        if [[ "$value" =~ ^\"(.*)\"$ ]] || [[ "$value" =~ ^\'(.*)\'$ ]]; then
            value="${BASH_REMATCH[1]}"
        fi

        CONFIG["$key"]="$value"
    fi
done < "$file"

}

Get config value with default

get_config() { local key="$1" local default="${2:-}"

echo "${CONFIG[$key]:-$default}"

}

Check if key exists

has_config() { local key="$1" [[ -v CONFIG[$key] ]] }

Usage

parse_config "$CONFIG_FILE"

Access values

echo "Database: $(get_config 'database' 'default.db')" echo "Port: $(get_config 'port' '8080')"

if has_config 'debug'; then echo "Debug mode enabled" fi

  1. JSON Configuration with jq

Load and manipulate JSON configuration:

#!/bin/bash

ABOUTME: JSON configuration loading with jq

ABOUTME: Provides safe defaults and nested value access

Check jq dependency

check_jq() { if ! command -v jq &> /dev/null; then echo "Error: jq is required but not installed" >&2 echo "Install with: apt install jq (Ubuntu) or brew install jq (Mac)" >&2 exit 1 fi }

Load JSON config file

load_json_config() { local file="$1"

if [[ ! -f "$file" ]]; then
    echo "{}"
    return 1
fi

# Validate JSON
if ! jq empty "$file" 2>/dev/null; then
    echo "Error: Invalid JSON in $file" >&2
    echo "{}"
    return 1
fi

cat "$file"

}

Get value from JSON with default

json_get() { local json="$1" local path="$2" local default="${3:-}"

local value
value=$(echo "$json" | jq -r "$path // empty" 2>/dev/null)

if [[ -z "$value" || "$value" == "null" ]]; then
    echo "$default"
else
    echo "$value"
fi

}

Get array from JSON

json_get_array() { local json="$1" local path="$2"

echo "$json" | jq -r "$path[]? // empty" 2>/dev/null

}

Check if path exists in JSON

json_has() { local json="$1" local path="$2"

local result
result=$(echo "$json" | jq -e "$path != null" 2>/dev/null)
[[ "$result" == "true" ]]

}

Usage example

check_jq

CONFIG_JSON=$(load_json_config "config.json")

Access nested values

DB_HOST=$(json_get "$CONFIG_JSON" '.database.host' 'localhost') DB_PORT=$(json_get "$CONFIG_JSON" '.database.port' '5432') DEBUG=$(json_get "$CONFIG_JSON" '.settings.debug' 'false')

echo "Database: $DB_HOST:$DB_PORT" echo "Debug: $DEBUG"

Iterate array values

echo "Enabled features:" while IFS= read -r feature; do echo " - $feature" done < <(json_get_array "$CONFIG_JSON" '.features')

  1. JSON Report Generation

Generate structured JSON reports:

#!/bin/bash

ABOUTME: Generate JSON reports from bash data

ABOUTME: Uses jq for proper JSON encoding and structure

Generate simple JSON object

generate_json_object() { local -n data=$1 # Nameref to associative array

local json="{}"

for key in "${!data[@]}"; do
    local value="${data[$key]}"
    json=$(echo "$json" | jq --arg k "$key" --arg v "$value" '. + {($k): $v}')
done

echo "$json"

}

Generate JSON report with structure

generate_report() { local status="$1" local total="$2" local errors="$3" local warnings="$4"

jq -n \
    --arg status "$status" \
    --arg timestamp "$(date -Iseconds)" \
    --arg run_id "$(date +%Y%m%d-%H%M%S)" \
    --argjson total "$total" \
    --argjson errors "$errors" \
    --argjson warnings "$warnings" \
    '{
        metadata: {
            status: $status,
            timestamp: $timestamp,
            run_id: $run_id
        },
        summary: {
            total_processed: $total,
            errors: $errors,
            warnings: $warnings,
            success_rate: (if $total > 0 then (($total - $errors) * 100 / $total) else 0 end)
        }
    }'

}

Add items to JSON report

add_report_items() { local report="$1" shift local items=("$@")

# Convert items array to JSON array
local items_json="[]"
for item in "${items[@]}"; do
    items_json=$(echo "$items_json" | jq --arg i "$item" '. + [$i]')
done

echo "$report" | jq --argjson items "$items_json" '. + {items: $items}'

}

Save report to file

save_report() { local report="$1" local file="$2"

mkdir -p "$(dirname "$file")"
echo "$report" | jq '.' > "$file"

echo "Report saved: $file"

}

Usage

report=$(generate_report "success" 100 5 10) report=$(add_report_items "$report" "item1" "item2" "item3") save_report "$report" "reports/analysis-$(date +%Y%m%d).json"

  1. Multi-Section INI Parsing

Parse INI-style files with sections:

#!/bin/bash

ABOUTME: Parse INI-style configuration with sections

ABOUTME: Supports [section] headers and section.key access

declare -A INI_CONFIG declare -a INI_SECTIONS=()

parse_ini() { local file="$1" local current_section="default"

if [[ ! -f "$file" ]]; then
    echo "Error: INI file not found: $file" >&#x26;2
    return 1
fi

INI_SECTIONS=("default")

while IFS= read -r line || [[ -n "$line" ]]; do
    # Skip comments and empty lines
    [[ "$line" =~ ^[[:space:]]*[#\;] ]] &#x26;&#x26; continue
    [[ -z "${line// /}" ]] &#x26;&#x26; continue

    # Section header
    if [[ "$line" =~ ^\[([^\]]+)\] ]]; then
        current_section="${BASH_REMATCH[1]}"
        INI_SECTIONS+=("$current_section")
        continue
    fi

    # Key=value within section
    if [[ "$line" =~ ^([^=]+)=(.*)$ ]]; then
        local key="${BASH_REMATCH[1]}"
        local value="${BASH_REMATCH[2]}"

        # Trim whitespace
        key="${key#"${key%%[![:space:]]*}"}"
        key="${key%"${key##*[![:space:]]}"}"
        value="${value#"${value%%[![:space:]]*}"}"
        value="${value%"${value##*[![:space:]]}"}"

        # Store as section.key
        INI_CONFIG["${current_section}.${key}"]="$value"
    fi
done &#x3C; "$file"

}

Get INI value

ini_get() { local section="$1" local key="$2" local default="${3:-}"

echo "${INI_CONFIG["${section}.${key}"]:-$default}"

}

Get all keys in a section

ini_section_keys() { local section="$1" local prefix="${section}."

for key in "${!INI_CONFIG[@]}"; do
    if [[ "$key" == "${prefix}"* ]]; then
        echo "${key#$prefix}"
    fi
done

}

List all sections

ini_sections() { printf '%s\n' "${INI_SECTIONS[@]}" | sort -u }

Usage

parse_ini "settings.ini"

Access values

DB_HOST=$(ini_get "database" "host" "localhost") DB_PORT=$(ini_get "database" "port" "5432") LOG_LEVEL=$(ini_get "logging" "level" "INFO")

echo "Database: $DB_HOST:$DB_PORT" echo "Log Level: $LOG_LEVEL"

Iterate section keys

echo "Database settings:" for key in $(ini_section_keys "database"); do echo " $key = $(ini_get "database" "$key")" done

  1. Environment Variable Configuration

Load configuration with environment variable overrides:

#!/bin/bash

ABOUTME: Configuration with environment variable overrides

ABOUTME: File config < Environment variable precedence

declare -A APP_CONFIG

Load config with env override support

load_config_with_env() { local file="$1" local prefix="${2:-APP_}" # Environment variable prefix

# First load from file
if [[ -f "$file" ]]; then
    while IFS= read -r line || [[ -n "$line" ]]; do
        [[ "$line" =~ ^[[:space:]]*# ]] &#x26;&#x26; continue
        [[ -z "${line// /}" ]] &#x26;&#x26; continue

        if [[ "$line" =~ ^([^=]+)=(.*)$ ]]; then
            local key="${BASH_REMATCH[1]}"
            local value="${BASH_REMATCH[2]}"

            key="${key#"${key%%[![:space:]]*}"}"
            key="${key%"${key##*[![:space:]]}"}"

            APP_CONFIG["$key"]="$value"
        fi
    done &#x3C; "$file"
fi

# Override with environment variables
for key in "${!APP_CONFIG[@]}"; do
    local env_key="${prefix}${key^^}"  # Convert to UPPER_CASE
    env_key="${env_key//-/_}"          # Replace - with _

    if [[ -v "$env_key" ]]; then
        APP_CONFIG["$key"]="${!env_key}"
    fi
done

}

Check required config keys

require_config() { local missing=()

for key in "$@"; do
    if [[ -z "${APP_CONFIG[$key]:-}" ]]; then
        missing+=("$key")
    fi
done

if [[ ${#missing[@]} -gt 0 ]]; then
    echo "Error: Missing required configuration:" >&#x26;2
    printf "  - %s\n" "${missing[@]}" >&#x26;2
    return 1
fi

return 0

}

Get config with type conversion

config_string() { local key="$1" local default="${2:-}" echo "${APP_CONFIG[$key]:-$default}" }

config_int() { local key="$1" local default="${2:-0}" local value="${APP_CONFIG[$key]:-$default}"

if [[ "$value" =~ ^-?[0-9]+$ ]]; then
    echo "$value"
else
    echo "$default"
fi

}

config_bool() { local key="$1" local default="${2:-false}" local value="${APP_CONFIG[$key]:-$default}"

case "${value,,}" in
    true|yes|1|on) echo "true" ;;
    false|no|0|off) echo "false" ;;
    *) echo "$default" ;;
esac

}

Usage

load_config_with_env "app.conf" "MYAPP_"

Check required keys

require_config "api_key" "database_url" || exit 1

Access with type conversion

PORT=$(config_int "port" 8080) DEBUG=$(config_bool "debug" false) API_KEY=$(config_string "api_key")

echo "Starting on port $PORT (debug: $DEBUG)"

  1. YAML Configuration (via yq)

Parse YAML files when yq is available:

#!/bin/bash

ABOUTME: YAML configuration parsing with yq

ABOUTME: Falls back to jq for JSON subset of YAML

Check for yaml parser

get_yaml_parser() { if command -v yq &> /dev/null; then echo "yq" elif command -v jq &> /dev/null; then echo "jq" # Can parse YAML's JSON subset else echo "none" fi }

Load YAML config

load_yaml_config() { local file="$1" local parser parser=$(get_yaml_parser)

if [[ ! -f "$file" ]]; then
    echo "{}"
    return 1
fi

case "$parser" in
    yq)
        yq -o=json "$file" 2>/dev/null || echo "{}"
        ;;
    jq)
        # Try to parse as JSON (YAML subset)
        jq '.' "$file" 2>/dev/null || echo "{}"
        ;;
    *)
        echo "Error: No YAML parser available (install yq or jq)" >&#x26;2
        echo "{}"
        return 1
        ;;
esac

}

Get YAML value (returns as JSON for jq processing)

yaml_get() { local file="$1" local path="$2" local default="${3:-}"

local parser
parser=$(get_yaml_parser)

local value
case "$parser" in
    yq)
        value=$(yq -r "$path // \"$default\"" "$file" 2>/dev/null)
        ;;
    jq)
        value=$(jq -r "$path // \"$default\"" "$file" 2>/dev/null)
        ;;
    *)
        value="$default"
        ;;
esac

if [[ -z "$value" || "$value" == "null" ]]; then
    echo "$default"
else
    echo "$value"
fi

}

Usage

CONFIG_FILE="config.yaml"

Load entire config as JSON

CONFIG_JSON=$(load_yaml_config "$CONFIG_FILE")

Or get specific values

DB_HOST=$(yaml_get "$CONFIG_FILE" '.database.host' 'localhost') DB_PORT=$(yaml_get "$CONFIG_FILE" '.database.port' '5432')

echo "Database: $DB_HOST:$DB_PORT"

Complete Example: Config Manager

Full configuration management with multiple formats:

#!/bin/bash

ABOUTME: Universal configuration manager

ABOUTME: Supports key=value, JSON, and environment overrides

set -e

─────────────────────────────────────────────────────────────────

Configuration Storage

─────────────────────────────────────────────────────────────────

declare -A CONFIG CONFIG_FILE="" CONFIG_FORMAT=""

─────────────────────────────────────────────────────────────────

Format Detection

─────────────────────────────────────────────────────────────────

detect_format() { local file="$1"

case "${file##*.}" in
    json) echo "json" ;;
    yaml|yml) echo "yaml" ;;
    ini) echo "ini" ;;
    *) echo "keyvalue" ;;
esac

}

─────────────────────────────────────────────────────────────────

Loaders

─────────────────────────────────────────────────────────────────

load_keyvalue() { local file="$1"

while IFS= read -r line || [[ -n "$line" ]]; do
    [[ "$line" =~ ^[[:space:]]*# ]] &#x26;&#x26; continue
    [[ -z "${line// /}" ]] &#x26;&#x26; continue

    if [[ "$line" =~ ^([^=]+)=(.*)$ ]]; then
        local key="${BASH_REMATCH[1]// /}"
        local value="${BASH_REMATCH[2]}"
        value="${value#"${value%%[![:space:]]*}"}"
        CONFIG["$key"]="$value"
    fi
done &#x3C; "$file"

}

load_json() { local file="$1"

if ! command -v jq &#x26;> /dev/null; then
    echo "Error: jq required for JSON config" >&#x26;2
    return 1
fi

# Flatten JSON to key=value pairs
while IFS="=" read -r key value; do
    CONFIG["$key"]="$value"
done &#x3C; &#x3C;(jq -r 'paths(scalars) as $p | "\($p | join("."))"+"="+"\(getpath($p))"' "$file" 2>/dev/null)

}

─────────────────────────────────────────────────────────────────

Main API

─────────────────────────────────────────────────────────────────

config_load() { local file="$1" local env_prefix="${2:-}"

if [[ ! -f "$file" ]]; then
    echo "Error: Config file not found: $file" >&#x26;2
    return 1
fi

CONFIG=()
CONFIG_FILE="$file"
CONFIG_FORMAT=$(detect_format "$file")

case "$CONFIG_FORMAT" in
    json) load_json "$file" ;;
    *) load_keyvalue "$file" ;;
esac

# Apply environment overrides
if [[ -n "$env_prefix" ]]; then
    for key in "${!CONFIG[@]}"; do
        local env_key="${env_prefix}${key^^}"
        env_key="${env_key//./_}"
        env_key="${env_key//-/_}"

        if [[ -v "$env_key" ]]; then
            CONFIG["$key"]="${!env_key}"
        fi
    done
fi

echo "Loaded ${#CONFIG[@]} config values from $file ($CONFIG_FORMAT)"

}

config_get() { local key="$1" local default="${2:-}" echo "${CONFIG[$key]:-$default}" }

config_set() { local key="$1" local value="$2" CONFIG["$key"]="$value" }

config_has() { [[ -v CONFIG[$1] ]] }

config_keys() { printf '%s\n' "${!CONFIG[@]}" | sort }

config_dump() { echo "# Configuration ($CONFIG_FORMAT from $CONFIG_FILE)" for key in $(config_keys); do echo "$key=${CONFIG[$key]}" done }

config_to_json() { local json="{}"

for key in "${!CONFIG[@]}"; do
    json=$(echo "$json" | jq --arg k "$key" --arg v "${CONFIG[$key]}" '. + {($k): $v}')
done

echo "$json" | jq '.'

}

─────────────────────────────────────────────────────────────────

Validation

─────────────────────────────────────────────────────────────────

config_require() { local missing=()

for key in "$@"; do
    if ! config_has "$key" || [[ -z "$(config_get "$key")" ]]; then
        missing+=("$key")
    fi
done

if [[ ${#missing[@]} -gt 0 ]]; then
    echo "Error: Missing required config keys:" >&#x26;2
    printf "  - %s\n" "${missing[@]}" >&#x26;2
    return 1
fi

}

config_validate_int() { local key="$1" local value value=$(config_get "$key")

if [[ -n "$value" &#x26;&#x26; ! "$value" =~ ^-?[0-9]+$ ]]; then
    echo "Error: $key must be an integer (got: $value)" >&#x26;2
    return 1
fi

}

config_validate_url() { local key="$1" local value value=$(config_get "$key")

if [[ -n "$value" &#x26;&#x26; ! "$value" =~ ^https?:// ]]; then
    echo "Error: $key must be a URL (got: $value)" >&#x26;2
    return 1
fi

}

─────────────────────────────────────────────────────────────────

Usage Example

─────────────────────────────────────────────────────────────────

if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then # Load config with APP_ prefix for env overrides config_load "${1:-config.conf}" "APP_"

# Validate required keys
config_require "database_host" "api_key" || exit 1

# Validate types
config_validate_int "port" || exit 1
config_validate_url "api_endpoint" || exit 1

# Use config values
echo "Host: $(config_get 'database_host' 'localhost')"
echo "Port: $(config_get 'port' '5432')"

# Dump all config
echo ""
config_dump

fi

Best Practices

  1. Always Provide Defaults

value=$(config_get "key" "default_value")

  1. Validate Early

config_require "api_key" "database_url" || exit 1

  1. Use Environment Overrides for Secrets

Don't store secrets in files

API_KEY="${API_KEY:-$(config_get 'api_key')}"

  1. Validate JSON with jq

if ! jq empty "$file" 2>/dev/null; then echo "Invalid JSON" >&2 exit 1 fi

  1. Handle Missing Files Gracefully

if [[ -f "$config_file" ]]; then load_config "$config_file" else echo "Warning: Config not found, using defaults" >&2 fi

Resources

  • jq Manual

  • yq Documentation

  • Bash Associative Arrays

Version History

  • 1.0.0 (2026-01-14): Initial release - extracted from workspace-hub configuration scripts

Source Transparency

This detail page is rendered from real SKILL.md content. Trust labels are metadata-based hints, not a safety guarantee.

Related Skills

Related by shared tags or category signals.

General

echarts

No summary provided by upstream source.

Repository SourceNeeds Review
General

pandoc

No summary provided by upstream source.

Repository SourceNeeds Review
General

mkdocs

No summary provided by upstream source.

Repository SourceNeeds Review
General

gis

No summary provided by upstream source.

Repository SourceNeeds Review