-1

I´ve a json which is a list of dictionaries with the next syntax:

 [ 
     {
    "Date_and_Time": "Dec 29, 2017 15:35:37",
    "Componente": "Bar",
    "IP_Origen": "175.11.13.6",
    "IP_Destino": "81.18.119.864",
    "Country": "Brazil",
    "Age": "3"

},

{

    "Date_and_Time": "Dec 31, 2017 17:35:37",
    "Componente": "Foo",
    "IP_Origen": "176.11.13.6",
    "IP_Destino": "80.18.119.864",
    "Country": "France",
     'Id': '123456',
     'Car': 'Ferrari'

},
{
  "Date_and_Time": "Dec 31, 2017 17:35:37",
    "Age": "1",
    "Country": "France",
     'Id': '123456',
     'Car': 'Ferrari'
},
{
    "Date_and_Time": "Mar 31, 2018 14:35:37",
    "Componente": "Foo",
    "Country": "Germany",
     'Id': '2468',
     'Genre': 'Male'

}
]

The json is really big and each dictionary have different amount of key/values fields. And what I want to do is to rewrite each character of the KEYS into lower case. Expected input:

[ 
     {
    "date_and_time": "Dec 29, 2017 15:35:37",
    "componente": "Bar",
    "ip_origen": "175.11.13.6",
    "ip_destino": "81.18.119.864",
    "country": "Brazil",
     .
     .
     .
 
Kiko
  • 57
  • 6
  • only keys wrapped in double quotes? or do you also want to apply the 'lower()' logic to keys wrapped in single quotes? (eg, `'Id': '2468',` ==> `'id': '2468'`); what (code) have you tried so far? – markp-fuso Dec 30 '20 at 16:17
  • Both of them. What I have thought is to implement a sed command changing every character into lower case but it's not efficient at all and it will change also the values (i only want to change keys) – Kiko Dec 30 '20 at 16:21
  • Could you explain a little bit? @oguzismail – Kiko Dec 30 '20 at 16:26
  • I'm not looking for a JQ solution, I would like to implement in bash – Kiko Dec 30 '20 at 16:40
  • 5
    Use a JSON parser to parse JSON. Same advice for XML, HTML, CSV, ... – glenn jackman Dec 30 '20 at 17:14

3 Answers3

5
awk 'NF>1{$1=tolower($1)} 1' FS=: OFS=: file
perl -pe 's/.*?:/\L$&/' file

GNU sed:

sed 's/[^:]*:/\L&/' file

Convert to lower case everything before the : character on each line. For this to work correctly, each key/val pair must occupy a single line, and keys must not contain the : character. In awk it can be done by splitting at : so that the first field may be converted. In perl the substitution operator is used to replace everything up to the first : with itself lowercased by the \L escape (info in man 1 perlop, perldoc.perl.org). GNU sed offers a perl-like \L sequence (only usable in the replacement part of s/// in sed).

3

Despite my comment to your question, with bash:

# strings assigned to the "key" variable will be lower-cased
declare -l key

while IFS=: read -r key value; do
  [[ -z $value ]] && echo "$key" || echo "$key:$value"
done < file.json

outputs

 [
     {
    "date_and_time": "Dec 29, 2017 15:35:37",
    "componente": "Bar",
    "ip_origen": "175.11.13.6",
...

Instead of laboriously explaining each line, I'll provide some links to documentation for self-learning:

glenn jackman
  • 238,783
  • 38
  • 220
  • 352
1

Use this Perl one-liner:

perl -lne '@F = split /:/, $_, 2; $F[0] = lc $F[0]; print join ":", @F;' in.json > out.json

The Perl one-liner uses these command line flags:
-e : Tells Perl to look for code in-line, instead of in a file.
-n : Loop over the input one line at a time, assigning it to $_ by default.
-l : Strip the input line separator ("\n" on *NIX by default) before executing the code in-line, and append it when printing.

@F = split /:/, $_, 2; : Split the input string $_ into array @F with a max of 2 elements.

Timur Shtatland
  • 12,024
  • 2
  • 30
  • 47