Warum kann der JSON-Inhalt von heredoc nicht analysiert werden?

11

Ich habe ein JSON-Fragment.

Folgendes funktioniert nicht:

VALUE=<<PERSON
{
  "type": "account",
  "customer_id": "1234",
  "customer_email": "[email protected]"  
}
PERSON
echo -n "$VALUE" | python -m json.tool

Das Ergebnis ist:

Es konnte kein JSON-Objekt dekodiert werden

Das Gleiche tun mit jq, dh

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

Es erfolgt keine Ausgabe.

Es gibt das gleiche Verhalten für Folgendes:

VALUE=<<PERSON
'{
  "type": "account",
  "customer_id": "1234",
  "customer_email": "[email protected]"  
}'
PERSON
echo -n "$VALUE" | python -m json.tool

Antwort:

Es konnte kein JSON-Objekt dekodiert werden

Aber folgendes funktioniert:

VALUE='{
  "type": "account",
  "customer_id": "1234",
  "customer_email": "[email protected]"
}'
echo -n "$VALUE" | jq '.'
echo -n "$VALUE" | python -m json.tool
Jim
quelle
5
Ich weiß nicht, was Bash macht, aber es gibt ein nachfolgendes Komma nach der E-Mail-Zeichenfolge in Ihren ersten beiden, aber nicht nach dem dritten, was das erste Paar illegal machen würde. JSON
Nick T
@NickT du solltest das eine Antwort machen, da ich denke das ist genau das Problem.
Rrauenza
Wenn dies die (einzige) Antwort ist, sollte sie wahrscheinlich geschlossen werden, da "nicht reproduziert werden kann (Tippfehler)". Es sieht jedoch so aus, als ob Kusas und Terdons Antwort erwähnen, dass die Zuweisung + Umleitung vollständig unterbrochen ist, sodass Sie eine leere Zeichenfolge erhalten. Es gibt also zwei Probleme, die beide den gleichen Fehler "Kein JSON ..." ergeben würden. Es ist eine sehr gute Praxis, Probleme zu halbieren, indem Sie Ihre Annahmen in der Mitte überprüfen: Ein einfaches echo $VALUEOhne ... | jqwäre informativ.
Nick T
@ NickT: Das war ein Problem beim Kopieren / Einfügen. Entschuldigung für die Verwirrung
Jim

Antworten:

19
VALUE=<<PERSON
some data
PERSON

echo "$VALUE"

Keine Leistung.

Ein Here-Dokument ist eine Umleitung , Sie können nicht in eine Variable umleiten.

Wenn die Befehlszeile analysiert wird, werden Umleitungen in einem von den Variablenzuweisungen getrennten Schritt behandelt. Ihr Befehl entspricht daher (beachten Sie das Leerzeichen)

VALUE= <<PERSON
some data
PERSON

Das heißt, es weist Ihrer Variablen eine leere Zeichenfolge zu und leitet dann die Standardeingabe von der Here-Zeichenfolge in den Befehl um (es gibt jedoch keinen Befehl, sodass nichts passiert).

Beachten Sie, dass

<<PERSON
some data
PERSON

ist gültig, wie es ist

<somefile

Es gibt nur keinen Befehl, dessen Standardeingabestream so eingestellt werden kann, dass er die Daten enthält. Er geht also einfach verloren.

Dies würde jedoch funktionieren:

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

Hier ist der Befehl, der das Here-Dokument empfängt cat, und es kopiert es in seine Standardausgabe. Dies wird dann der Variablen durch die Befehlssubstitution zugewiesen.

In Ihrem Fall könnten Sie stattdessen verwenden

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

ohne den zusätzlichen Schritt des Speicherns der Daten in einer Variablen zu unternehmen.

