Perché il contenuto JSON di heredoc non è analizzabile?


11

Ho un frammento JSON.

Quanto segue non funziona:

VALUE=<<PERSON
{
  "type": "account",
  "customer_id": "1234",
  "customer_email": "jim@gmail.com"  
}
PERSON
echo -n "$VALUE" | python -m json.tool

Il risultato è:

Nessun oggetto JSON può essere decodificato

Fare lo stesso con jq, ad es

echo -n "$VALUE" | jq '.'

Non c'è output.

Esiste lo stesso comportamento per quanto segue:

VALUE=<<PERSON
'{
  "type": "account",
  "customer_id": "1234",
  "customer_email": "jim@gmail.com"  
}'
PERSON
echo -n "$VALUE" | python -m json.tool

Risposta:

Nessun oggetto JSON può essere decodificato

Ma i seguenti lavori:

VALUE='{
  "type": "account",
  "customer_id": "1234",
  "customer_email": "jim@gmail.com"
}'
echo -n "$VALUE" | jq '.'
echo -n "$VALUE" | python -m json.tool

5
Non so cosa stia facendo bash, ma c'è una virgola finale dopo la stringa di posta elettronica nei tuoi primi due ma non nel terzo, il che renderebbe illegale la prima coppia JSON
Nick T

@NickT dovresti dare una risposta perché penso che sia proprio il problema.
rrauenza,

Se questa è la (sola) risposta, dovrebbe probabilmente essere chiusa come "impossibile riprodurre (un refuso)". Tuttavia, sembra che la risposta di Kusa e Terdon menzioni che l'assegnazione + reindirizzamento è totalmente rotta in modo da ottenere una stringa vuota, quindi ci sono due problemi, entrambi i quali darebbero lo stesso errore "No JSON ...". È un'ottima pratica sezionare i problemi controllando le tue ipotesi nel mezzo: un semplice echo $VALUEsenza ... | jqsarebbe informativo.
Nick T

@NickT: era un problema di copia / incolla. Ci scusiamo per la confusione
Jim,

Risposte:


19
VALUE=<<PERSON
some data
PERSON

echo "$VALUE"

Nessuna uscita

Un documento qui è un reindirizzamento , non è possibile reindirizzare in una variabile.

Quando viene analizzata la riga di comando, i reindirizzamenti vengono gestiti in un passaggio separato dalle assegnazioni di variabili. Il tuo comando è quindi equivalente a (nota lo spazio)

VALUE= <<PERSON
some data
PERSON

Cioè, assegna una stringa vuota alla tua variabile, quindi reindirizza l'input standard dalla stringa qui al comando (ma non c'è alcun comando, quindi non succede nulla).

Nota che

<<PERSON
some data
PERSON

è valido così com'è

<somefile

È solo che non esiste alcun comando il cui flusso di input standard può essere impostato per contenere i dati, quindi è semplicemente perso.

Funzionerebbe però:

VALUE=$(cat <<PERSON
some data
PERSON
)

Qui, il comando che riceve il documento here è cate lo copia nel suo output standard. Questo è quindi ciò che viene assegnato alla variabile mediante la sostituzione del comando.

Nel tuo caso, potresti invece usare

python -m json.tool <<END_JSON
JSON data here
END_JSON

senza fare il passo aggiuntivo di memorizzare i dati in una variabile.


2
Potresti anche semplicemente fare PERSON="seguito da una nuova riga e dai dati multilinea, quindi un altro "alla fine.
R .. GitHub FERMA AIUTANDO ICE

1
@R .. Sì, ma un documento qui consente di ignorare le regole di quotazione della shell. Pertanto, è spesso più sicuro utilizzare un documento here anziché una stringa tra virgolette per i dati multilinea, soprattutto se i dati contengono virgolette singole o doppie (o entrambe).
Kusalananda

2
@R .. Dato che stiamo parlando di JSON, potrebbe essere meglio usare virgolette singole per non dover sfuggire alle doppie virgolette di ogni nome di proprietà. PERSON='. Questo a meno che l'OP non voglia interpolare le variabili in un secondo momento.
JoL

(backslash) (newline) sembra svanire in un documento qui, anche se si cita / sfugge alla parola delimitatore. Potrebbe essere desiderabile, ma c'è un modo per disabilitarlo?
Scott,

@Scott Se quella domanda non è stata posta prima su questo sito, sarebbe una domanda eccellente a sé stante.
Kusalananda

11

Perché la variabile non viene impostata dalla tua eredità:

$ VALUE=<<PERSON  
> {    
>   "type": "account",  
>   "customer_id": "1234",  
>   "customer_email": "jim@gmail.com",  
> }  
> PERSON
$ echo "$VALUE" 

$

Se vuoi usare un heredoc per assegnare un valore a una variabile, hai bisogno di qualcosa come:

$ read -d '' -r VALUE <<PERSON  
{    
  "type": "account",  
  "customer_id": "1234",  
  "customer_email": "jim@gmail.com",  
}   
PERSON

1
Perché stai racchiudendo i dati JSON tra virgolette singole? Non sembra davvero che l'OP voglia che facciano parte della sua stringa di input. A parte ciò, +1 per ridurre la popolazione di gatti senza tetto. Come per la risposta di Kusalananda, potresti voler suggerire << \PERSONdi proteggere da $s nell'input e nelle barre rovesciate alle estremità delle righe.
Scott,

@Scott um, perché ho appena copiato ciecamente il testo dall'OP. Grazie
terdon

3
Questa è la risposta esatta. $(cat <<EOF ... EOF)è un costrutto strano: eseguire una subshell e quindi inviare un heredoc a cat solo per inviarlo a STDOUT e quindi assegnare il risultato di quella subshell a una variabile? Vorrei che le persone pensassero a quello che stanno dicendo sui loro processi di pensiero. Assegnare un heredoc a una variabile tramite read, al confronto, è sano.
Ricco

Non direi che $(cat << EOF... (dati) ... EOF )è strano. È scomodo e contorto, ma lo è anche read -d … << EOF - soprattutto read -d '' << EOF . Apprezzo la risposta di Terdon perché utilizza solo builtin, nessun programma. Ma, soprattutto, il $(cat << EOF... (dati) ... EOF )fallisce se qualche riga termina con \(barra rovesciata) - vedi i commenti sotto la risposta di Kusalananda .
Scott,

5

È perché il modo in cui hai definito un documento here da usare con un JSON è sbagliato. Devi usarlo come

VALUE=$(cat <<EOF
{  
  "type": "account",  
  "customer_id": "1234",  
  "customer_email": "jim@gmail.com",  
}
EOF
)

e fare printf "$VALUE"dovrebbe scaricare il JSON come previsto.


3

Heredocs e variabili non si mescolano bene o almeno non in questo modo. Puoi ...

Passa l'ereditarietà come input standard di un'applicazione

python -m json.tool <<PERSON  
{
  "type": "account",
  "customer_id": "1234",
  "customer_email": "jim@gmail.com",
}
PERSON

o…

Memorizza il testo su più righe in una variabile shell

VALUE='{
  "type": "account",
  "customer_id": "1234",
  "customer_email": "jim@gmail.com",
}'

Ho usato virgolette singole per evitare la necessità di sfuggire alle doppie virgolette interne. Ovviamente puoi anche usare virgolette doppie, ad esempio se devi espandere i parametri:

VALUE="{
  \"type\": \"account\",
  \"customer_id\": ${ID},
  \"customer_email\": \"${EMAIL}\",
}"

Quindi è possibile utilizzare il valore della variabile in un secondo momento.

echo -n "$VALUE" | python -m json.tool
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.