Analizar lsblk con jq

Analizar lsblk con jq

Actualmente estoy intentando analizar la salida de lsblk con jq y filtrarla según algunos criterios.

Dado el siguiente ejemplo de salida:

{
   "blockdevices": [
      {
         "name": "/dev/sda",
         "fstype": null,
         "size": "931.5G",
         "mountpoint": null,
         "children": [
            {
               "name": "/dev/sda1",
               "fstype": "ntfs",
               "size": "50M",
               "mountpoint": null
            },{
               "name": "/dev/sda2",
               "fstype": "ntfs",
               "size": "439.8G",
               "mountpoint": null
            },{
               "name": "/dev/sda3",
               "fstype": "vfat",
               "size": "512M",
               "mountpoint": "/boot/efi"
            },{
               "name": "/dev/sda4",
               "fstype": "ext4",
               "size": "491.2G",
               "mountpoint": "/"
            }
         ]
      },{
         "name": "/dev/sdb",
         "fstype": "crypto_LUKS",
         "size": "200GG",
         "mountpoint": null,
         "children": [
            {
               "name": "/dev/mapper/d1",
               "fstype": "btrfs",
               "size": "200G",
               "mountpoint":[
                  null
               ]
            }
         ]
      },{
         "name": "/dev/sdc",
         "fstype": "crypto_LUKS",
         "size": "100G",
         "mountpoint": null,
         "children": [
            {
               "name": "/dev/mapper/abc2",
               "fstype": "btrfs",
               "size": "100GG",
               "mountpoint": "/mnt/test"
            }
         ]
      }
   ]
}

Quiero repasar todos los dispositivos de nivel superior que tienen fstype "crypto_LUKS". Luego, para esos dispositivos, quiero verificar si los hijos (si están presentes) tienen un punto de montaje (no nulo). Finalmente quiero devolver el nombre del dispositivo de nivel superior que coincida con ambos criterios.

Entonces, para el ejemplo anterior, solo se devolverá 1 coincidencia: /dev/sdc /dev/mapper/d1.

El /dev/sdcdispositivo no se devolverá porque el punto de montaje del dispositivo secundario es nulo/vacío.

Ya tengo esto hasta ahora:

lsblk -Jpo NAME,FSTYPE,SIZE,MOUNTPOINT | jq -r '.blockdevices[] | select(.fstype == "crypto_LUKS") '

Pero esto sólo comprueba los criterios crypto_LUKS, y no los puntos de montaje de los hijos. También imprime la entrada completa de la matriz en lugar de solo los dos valores.

¿Como puedo resolver esto?

Respuesta1

Para obtener el nombre del dispositivo de bloque y cada uno de sus puntos de montaje secundarios no nulos como una lista delimitada por tabulaciones:

jq -r '
    .blockdevices[]  | select(.fstype == "crypto_LUKS") as $dev |
    $dev.children[]? | select(.mountpoint | type == "string") as $mp |
    [ $dev.name, $mp.name ] | @tsv'

Dado que un "punto de montaje nulo" en realidad no es nullsino una matriz de un solo nullvalor, en lugar de eso estoy probando si el punto de montaje es una cadena o no.

Dados los datos de la pregunta, esto devolvería

/dev/sdc        /dev/mapper/abc2

Para obtener los objetos del dispositivo de bloque que cumplen con los criterios (si eso es lo que quiere decir con "toda la matriz"):

jq '.blockdevices[] |
    select(.fstype == "crypto_LUKS" and
           any(.children[]?; .mountpoint | type == "string"))'

Esto devuelve el objeto de dispositivo de bloque que tiene el fstypevalor crypto_LUKSy que tiene al menos un childrenelemento con mountpointuna cadena.

Dados los datos de la pregunta, esto devolvería

{
  "name": "/dev/sdc",
  "fstype": "crypto_LUKS",
  "size": "100G",
  "mountpoint": null,
  "children": [
    {
      "name": "/dev/mapper/abc2",
      "fstype": "btrfs",
      "size": "100GG",
      "mountpoint": "/mnt/test"
    }
  ]
}

información relacionada