Tenho nomes de usuário e senhas de arquivos no formato JSON que desejo converter para processo.
Usei sed
comandos 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 sed
comandos em um único "roteiro", você pode usar vários -e
sinalizadores (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 $k
irá iterar através de cada chave armazenando seu valor em$k
- ou seja:
user.name1
,user.name2
- ou seja:
"\($k):\(.[$k])"
formará uma string, substituindo in$k
e.[$k]
- Usar
-r
remove as aspas das strings de saída (crumodo)
Usar sed
para 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 jq
como 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 sed
comandos, 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 tr
comando faz tudo o que você procura:
cat json_filename | tr -d "{}\" \012\011\015" | tr "," "\012"
O primeiro tr
comando 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 tr
comando 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 sed
comandos em que cada um funciona de forma independente, combiná-los pode ser mais facilmente realizado usando a sed
opçã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 sed
comandos 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 sed
este arquivo de comando usando:
sed -f json.convert.sed
Dito isso, esses sed
comandos não funcionam para eu realizar o que você deseja e não tenho certeza se você conseguirá sed
modificar 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 sed
modificar 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 tr
esse método se tudo o que você deseja fazer é excluir novas linhas, pois tr
isso 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, sed
convertem 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