Múltiples comandos sed en Bash

Múltiples comandos sed en Bash

Tengo un archivo de nombres de usuario y contraseñas en formato JSON que quiero convertir para procesar.

He utilizado seddiferentes comandos para procesarlo, pero lo que me gustaría saber es cómo agrupar los tres comandos en uno para el futuro.

Formato original

    { "user.name1" : "hashed_password",
"user.name2" : "hashed_password" }

Salida deseada

user.name:hashed_password

Estos son los comandos que ejecuté, sin embargo, no pude encadenarlos usando tuberías o simplemente concatenándolos donde aparece un error sed: -e expression #1, char 8: unknown option to 's'.

Comando ofensivo...

sed -i 's/\"//g/s/\,/\n/g/\s//g' input_file 
sed: -e expression #1, char 8: unknown option to `s'

¿Cómo se podrían concatenar los siguientes comandos en uno solo?

Comandos Eliminar comillas dobles

sed -i 's/\"//g' input_file

Reemplace la coma con una nueva línea

sed -i 's/\,/\n/g' input_file

Eliminar espacios en blanco

sed -i 's/\s//g input_file

Respuesta1

Para poner varios sedcomandos en un solo "guion", puede utilizar varios -eindicadores (que son portátiles):

sed -i -e 's/\"//g' -e 's/\,/\n/g' -e 's/\s//g' input_file

O el delimitador de punto y coma (que no está disponible en todas las implementaciones):

sed -i 's/\"//g;s/\,/\n/g;s/\s//g' input_file

También necesitarás agregar manejo para los tirantes {}-...


Dicho esto, para analizar y manejar JSON correctamente, no deberías usar sed... tal vez intentesjq!

jq -r 'keys[] as $k | "\($k):\(.[$k])"' input_file

Producción:

user.name1:hashed_password
user.name2:hashed_password
  • keys[] as $kiterará a través de cada clave almacenando su valor en$k
    • es decir: user.name1,user.name2
  • "\($k):\(.[$k])"formará una cadena, sustituyendo en $ky.[$k]
  • El uso -relimina las comillas de las cadenas de salida (crudomodo)

Usar sedpara procesar JSON lo abrirá a todo tipo de problemas... por ejemplo, ¿cómo manejaría la siguiente entrada (JSON completamente válida)?

{
    "user.name1" :
        "hashed_password",
    "user.name2" :
        "hashed_password"
}

Respuesta2

Cuando se trata de entradas estandarizadas como JSON, generalmente es mejor usar un analizador adecuado en lugar de expresiones regulares. Por ejemplo, convertirá correctamente cualquier secuencia de escape (¡aunque eso puede no ser posible con sus datos de entrada particulares!).

Desafortunadamente, no existen excelentes herramientas para manejar JSON dentro de coreutils.Attie siempre jqcomo una opción decente si eres libre de instalar paquetes.

Si no puede instalar paquetes adicionales, no es particularmente difícil en Python. Tome este script por ejemplo:

import json,sys
for (k, v) in json.load(sys.stdin):
    print(k + ":" + v)

Que se puede comprimir en una línea:

cat inputdata | python -c 'import json,sys;print("\n".join((k + ":" + v) for (k, v) in json.load(sys.stdin).items()))'

Respuesta3

Para la eliminación simple de caracteres que está realizando en estos sedcomandos, le recomendaría que utilice tr, cuyo único propósito es eliminar, comprimir o reemplazar caracteres individuales, incluidas las nuevas líneas ( sedse basa en expresiones regulares, que normalmente dependen de las nuevas líneas como separadores de búfer). por lo que usar sed para modificar nuevas líneas es complicado). Creo que este trcomando hace todo lo que buscas:

cat json_filename | tr -d "{}\" \012\011\015" | tr "," "\012"

El primer trcomando elimina todas las llaves, comillas dobles, espacios, retornos de carro (octal 012, ascii 10), tabulaciones (octal 011, ascii 9 y salto de línea (octal 015, ascii 13). El segundo trcomando reemplaza todas las comas con retornos de carro. Siempre que los nombres y valores de las variables de su archivo JSON no contengan comas, estos comandos le permitirán evitar la necesidad de un analizador JSON dedicado.

Dicho esto, si tiene un conjunto de sedcomandos y cada uno de ellos funciona de forma independiente, combinarlos se puede lograr más fácilmente usando la sedopción "-f" para leer los comandos separados de un archivo. Simplemente coloque las cadenas s/.../.../g en un archivo, cada cadena en su propia línea, luego especifique ese nombre de archivo después de la opción "-f". Por ejemplo, si los tres sedcomandos que enumeró son satisfactorios, puede colocarlos en un archivo llamado "json.convert.sed" que simplemente contenga esto:

s/\"//g 
s/\,/\n/g
s/\s//g

Luego invocarías sedcon este archivo de comando usando:

sed -f json.convert.sed

Dicho esto, estos sedcomandos no me funcionan para lograr lo que quieres, y no estoy seguro de que alguna vez puedas sedmodificar los caracteres de nueva línea. Esto se debe a que sedse basa en el antiguo editor de líneas "ed", diseñado para editar líneas individuales a la vez (una versión compatible con "script"), por lo que cada línea de entrada se "analiza" usando nuevas líneas como delimitadores, luego la línea (sin la nueva línea) se pasa al motor de edición, se aplican los comandos de edición y luego la línea editada se genera con una nueva línea. Luego el bucle se repite. Solo he podido utilizar sedpara modificar la nueva línea cambiando primero las nuevas líneas a algún carácter distinto (que de otro modo no aparece en la entrada) usando tr. No tiene sentido utilizar tresta forma si todo lo que desea hacer es eliminar nuevas líneas, ya que trlo hará por usted. Pero si, por ejemplo, quisieras convertir nuevas líneas en punto y coma con un espacio final, una forma de hacerlo sería:

cat input_file | tr "\012" "%" | sed "s/%/; /g"

(Las nuevas líneas se convierten a % mediante tr, luego sedconvierte todos los % caracteres en pares de caracteres "; ").

Respuesta4

Podrías combinarlo así:

sed -i 's/\"//g;s/\,/\n/g;s/\s//g' input_file

Olvidaste agregar la eliminación de {}. Entonces probablemente quieras:

sed -i 's/\"//g;s/\,/\n/g;s/\s//g;s/{//g;s/}//g' input_file

información relacionada