Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

I have a json file that needs to be updated on a certain condition.

Sample json

{    "Actions" : [       {          "value" : "1",          "properties" : {             "name" : "abc",             "age" : "2",             "other ": "test1"           }       },       {          "value" : "2",          "properties" : {             "name" : "def",             "age" : "3",             "other" : "test2"           }       }    ] } 

I am writing a script that makes use of Jq to match a value and update, as shown below

cat sample.json |  jq '.Actions[] | select (.properties.age == "3") .properties.other = "no-test"' 

Output (printed to terminal)

{   "value": "1",   "properties": {     "name": "abc",     "age": "2",     "other ": "test1"   } } {   "value": "2",   "properties": {     "name": "def",     "age": "3",     "other": "no-test"   } } 

While this command makes the needed change, it outputs the entire json on the terminal and does not make change to the file itself.

Please advise if there is an option to have jq make changes on the file directly (similar to sed -i).

like image 721
Supra Avatar asked Apr 12 '16 06:04

Supra


People also ask

How does sed command can be used to replace the content of any file?

By default, sed reads the file line by line and changes only the first occurrence of the SEARCH_REGEX on a line. When the replacement flag is provided, all occurrences are replaced. INPUTFILE - The name of the file on which you want to run the command.

Which sed command is used for replacement?

The s command (as in substitute) is probably the most important in sed and has a lot of different options. The syntax of the s command is ' s/ regexp / replacement / flags '.

What is S in sed command?

Substitution command In some versions of sed, the expression must be preceded by -e to indicate that an expression follows. The s stands for substitute, while the g stands for global, which means that all matching occurrences in the line would be replaced.


2 Answers

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 
like image 136
peak Avatar answered Oct 03 '22 12:10

peak


instead of sponge :

cat <<< $(jq 'QUERY' sample.json) > sample.json 
like image 22
moriaki Avatar answered Oct 03 '22 12:10

moriaki