Excluir entradas no arquivo se a mesma entrada existir em um arquivo mestre

2

Eu tenho um arquivo de configuração mestre JSON cujo valor pode ser substituído pelo arquivo de configuração de uma conta específica (também em JSON). O arquivo mestre tem essa estrutura:

{
    "section1Configs": {
        "setting01": true,
        "setting02": true,
        "setting03": false
    },
    section2Configs: {
        "setting01": true,
        "setting02": true,
        "setting03": false
    },
    section3Configs: {
        "setting01": true,
        "setting02": true,
        "setting03": false
    },
    section4Configs: {
        "setting01": true,
        "setting02": true,
        "setting03": false
    }
}

O arquivo de configuração de uma conta específica pode ter esta aparência:

{
    "section1Configs": {
        "setting01": true,
        "setting02": true,
        "setting03": true
    },
    section2Configs: {
        "setting01": false,
        "setting02": true,
        "setting03": false
    },
    section3Configs: {
        "setting01": true,
        "setting02": false,
        "setting03": false
    },
    section4Configs: {
        "setting01": true,
        "setting02": true,
        "setting03": false
    }
}

Observe que eles são idênticos, exceto que determinados valores (section01Config.setting03, section02Config.setting01 e section03Config.setting02) são diferentes. Note também que todo o bloco section4Configs é o mesmo em ambos os arquivos.

Os que são os mesmos não são necessários, pois o aplicativo carrega os dois e substitui o arquivo mestre com os que são diferentes na configuração da conta.

O que eu gostaria de fazer é ter um script que percorra um diretório de tais arquivos de conta e exclua a entrada em cada arquivo que tenha a mesma chave e valor que o arquivo mestre. A partir desse exemplo, eu acabaria com um arquivo como este:

{
    section1Configs: {
        setting03: true
    },
    section2Configs: {
        setting01: false
    },
    section3Configs: {
        setting02: false
    }
}

Existem mais de 200 arquivos de configuração de conta, e fazer isso manualmente levará uma vida inteira. Qualquer ajuda é muito apreciada!

------ EDITAR -------

Eu tentei manter a pergunta simples, mas acho que um detalhe faltante terá um impacto na resposta.

O arquivo JSON da conta e da configuração consiste em seções e suas configurações correspondentes. Isso significa que o JSON é um nível mais profundo do que o mencionado acima:

{
    "section1Configs": {
        "level1Settings": {
            "section01Lev01_01": true,
            "section01Lev01_012": true,
            "section01Lev01_02": true
        }
    }
}

Obrigado!

    
por vdiaz1130 24.07.2015 / 17:29

3 respostas

0

Então eu copiei sua parte inferior em dois arquivos.

Arquivo 1:

{
    "section1Configs": {
        "level1Settings": {
            "section01Lev01_01": true,
            "section01Lev01_012": true,
            "section01Lev01_02": true
        }
    }
}

E o arquivo 2 ...

{
    "section1Configs": {
        "level1Settings": {
            "section01Lev01_01": true,
            "section01Lev01_012": false,
            "section01Lev01_02": true
        }
    }
}

Eles diferem apenas na linha Level01_012 .

Então eu fiz:

grep -Ev '[{}]|^$' file1 | grep -Fxvf- file2
{
    "section1Configs": {
        "level1Settings": {
            "section01Lev01_012": false,
        }
    }
}

Esse comando é dividido da seguinte forma:

  1. grep -Ev '[{}]|^$' file1

    • Aqui, pedimos que grep imprima todas as linhas em file1 que não correspondem a { ou } , mas deve corresponder a pelo menos um personagem.
    • Sua saída é semelhante a:

              "section01Lev01_01": true,
              "section01Lev01_012": true,
              "section01Lev01_02": true
      
  2. grep -Fxvf- file2

    • Isso é lido por este segundo grep que interpreta seu padrão de entrada - stdin -f ile como -F ixed-string padrão -x correspondência de linha inteira que deve - v não imprime para saída. E assim, este segundo grep imprime todas as linhas no arquivo2 que não correspondem exatamente às linhas verdadeiro / falso no arquivo1.

Agora, se o seu grep não entender - como stdin, temos algumas opções:

grep -Ev '[{}]|^$' file1 | grep -Fxvf /dev/fd/0 file2

... funcionará na maioria dos sistemas. Uma opção semelhante é usar /dev/stdin , que também é muito provável que funcione, se bem que um pouco menos.

Existe também uma implementação específica do shell, conhecida como substituição de processo , que funciona exatamente da mesma maneira ...

grep -Fxvf <(grep -Ev '[{}]|^$' file1) file2

... que pode ou não funcionar para você, dependendo do seu shell.

Outra possibilidade é ...

grep -Fxv "$(grep -Ev '[{}]|^$' file1)" file2

... que pode ou não funcionar para você, dependendo de quão grande é a saída do comando subbed grep .

Experimente alguns e provavelmente encontrará um que funcione para você.

    
por 24.07.2015 / 20:46
0

Pode ser melhor usar ferramentas especializadas para json como jq ou jshon ?
Mas se você quiser, pode ser feito com paste e sed

paste config master | sed '/[{}]/! {/\(.\+\)\t/d;};s/\t.*//'

ou awk

awk '{getline a < "master"} /[{}]/ || $0 != a' config

para cada linha no arquivo de configuração recebe a linha correspondente (por número) do arquivo mestre para a variável a e se a linha consistir em { ou } ou não os mesmos com os do arquivo mestre, imprima-os.
Resultado:

{
    "section1Configs": {
        "setting03": true
    },
    section2Configs: {
        "setting01": false,
    },
    section3Configs: {
        "setting02": false,
    },
    section4Configs: {
    }
}
    
por 24.07.2015 / 17:48
0

Como foi apontado em outra parte desta página, uma maneira robusta e eficiente de resolver o problema é usar uma ferramenta compatível com JSON, como jq . O seguinte fornece uma solução para o problema original; pode ser facilmente adaptado para resolver variantes.

(1) Coloque o seguinte em um arquivo, digamos minusConfig.jq:

def minus(o1;o2):
  o1 | with_entries( select(o2[.key] != .value) );

def minusConfig(o1;o2):
  reduce (o1|keys)[] as $key ({};
    minus( o1[$key] ; o2[$key]) as $v
    | if $v == {} then . else . + {($key): $v} end );

minusConfig($user; $master)

(2) Supondo que o master e os arquivos de configuração do usuário são master.json e user.json respectivamente,

$ jq -n --arg master master.json --arg user user.json -f minusConfig.jq

produz:

{
  "section1Configs": {
    "setting03": true
  },
  "section2Configs": {
    "setting01": false
  },
  "section3Configs": {
    "setting02": false
  }
}
    
por 07.09.2015 / 06:32