Kusalananda
quelle
2
Sie können auch einfach PERSON="eine neue Zeile und die mehrzeiligen Daten gefolgt von einer weiteren "am Ende verwenden.
R .. GitHub STOP HELPING ICE
1
@R .. Ja, aber mit einem Here-Dokument können Sie die Anführungszeichen der Shell umgehen. Es ist daher oft sicherer, für mehrzeilige Daten ein Here-Dokument anstelle einer Zeichenfolge in Anführungszeichen zu verwenden, insbesondere wenn die Daten einfache oder doppelte Anführungszeichen (oder beides) enthalten.
Kusalananda
2
@R .. Da es sich um JSON handelt, ist es möglicherweise besser, einfache Anführungszeichen zu verwenden, um nicht den doppelten Anführungszeichen jedes Eigenschaftsnamens zu entgehen. PERSON='. Es sei denn, das OP möchte später Variablen interpolieren.
JoL
(Backslash) (Zeilenumbruch) scheint in einem Dokument hier zu verschwinden, selbst wenn Sie das Trennwort zitieren / entkommen. Das mag wünschenswert sein, aber gibt es eine Möglichkeit, es zu deaktivieren?
Scott
@Scott Wenn diese Frage noch nicht auf dieser Website gestellt wurde, wäre sie eine hervorragende Frage für sich.
Kusalananda
11

Weil die Variable nicht von Ihrem Heredoc festgelegt wird:

$ VALUE=<<PERSON  
> {    
>   "type": "account",  
>   "customer_id": "1234",  
>   "customer_email": "[email protected]",  
> }  
> PERSON
$ echo "$VALUE" 

$

Wenn Sie einen Heredoc verwenden möchten, um einer Variablen einen Wert zuzuweisen, benötigen Sie Folgendes:

$ read -d '' -r VALUE <<PERSON  
{    
  "type": "account",  
  "customer_id": "1234",  
  "customer_email": "[email protected]",  
}   
PERSON
terdon
quelle
1
Warum verpacken Sie die JSON-Daten in einfache Anführungszeichen? Es sieht nicht wirklich so aus, als ob das OP möchte, dass sie Teil seiner Eingabezeichenfolge sind. Abgesehen davon +1 für die Reduzierung der obdachlosen Katzenpopulation. Wie bei Kusalanandas Antwort möchten Sie vielleicht vorschlagen << \PERSON, sich vor $s in der Eingabe und Backslashes an den Zeilenenden zu schützen .
Scott
@Scott ähm, weil ich den Text nur blind aus dem OP kopiert habe. Danke
terdon
3
Das ist die richtige Antwort. $(cat <<EOF ... EOF)ist ein seltsames Konstrukt: eine Unterschale ausführen und dann einen Heredoc an cat senden, nur damit er an STDOUT gesendet wird, und dann das Ergebnis dieser Unterschale einer Variablen zuweisen? Ich wünschte, die Leute würden darüber nachdenken, was sie über ihre Denkprozesse sagen . Im readVergleich dazu ist es sinnvoll, einer Variablen über einen Heredoc zuzuweisen.
Rich
Ich würde nicht sagen, dass $(cat << EOF… (Daten)… EOF )komisch ist. Es ist umständlich und verworren, aber auch read -d … << EOF - besonders read -d '' << EOF . Ich schätze Terdons Antwort, weil sie nur eingebaute Programme verwendet. Noch wichtiger ist jedoch, dass $(cat << EOF… (Daten)… EOF )fehlschlägt, wenn Zeilen mit \(Backslash) enden - siehe die Kommentare unter Kusalanandas Antwort .
Scott
4

Dies liegt daran, dass die Art und Weise, wie Sie ein Here-Dokument für die Verwendung mit einem JSON definiert haben, falsch ist. Sie müssen es als verwenden

VALUE=$(cat <<EOF
{  
  "type": "account",  
  "customer_id": "1234",  
  "customer_email": "[email protected]",  
}
EOF
)

und dabei printf "$VALUE"sollte der JSON wie erwartet ausgegeben werden.

Inian
quelle
3

Heredocs und Variablen mischen sich nicht gut oder zumindest nicht auf diese Weise. Du kannst entweder…

Übergeben Sie den Heredoc als Standardeingabe einer Anwendung

python -m json.tool <<PERSON  
{
  "type": "account",
  "customer_id": "1234",
  "customer_email": "[email protected]",
}
PERSON

oder…

Speichern Sie mehrzeiligen Text in einer Shell-Variablen

VALUE='{
  "type": "account",
  "customer_id": "1234",
  "customer_email": "[email protected]",
}'

Ich habe einfache Anführungszeichen verwendet, um zu vermeiden, dass die inneren doppelten Anführungszeichen vermieden werden müssen. Natürlich können Sie auch doppelte Anführungszeichen verwenden, z. B. wenn Sie Parameter erweitern müssen:

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

Dann können Sie den Variablenwert später verwenden.

echo -n "$VALUE" | python -m json.tool
David Foerster
quelle