-
-
Save Fordi/47bade5d63d4a6cb72c4b9df8e5185d1 to your computer and use it in GitHub Desktop.
Sourceable script to add `-i` / `--in-place` option to `jq`
This file contains hidden or 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
| #!/bin/bash | |
| # Add in-place editing support to `jq` | |
| # `source` it in your profile to wrap around `jq`, or run it directly | |
| JQ="${JQ:-"$(command -v jq)"}" | |
| function jq() { | |
| # Original command line, minus -i/--in-place, in its original order | |
| local passthrough=() | |
| local positionals=() | |
| local inplace= | |
| local help= | |
| local hasFromFile= | |
| local suppressRemainder= | |
| local arg | |
| local original=("${@}") | |
| while [[ $# -gt 0 ]]; do | |
| arg="${1}" | |
| shift | |
| case "${arg}" in | |
| -i|--in-place) | |
| inplace=true;; | |
| -h|--help) | |
| help=true;; | |
| # Options that consume the following two arguments | |
| --arg|--argjson|--slurpfile|--rawfile) | |
| passthrough+=("${arg}" "${1}" "${2}") | |
| shift 2 || break;; | |
| # Options that consume the following argument | |
| -f|--from-file) | |
| hasFromFile=true | |
| passthrough+=("${arg}" "${1}") | |
| shift || break;; | |
| --indent|-L) | |
| passthrough+=("${arg}" "${1}") | |
| shift || break;; | |
| # Everything after these is an argument for the filter, not a file | |
| --args|--jsonargs) | |
| suppressRemainder=true | |
| passthrough+=("${arg}");; | |
| -*) | |
| passthrough+=("${arg}");; | |
| *) | |
| passthrough+=("${arg}") | |
| if [[ -z "${suppressRemainder}" ]]; then | |
| positionals+=("${arg}") | |
| fi;; | |
| esac | |
| done | |
| # Inform the user of the new flag | |
| if [[ -n "${help}" ]]; then | |
| "${JQ}" --help | sed '/--null-input/a\ -i, --in-place update the file in-place;' || true | |
| return | |
| fi | |
| # If inplace wasn't flagged, just run JQ as normal | |
| if [[ -z "${inplace}" ]]; then | |
| "${JQ}" "${original[@]}" | |
| return $? | |
| fi | |
| # With -f, every positional is a file; otherwise the first is the filter. | |
| local files=("${positionals[@]}") | |
| if [[ -z "${hasFromFile}" ]]; then | |
| files=("${positionals[@]:1}") | |
| fi | |
| if [[ ${#files[@]} -ne 1 ]]; then | |
| echo "--in-place requires exactly one input file" >&2 | |
| return 1 | |
| fi | |
| local file="${files[0]}" | |
| local tmp ret | |
| tmp="$(mktemp)" | |
| rm -f "${tmp}" | |
| cp -dP "${file}" "${tmp}" | |
| "${JQ}" "${passthrough[@]}" > "${tmp}" | |
| ret=$? | |
| if [[ "${ret}" == "0" ]]; then | |
| mv "${tmp}" "${file}" | |
| else | |
| echo "Error: jq failed; \`${file}\` not modified" >&2 | |
| rm -f "${tmp}" | |
| return "${ret}" | |
| fi | |
| } | |
| if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then | |
| jq "${@}" | |
| fi |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment