skip to Main Content

I try to reformat the output of the sensors command:

sensors -j ftsteutates-i2c-0-73
{
   "ftsteutates-i2c-0-73":{
      "Adapter": "SMBus I801 adapter at efa0",
      "VCC 3.3V":{
         "in0_input": 3.331
      },
      "3.3V AUX":{
         "in1_input": 3.359
      },
      "V_IN (12V)":{
         "in2_input": 12.012
      },
      "VBAT 3.0V":{
         "in3_input": 2.692
      },
      "CPU":{
         "fan1_input": 660.000,
         "fan1_alarm": 0.000,
         "fan1_fault": 0.000
      },
      "Chassis":{
         "fan3_input": 1200.000,
         "fan3_alarm": 0.000,
         "fan3_fault": 0.000
      },
      "CPU":{
         "temp1_input": 51.000,
         "temp1_alarm": 0.000,
         "temp1_fault": 0.000
      },
      "Ambient":{
         "temp2_input": 44.000,
         "temp2_alarm": 0.000,
         "temp2_fault": 0.000
      },
      "Core":{
         "temp3_input": 54.000,
         "temp3_alarm": 0.000,
         "temp3_fault": 0.000
      },
      "Memory":{
         "temp4_input": 42.000,
         "temp4_alarm": 0.000,
         "temp4_fault": 0.000
      },
      "PCH":{
         "temp5_input": 54.000,
         "temp5_alarm": 0.000,
         "temp5_fault": 0.000
      },
      "Graphics":{
         "temp6_input": 40.000,
         "temp6_alarm": 0.000,
         "temp6_fault": 0.000
      }
   }
}

What I am expecting is:

sensors -j ftsteutates-i2c-0-73 | jq '."ftsteutates-i2c-0-73" | del(."Adapter") | ???' 
{
  "VCC 3.3V": 3.331,
  "3.3V AUX": 3.359,
  "V_IN (12V)": 12.012,
  "VBAT 3.0V": 2.692,
  "CPU": 51.000,
  "Chassis": 1200.000,
  "Ambient": 44.000,
  "Core": 54.000,
  "Memory": 42.000,
  "PCH": 54.000,
  "Graphics": 40.000
}

But I cant figure out how to Map the values of the subkeys and also delete the *_alarm and *_fault subkeys or select just the first subkey which is always the *_input key.

EDIT:
I found, that the temp and fan values from CPU get joined, which need to be keeped.

Maybe it is possible to match the part of the subkey name in/fan/temp and join it together in the output name like:

sensors -j ftsteutates-i2c-0-73 | jq '."ftsteutates-i2c-0-73" | del(."Adapter") | ???' 
{
  "VCC 3.3V_in": 3.331,
  "3.3V AUX_in": 3.359,
  "V_IN (12V)_in": 12.012,
  "VBAT 3.0V_in": 2.692,
  "CPU_fan": 51.000,
  "Chassis_fan": 1200.000,
  "Ambient_temp": 44.000,
  "Core_temp": 54.000,
  "Memory_temp": 42.000,
  "PCH_temp": 54.000,
  "Graphics_temp": 40.000
}

Somehow like (dosnt work)

sensors -j ftsteutates-i2c-0-73 | jq '."ftsteutates-i2c-0-73" | del(."Adapter") | with_entries(.key |= gsub(" "; "_") | .value |= with_entries(select(.key | endswith("_input")) | .key |= gsub("_input"; "_in") | .key |= gsub("temp"; "_temp") | .key |= gsub("fan"; "_fan"))) | with_entries(.value |= if type == "object" then .[] else . end)'

or

sensors -j ftsteutates-i2c-0-73 | jq '."ftsteutates-i2c-0-73" | del(."Adapter") | with_entries(.value |= if type == "object" then with_entries(select(.key | endswith("_input")) | .key |= gsub("_input"; "_in") | .key |= gsub("temp"; "_temp") | .key |= gsub("fan"; "_fan")) else . end) | with_entries(.value |= if type == "object" then .[] else . end)'

3

Answers


  1. Chosen as BEST ANSWER

    I got the right answer:

    sensors -j ftsteutates-i2c-0-73 | jq '
      ."ftsteutates-i2c-0-73"
      | del(."Adapter")
      | with_entries(.value |= 
          if type == "object" 
          then with_entries(select(.key
                                   | endswith("_input")))
          | .[] 
          else . end)'
    

    This command does the following:

    with_entries(.value |= if type == "object" then with_entries(select(.key | endswith("_input"))) | .[] else . end): 
    

    Iterates over each key-value pair, and if the value is an object, it selects the entries where the key ends with _input and then extracts the value.

    This give me the desired output.

    https://jqplay.org/s/KLkFpP0Q2yN3f9j


  2. Here’s another way using the error suppression operator ? (with jq 1.7+):

    jq '."ftsteutates-i2c-0-73" | .[] |= (.[keys[] | select(endswith("_input"))])?'
    

    Demo

    For older versions, just add another types filter for objects (with jq 1.6+):

    jq '."ftsteutates-i2c-0-73" | .[] |= (objects | .[keys[] | select(endswith("_input"))])'
    

    Demo

    Not recommended, but if the field ending with _input is always encoded as the first one, you could even shorten this with jq 1.7+ to:

    jq '."ftsteutates-i2c-0-73" | .[] |= .[]?'   # or .[] |= objects[]
    

    Demo

    Result (due to its type, the Adapter field was deleted implicitly):

    {
      "VCC 3.3V": 3.331,
      "3.3V AUX": 3.359,
      "V_IN (12V)": 12.012,
      "VBAT 3.0V": 2.692,
      "CPU": 51.000,
      "Chassis": 1200.000,
      "Ambient": 44.000,
      "Core": 54.000,
      "Memory": 42.000,
      "PCH": 54.000,
      "Graphics": 40.000
    }
    

    EDIT: I found, that the temp and fan values from CPU get joined, which need to be keeped.

    Maybe it is possible to match the part of the subkey name in/fan/temp and join it together in the output name

    You’d need to --stream the input at invocation in order to process broken-down parts individually, before they are collapsed in a superordinate structure Here’s one way:

    jq --stream -n '[inputs | select(.[0][0] == "ftsteutates-i2c-0-73") | {
      key: "(.[0][1])_(.[0][2] | strings | scan("^([a-z]+)\d+_input$")[0])", 
      value: .[1] | values
    }] | from_entries'
    
    {
      "VCC 3.3V_in": 3.331,
      "3.3V AUX_in": 3.359,
      "V_IN (12V)_in": 12.012,
      "VBAT 3.0V_in": 2.692,
      "CPU_fan": 660.000,
      "Chassis_fan": 1200.000,
      "CPU_temp": 51.000,
      "Ambient_temp": 44.000,
      "Core_temp": 54.000,
      "Memory_temp": 42.000,
      "PCH_temp": 54.000,
      "Graphics_temp": 40.000
    }
    
    Login or Signup to reply.
  3. A simple solution using jq:

    .["ftsteutates-i2c-0-73"] | map_values(objects | .[(keys[] | select(endswith("_input")))])
    

    How it works:

    .["ftsteutates-i2c-0-73"].     # extract the interesting object
    | map_values(                  # process its values, preserve the keys association
        objects                    # process only the values that are object (ignore "Adapter")
        | .[                              # extract only some properties of these objects
            keys[] |                      # choose the keys...
            select(endswith("_input"))    # ...ending in "_input"
          ]                               # yield the values of the chosen keys
      )
    

    See it online.

    h3. Remarks

    • if multiple keys ending in _input are present in an object, the value associated to the last one is returned;
    • the sample data contains the key CPU two times;
      depending on the JSON implementation, this can be reported as invalid
      JSON or one of the keys is ignored (usually the last occurrence
      overwrites any previous occurrences); this is also how jq works.
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search