Jq to replace text directly on file (like sed -i)

This post addresses the question about the absence of the equivalent of sed’s “-i” option, and in particular the situation described:

I have a bunch of files and writing each one to a separate file wouldn’t be easy.

There are several options, at least if you are working in a Mac or Linux or similar environment. Their pros and cons are discussed at
http://backreference.org/2011/01/29/in-place-editing-of-files/
so I’ll focus on just three techniques:

One is simply to use “&&” along the lines of:

jq ... INPUT > INPUT.tmp && mv INPUT.tmp INPUT

Another is to use the sponge utility (part of GNU moreutils):

jq ... INPUT | sponge INPUT

The third option might be useful if it is advantageous to avoid updating a file if there are no changes to it. Here is a script which illustrates such a function:

#!/bin/bash

function maybeupdate {
    local f="$1"
    cmp -s "$f" "$f.tmp"
    if [ $? = 0 ] ; then
      /bin/rm $f.tmp
    else
      /bin/mv "$f.tmp" "$f"
    fi
}

for f
do
    jq . "$f" > "$f.tmp"
    maybeupdate "$f"
done

Leave a Comment