Gerar JSON a partir de dados delimitados por dois pontos em um script de shell

4

Eu tenho um arquivo como este

103710:v2HAbAFH029324:[email protected]:localhost:Sent
103821:CCFE5609E3:[email protected]:localhost:bounced
103922:DFF19609E2:[email protected]:localhost:Deferred

Eu preciso mudar isso para

{"randomId":{"s":"103710"},"id":{"s":"v2HAbAFH029324"},"userId":{"s":"[email protected]"},"dns":{"s":"localhost"},"status":{"s":"Sent"}}
{"randomId":{"s":"103821"},"id":{"s":"CCFE5609E3"},"userId":{"s":"[email protected]"},"dns":{"s":"localhost"},"status":{"s":"bounced"}}
{"randomId":{"s":"103922"},"id":{"s":"DFF19609E2"},"userId":{"s":"[email protected]"},"dns":{"s":"localhost"},"status":{"s":"Deferred"}}

Estou pensando o código como este

while read line
do     
        sed -i 's/^/{"randomId":{"s":"/' test
        echo $line

        echo $line | grep -q ":"
        [ $? -eq 0 ] && echo "/"{"id":{"s":/"
        [ $? -eq 1 ] && echo "/",{"userId":{"s":/"
        [ $? -eq 2 ] && echo "/",{"host":{"s":/"
        [ $? -eq 3 ] && echo "/",{"status":{"s":/"
        echo "$line | " ";
done < test

Adicionando a primeira ocorrência de: {"id":{"s": e depois a segunda ocorrência adicionando {"userId":{"s":

    
por kumar babu 24.03.2017 / 16:42

4 respostas

1

Como seus dados são delimitados e fáceis de ler, há algumas maneiras de fazer isso. Sed pode analisar seus dados em uma linha e gerar as alterações:

sed -r -i 's/^(.*):(.*):(.*):(.*):(.*)$/{"randomId":{"s":""},"id":{"s":""},"userId":{"s":""},"dns":{"s":""},"status":{"s":""}}/' input.txt

Você usa grupos de captura para capturar tudo entre o início do arquivo, seu delimitador e o final do arquivo e depois manipular o texto em torno desses grupos. Cada grupo de captura é referenciado por "\ #", em que # é o número do grupo de captura iniciado em um e incrementado em um para cada grupo.

Como já mencionado, você também pode definir seu próprio delimitador. Bash tem uma variável interna chamada IFS (separador de campo interno). O IFS padroniza o espaço em branco, mas você pode alterá-lo. Eu não vou mostrar o exemplo como já foi dado e seria apenas uma cópia dele.

    
por 24.03.2017 / 18:13
5

Esse bloco grep / echo não fará nada de útil; $? vai ser definido uma vez - não vai iterar pelos campos.

Felizmente, parece haver uma maneira muito mais fácil de fazer isso: apenas divida os campos em variáveis. Felizmente, read pode fazer isso por você:

while IFS=':' read -r randomid id userid dns status; do
    printf '{"randomId":{"s":"%s"},"id":{"s":"%s"},"userId":{"s":"%s"},"dns":{"s":"%s"},"status":{"s":"%s"}}\n' \
           "$randomid" "$id" "$userid" "$dns" "$status"
done

Usar printf em vez do mais familiar echo evita todos os \" -sequences echo que seriam necessários. Observe a barra invertida no final da linha para dividi-la.

BTW: O formato que você está produzindo é chamado de JSON, e pode haver ferramentas para ajudar a gerá-lo (por exemplo, jq ). Além disso, ele pode exigir seu próprio escape se, por exemplo, seus campos puderem conter aspas duplas.

    
por 24.03.2017 / 17:06
2

com perl :

perl -MJSON -F: -ple '@A = qw/randomId id userId dns status/; $_ = encode_json({map { shift @A => { "s" => $_ } } @F } )' input.csv
    
por 24.03.2017 / 17:49
1
perl -F: -pale '
   @A = qw/randomId id userId dns status/;
   ($k, $_) = (0, "{" . join(",", map qq/"$A[$k++]":{"s":"$_"}/, @F) . "}");
' yourfile

Explicação

O @F detém os campos divididos em : que são então costurados junto com o% massageador apropriado e prefixados com o elemento correspondente da matriz {"s":"fieldI"} . Todos esses elementos são reunidos por um @A on join e entre "{" ... "}". E você está feito.

    
por 24.03.2017 / 17:28