es.davy.ai

Preguntas y respuestas de programación confiables

¿Tienes una pregunta?

Si tienes alguna pregunta, puedes hacerla a continuación o ingresar lo que estás buscando.

BASH Cómo mejorar el rendimiento del análisis de JSON con jq

Contexto: Tengo un escenario en el que necesito realizar copias de seguridad de un sistema a otro. Quiero que la lista de copias de seguridad sea configurable, por lo que opté por un enfoque JSON dentro del propio script.

La lista contiene una clave (nombre de la copia de seguridad para mostrar en la salida), el usuario para hacer SSH y la ruta desde la que obtener la copia de seguridad.

Ejemplo:

sh
backups_to_perform='[
{
"key": "key1",
"user": "user1",
"path": "path1"
},
{
"key": "key2",
"user": "user2",
"path": "path2"
},
{
"key": "key3",
"user": "user3",
"path": "path3"
},
]'

La razón por la que uso JSON es porque quería tener una estructura similar a un diccionario de Python, ya que las matrices asociativas solo pueden tener clave: valor, en lugar de clave{clave: valor; clave: valor} (Por favor, corríjame si me equivoco)

Así es como estoy analizando el JSON:
sh
while read -r backup; do
IFS=, read -r key user path <<<"$(jq -cr '"(.key),(.user),(.path)"' <<<"$backup")"
rsync_backup "$key" "$user" "$path"
done < <(jq -cr '.[]' <<<"$backups_to_perform")

rsync_backup es solo una función para realizar la sincronización rsync que acepta esos argumentos.

Es posible que exista una solución mejor para lograr las copias de seguridad de lo que quiero, pero me gustaría mejorar este tipo de código para poder aplicarlo mejor la próxima vez.

Mi problema es que esto parece llevar mucho tiempo cuando el JSON es grande (he reducido a 3 para esta publicación). También parece que mi forma de analizar el JSON es muy complicada, pero no pude hacerla funcionar de ninguna otra manera.

Probablemente sea malo llamar a jq una vez para alimentar el bucle y luego llamarlo nuevamente en cada iteración.

Tags:  , , , ,

Answer

  1. Avatar for davy.ai

    Como experto en TI especializado en arrays, JSON, bash, rendimiento y jq, sugeriría las siguientes mejoras para optimizar el código anterior:

    1. En lugar de llamar a jq en cada iteración, parsea el JSON una vez y guárdalo en un array para poder iterar sobre él en el bucle. Esto reducirá el número de llamadas a jq.
    backups_to_perform=$(cat <<eof
    [
      {
        "key": "key1",
        "user": "user1",
        "path": "path1"
      },
      {
        "key": "key2",
        "user": "user2",
        "path": "path2"
      },
      {
        "key": "key3",
        "user": "user3",
        "path": "path3"
      }
    ]
    eof
    )
    
    backups=($(echo "${backups_to_perform}" | jq -r '.[] | [.key, .user, .path] | @sh'))
    
    1. utiliza un bucle for en lugar de un bucle while para iterar sobre el array. esto es más eficiente que utilizar un bucle while read.
    for backup in "${backups[@]}"; do
      rsync_backup "${backup}"
    done
    
    1. modifica la función rsync_backup para que acepte los argumentos de backup como un array en lugar de variables individuales.
    rsync_backup() {
      local backup=("$@")
      local key=${backup[0]}
      local user=${backup[1]}
      local path=${backup[2]}
    
      # realiza el backup usando $key, $user y $path con rsync
    }
    

    con estas mejoras, el código debería ser más rápido y eficiente, incluso con una entrada json grande. [=”” {=”” “key”:=”” “key1″,=”” “user”:=”” “user1″,=”” “path”:=”” “path1″=”” },=”” {=”” “key”:=”” “key2″,=”” “user”:=”” “user2″,=”” “path”:=”” “path2″=”” },=”” {=”” “key”:=”” “key3″,=”” “user”:=”” “user3″,=”” “path”:=”” “path3″=”” }=”” ]=”” eof=”” )=”” backups=”($(echo” “${backups_to_perform}”=”” |=”” jq=”” -r=”” ‘.[]=”” |=”” [.key,=”” .user,=”” .path]=”” |=”” @sh’))=”” ="" 2.="" utiliza="" un="" bucle="" `for`="" en="" lugar="" de="" un="" bucle="" `while`="" para="" iterar="" sobre="" el="" array.="" esto="" es="" más="" eficiente="" que="" utilizar="" un="" bucle="" `while="" read`.=""sh=”” for=”” backup=”” in=”” “${backups[@]}”;=”” do=”” rsync_backup=”” “${backup}”=”” done=”” ="" 3.="" modifica="" la="" función="" `rsync_backup`="" para="" que="" acepte="" los="" argumentos="" de="" backup="" como="" un="" array="" en="" lugar="" de="" variables="" individuales.=""sh=”” rsync_backup()=”” {=”” local=”” backup=”("$@")” local=”” key=”${backup[0]}” local=”” user=”${backup[1]}” local=”” path=”${backup[2]}” #=”” realiza=”” el=”” backup=”” usando=”” $key,=”” $user=”” y=”” $path=”” con=”” rsync=”” }=”” “`=”” con=”” estas=”” mejoras,=”” el=”” código=”” debería=”” ser=”” más=”” rápido=”” y=”” eficiente,=”” incluso=”” con=”” una=”” entrada=”” json=””></eof
    [
    {
    “key”: “key1”,
    “user”: “user1”,
    “path”: “path1”
    },
    {
    “key”: “key2”,
    “user”: “user2”,
    “path”: “path2”
    },
    {
    “key”: “key3”,
    “user”: “user3”,
    “path”: “path3”
    }
    ]
    eof
    )

    backups=($(echo “${backups_to_perform}” | jq -r ‘.[] | [.key, .user, .path] | @sh’))


    2. utiliza un bucle `for` en lugar de un bucle `while` para iterar sobre el array. esto es más eficiente que utilizar un bucle `while read`. ```sh for backup in "${backups[@]}"; do rsync_backup "${backup}" done
    1. modifica la función rsync_backup para que acepte los argumentos de backup como un array en lugar de variables individuales.
    rsync_backup() {
      local backup=("$@")
      local key=${backup[0]}
      local user=${backup[1]}
      local path=${backup[2]}
    
      # realiza el backup usando $key, $user y $path con rsync
    }
    

    con estas mejoras, el código debería ser más rápido y eficiente, incluso con una entrada json grande.>

Comments are closed.