Existe um arquivo com conteúdo
{
"first_name": "John",
"last_name": "Smith",
"is_alive": true,
"age": 27,
"address": {
"street_address": "21 2nd Street",
"city": "New York",
"state": "NY",
"postal_code": "10021-3100"
},
"phone_numbers": [
{
"type": "home",
"number": "212 555-1234"
},
{
"type": "office",
"number": "646 555-4567"
}
],
"children": [
"Catherine",
"Thomas",
"Trevor"
],
"spouse": null
}
Como adicionar conteúdo a um arquivo antes do último caractere } usando os utilitários Busybox para que o conteúdo do arquivo fique como abaixo?
{
"first_name": "John",
"last_name": "Smith",
"is_alive": true,
"age": 27,
"address": {
"street_address": "21 2nd Street",
"city": "New York",
"state": "NY",
"postal_code": "10021-3100"
},
"phone_numbers": [
{
"type": "home",
"number": "212 555-1234"
},
{
"type": "office",
"number": "646 555-4567"
}
],
"children": [
"Catherine",
"Thomas",
"Trevor"
],
"spouse": null,
"field1": "value1",
"field2": "value2",
"field3": "value3",
"field4": "value4"
}
No entanto, o caractere } não é necessariamente o último caractere do arquivo e não está necessariamente localizado na última linha.
Até agora encontrei apenas esta solução
tac file2 | sed '0,/}/s/}/}\n"field4": "value4"\n"field3": "value3",\n"field2": "value2",\n"field1": "value1",\n,/' | tac>tmp_file && mv tmp_file file2
Usando o
ed
utilitário (testado em umBusyBox
contêiner):O arquivo de saída passa no teste jq .
Se o último } for a última linha, isso pode ser feito com o comando head. Inclua o último } no texto adicionado:
E o que você quer é:
Você omite o último } do texto adicionado e, em vez disso, canaliza a saída acima para este sed:
Usando qualquer shell do tipo awk e bourne:
Observe que ele define o recuo do novo bloco como qualquer recuo da linha imediatamente anterior, para que você não precise codificar esse recuo e funcionará mesmo se você tiver linhas de comentários ou linhas em branco depois a última
}
linha.Se você tiver certeza de que o arquivo termina com
}\n
(ou simplesmente}
nenhuma nova linha no final do arquivo), poderá usartruncate
os últimos 2 bytes (ou 1 byte). Usetail -c
para verificar de antemão.Depois
truncate
, o arquivo estaria faltando o último,}
mas estaria intacto. Neste ponto, basta>>
anexar o novo texto (incluindo o}
truncado).Infelizmente, o busybox
truncate
não entende tamanhos relativos (-2
), então você mesmo precisa fazer as contas e usarstat -c %s
para determinar o tamanho em bytes.Este método também funcionaria com arquivos muito grandes, sem a necessidade de ler todo o conteúdo primeiro.
awk
,ed
,head -n
, etc. todos leem o arquivo inteiro.Nota: Esta resposta não se restringe a usar apenas utilitários integrados ao multi-binário Busybox, mas usa o
jq
utilitário . Essa conhecida ferramenta de processamento JSON está disponível como um binário estático para a maioria das arquiteturas comuns, não exigindo escalonamento de permissão para instalação ou uso. Você também pode usá-lo por meio de uma imagem pública do Docker.Como os multi-binários do Busybox podem conter um número bastante variável de utilitários integrados, dependendo exatamente do que o Busybox está sendo usado (302 utilitários no Alpine Linux, mas mais 100 extras na imagem pública do Busybox Docker), e como isso não foi mencionado na pergunta, presumo que a restrição seja puramente artificial e não muito importante.
Depois de instalado,
jq
você poderá usá-lo de diferentes maneiras para adicionar seus dados, dependendo da forma como você fornece os novos dados.Assumindo chaves separadas e strings não codificadas, você usaria
jq
with--arg key value
para codificar cada string e criarjq
variáveis internas. Para valores que já estão codificados adequadamente (números, booleanos, strings JSON ou fragmentos JSON), use--argjson
em vez de--arg
. Você pode então usar os nomes das chaves prefixados por$
($key1
,$var2
,$lastname
etc.) dentro dajq
expressão para acessar os dados individuais, ou você pode acessar todas essas variáveis usando o$ARGS.named
objeto especial:Com seu primeiro documento de exemplo em
file.json
, isso produziria o seguinte:Obviamente você pode decidir onde os dados serão inseridos no documento especificando um caminho diferente
.
da expressão acima. Por exemplo, para adicionar os dados a qualquer objeto de entrada que represente uma pessoa que tenha pelo menos um número de telefone residencial começando com "212":