jsonstreameditjqdeluge

Handling multiple top level elements with jq


I'm trying to modify the deluge web.conf file with jq and I'm having some issues. The deluge web config seems to be invalid json

{
  "file": 1,
  "format": 1
}
{
  "sidebar_show_zero": false,
  "show_session_speed": false,
  "pwd_sha1": "CHANGEME",
  "show_sidebar": true,
  "sessions": {},
  "enabled_plugins": [],
  "base": "/",
  "first_login": true,
  "theme": "gray",
  "pkey": "ssl/daemon.pkey",
  "default_daemon": "",
  "cert": "test",
  "session_timeout": 3600,
  "https": false,
  "interface": "0.0.0.0",
  "sidebar_multiple_filters": true,
  "pwd_salt": "salt",
  "port": 8112
}

It has multiple top level elements which aren't separated by a comma so if I try to edit the file with jq using something like this jq '.pwd_sha1 = "NEW HASH"' web.conf I get the following

{
  "file": 1,
  "format": 1,
  "pwd_sha1": "NEW HASH"
}
{
  "sidebar_show_zero": false,
  "show_session_speed": false,
  "pwd_sha1": "NEW HASH",
  "show_sidebar": true,
  "sessions": {},
  "enabled_plugins": [],
  "base": "/",
  "first_login": true,
  "theme": "gray",
  "pkey": "ssl/daemon.pkey",
  "default_daemon": "",
  "cert": "test",
  "session_timeout": 3600,
  "https": false,
  "interface": "0.0.0.0",
  "sidebar_multiple_filters": true,
  "pwd_salt": "salt",
  "port": 8112
}

jq is adding a new element to the first top level object and changing the second top level element's value. How can I get this to only change the existing item in the second top level element?


Solution

  • The web.conf you show is a stream of JSON entities. Fortunately for you, jq is stream-oriented, and it appears from your example that you could simply write:

    jq 'if .pwd_sha1 then .pwd_sha1 = "NEW HASH" else . end' web.conf
    

    In general, though, it might be more appropriate to write something with a more stringent test, e.g.

    jq 'if type == "object" and has("pwd_sha1") 
      then .pwd_sha1 = "NEW HASH" else . end' web.conf
    

    "changing the second top level element's value"

    To edit the second top-level item only, you could use foreach inputs with the -n command-line option:

    foreach inputs as $in (0; .+1; 
      if . == 2 then $in | .pwd_sha1 = "NEW_HASH" 
      else $in end)