Vários comandos sed no Bash

Vários comandos sed no Bash

Tenho nomes de usuário e senhas de arquivos no formato JSON que desejo converter para processo.

Usei sedcomandos diferentes para processá-lo, mas o que gostaria de saber é como agrupar todos os três comandos em um para o futuro.

Formato original

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

Saída desejada

user.name:hashed_password

Esses são os comandos que executei, mas não consegui encadeá-los usando tubulação ou simplesmente concatenando-os onde recebo um erro 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'

Como os comandos abaixo poderiam ser concatenados em um?

Comandos Remover aspas duplas

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

Substitua vírgula por nova linha

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

Remover espaços em branco

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

Responder1

Para colocar vários sedcomandos em um único "roteiro", você pode usar vários -esinalizadores (que são portáteis):

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

Ou o delimitador de ponto e vírgula (que não está disponível em todas as implementações):

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

Você também precisará adicionar manuseio para os aparelhos - {}...


Dito isto, para analisar e manipular JSON corretamente, você realmente não deveria usar sed... talvez tentejq!

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

Saída:

user.name1:hashed_password
user.name2:hashed_password
  • keys[] as $kirá iterar através de cada chave armazenando seu valor em$k
    • ou seja: user.name1,user.name2
  • "\($k):\(.[$k])"formará uma string, substituindo in $ke.[$k]
  • Usar -rremove as aspas das strings de saída (crumodo)

Usar sedpara processar JSON irá abrir você para todos os tipos de problemas... por exemplo, como você lidaria com a seguinte entrada (JSON completamente válida)?

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

Responder2

Ao lidar com entradas padronizadas como JSON, geralmente é melhor usar um analisador adequado em vez de regex. Por exemplo, você converterá corretamente qualquer sequência de escape (embora isso possa não ser possível com seus dados de entrada específicos!).

Infelizmente, não existem ótimas ferramentas para lidar com JSON no coreutils.Attie forneceu jqcomo uma opção decente se você estiver livre para instalar pacotes.

Se você não conseguir instalar pacotes adicionais, não será particularmente difícil em Python. Veja este script, por exemplo:

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

Que pode ser compactado em uma linha:

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

Responder3

Para a exclusão simples de caracteres que você está fazendo nesses sedcomandos, recomendo que você use tr, cujo único objetivo é excluir, comprimir ou substituir caracteres individuais, incluindo novas linhas ( sedé baseado em regex, que normalmente dependem de novas linhas como separadores de buffer, então usar sed para modificar novas linhas é complicado). Acho que este trcomando faz tudo o que você procura:

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

O primeiro trcomando exclui todos os caracteres de chaves, aspas duplas, espaços, retornos de carro (octal 012, ascii 10), tabulações (octal 011, ascii 9 e avanço de linha (octal 015, ascii 13). O segundo trcomando substitui todas as vírgulas por retornos de carro. Contanto que os nomes e valores das variáveis ​​do arquivo JSON não contenham vírgulas, esses comandos permitirão que você evite a necessidade de um analisador JSON dedicado.

Dito isso, se você tiver um conjunto de sedcomandos em que cada um funciona de forma independente, combiná-los pode ser mais facilmente realizado usando a sedopção “-f” para ler os comandos separados de um arquivo. Você apenas coloca as strings s/.../.../g em um arquivo, cada string em sua própria linha, e especifica o nome do arquivo após a opção "-f". Por exemplo, se os três sedcomandos listados forem satisfatórios, você poderá colocá-los em um arquivo chamado "json.convert.sed" que contenha simplesmente isto:

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

Então você invocaria sedeste arquivo de comando usando:

sed -f json.convert.sed

Dito isso, esses sedcomandos não funcionam para eu realizar o que você deseja e não tenho certeza se você conseguirá sedmodificar caracteres de nova linha. Isso ocorre porque sedé baseado no antigo editor de linha "ed", projetado para editar linhas únicas por vez (uma versão compatível com "script"), de modo que cada linha de entrada é "analisada" usando novas linhas como delimitadores, então a linha (sem a nova linha) é passada para o mecanismo de edição, os comandos de edição são aplicados e a linha editada é exibida com uma nova linha. Então o loop se repete. Eu só consegui sedmodificar a nova linha primeiro alterando as novas linhas para algum caractere distinto (que de outra forma não aparece na entrada) usando tr. Não faz sentido usar tresse método se tudo o que você deseja fazer é excluir novas linhas, pois trisso será feito por você. Mas se, por exemplo, você quiser converter novas linhas em ponto e vírgula com espaço à direita, uma maneira de fazer isso seria:

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

(as novas linhas são convertidas em % por e tr, em seguida, sedconvertem todos os % caracteres em pares de caracteres "; ".)

Responder4

Você poderia combiná-lo assim:

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

Você esqueceu de adicionar a remoção de {}. Então você provavelmente quer:

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

informação relacionada