Eu tenho uma matriz JSON assim:
{
"SITE_DATA": {
"URL": "example.com",
"AUTHOR": "John Doe",
"CREATED": "10/22/2017"
}
}
Estou procurando iterar sobre esta matriz usando jq para poder definir a chave de cada item como o nome da variável e o valor como seu valor.
Exemplo:
- URL="exemplo.com"
- AUTOR="John Doe"
- CRIADO="22/10/2017"
O que eu tenho até agora itera sobre a matriz, mas cria uma string:
constants=$(cat ${1} | jq '.SITE_DATA' | jq -r "to_entries|map(\"\(.key)=\(.value|tostring)\")|.[]")
Quais saídas:
URL=example.com
AUTHOR=John Doe
CREATED=10/22/2017
Estou procurando usar essas variáveis mais abaixo no script:
echo ${URL}
Mas isso ecoa uma saída vazia no momento. Acho que preciso de um eval
ou algo lá, mas não consigo identificar.
Sua versão original não será
eval
capaz porque o nome do autor contém espaços - seria interpretado como a execução de um comandoDoe
com a variável de ambienteAUTHOR
definida comoJohn
. Também praticamente nunca há necessidade de canalizarjq
para si mesmo - a tubulação interna e o fluxo de dados podem conectar diferentes filtros.Tudo isso só faz sentido se você confiar totalmente nos dados de entrada (por exemplo, gerados por uma ferramenta que você controla). Existem vários problemas possíveis detalhados abaixo, mas vamos supor que os dados em si certamente estejam no formato que você espera no momento.
Você pode fazer uma versão muito mais simples do seu programa jq:
quais saídas:
Não há necessidade de um
map
:.[]
trata de levar cada objeto no array pelo resto do pipeline como um item separado , então tudo depois do último|
é aplicado a cada um separadamente. No final, apenas montamos uma string de atribuição de shell válida com+
concatenação comum, incluindo aspas apropriadas e escapando em torno do valor com@sh
.Todos os canais são importantes aqui - sem eles, você recebe mensagens de erro bastante inúteis, onde partes do programa são avaliadas em contextos sutilmente diferentes.
Essa string é
eval
possível se você confiar totalmente nos dados de entrada e tiver o efeito desejado:Como sempre, ao usar
eval
o , tenha cuidado para confiar nos dados que está obtendo, pois se for malicioso ou apenas em um formato inesperado, as coisas podem dar muito errado. Em particular, se a chave contiver metacaracteres de shell como$
ou espaço em branco, isso poderá criar um comando em execução. Ele também pode sobrescrever, por exemplo, aPATH
variável de ambiente inesperadamente.Se você não confia nos dados, não faça isso ou filtre o objeto para conter apenas as chaves que você deseja primeiro:
Você também pode ter um problema no caso de o valor ser uma matriz, então
.value | tostring | @sh
será melhor - mas esta lista de ressalvas pode ser um bom motivo para não fazer nada disso em primeiro lugar.Também é possível construir uma matriz associativa onde as chaves e os valores são citados:
Depois disso,
${data[CREATED]}
contém a data de criação e assim por diante, independentemente de qual seja o conteúdo das chaves ou valores. Essa é a opção mais segura, mas não resulta em variáveis de nível superior que possam ser exportadas. Ainda pode produzir um erro de sintaxe Bash quando um valor é uma matriz ou um erro jq se for um objeto, mas não executará o código nem substituirá nada.Com base na resposta de @Michael Homer, você pode evitar
eval
totalmente um potencial inseguro lendo os dados em uma matriz associativa.Por exemplo, se seus dados JSON estiverem em um arquivo chamado
file.json
:Resultado:
Acabei de perceber que posso percorrer os resultados e avaliar cada iteração:
Permite-me fazer:
Gostei muito da sugestão do @Michel. Às vezes, você pode apenas extrair o valor de algumas variáveis para executar uma tarefa naquele servidor específico usando o Bash. Então, se as variáveis desejadas são conhecidas, usar essa abordagem é a forma de evitar várias chamadas para
jq
definir um valor por variável ou mesmo usar aread
instrução com várias variáveis em que algumas podem ser válidas e vazias, levando a uma mudança de valor (isso foi meu problema).Minha abordagem anterior levaria a um erro de deslocamento de valor – se .svID[ ].ID="",
sv
obterá o valor slotID .Se você baixou o objeto usando curl, aqui está minha abordagem para renomear algumas variáveis para um nome amigável como extrair dados de matrizes de dados.
Usar eval e filtros resolverá o problema com uma linha e produzirá variáveis com os nomes desejados.
A vantagem neste caso, é o fato de que ele irá filtrar, renomear, formatar todas as variáveis desejadas na primeira etapa. Observe que há .[0] | é muito comum ter se a fonte for de um servidor RESTful API usando GET, dados de resposta como:
Se seus dados não são de um array, ou seja, é um objeto como:
apenas remova o índice inicial: