Bash-Variablensubstitution in einer JSON-Zeichenfolge

9

Ich versuche, einen JSON in BASH zu erstellen, wobei eines der Felder auf dem Ergebnis eines früheren Befehls basiert

BIN=$(cat next_entry)
OUTDIR="/tmp/cpupower/${BIN}"
echo $OUTDIR
JSON="'"'{"hostname": "localhost", "outdir": "${OUTDIR}", "port": 20400, "size": 100000}'"'"
echo $JSON

Das obige Skript gibt bei Ausführung Folgendes zurück:

/tmp/cpupower/0
, port: 20400, size: 100000}': /tmp/cpupower/0

Wie kann ich Variablen in diesen Zeichenfolgen mit mehreren Anführungszeichen richtig ersetzen?

Guru Prasad
quelle
1
Ich glaube, ich habe gerade eine rauchende Raupe und eine grinsende Katze gesehen. (1) Ich sehe keine Möglichkeit, dass die in der Frage dargestellten Befehle die in der Frage dargestellte Ausgabe erzeugt haben könnten. (Beachten Sie, dass die OUTDIRVariable im Wert von JSONund in den Anführungszeichen erweitert zu sein scheint "port"und "size"unerklärlicherweise nicht vorhanden ist.) (2) Es scheint mir offensichtlich, dass die BINVariable einen Wagenrücklauf enthält (aus der next_entryDatei); und doch ging das Problem anscheinend weg, ohne dass dieses Problem angesprochen wurde.
G-Man sagt "Reinstate Monica"

Antworten:

14
JSON=\''{"hostname": "localhost", "outdir": "'"$OUTDIR"'", "port": 20400, "size": 100000}'\'

Das ist aus den einfachen Anführungszeichen für die Erweiterung von $OUTDIR. Wir haben diese Erweiterung aus gutem Grund in doppelte Anführungszeichen gesetzt, obwohl dies für eine skalare Variablenzuweisung nicht unbedingt erforderlich ist.

Wenn Sie die vorbei sind $JSONVariable echo, Zitate sind notwendig , wenn die Split + glob Operator zu deaktivieren. Es ist auch am besten, echofür beliebige Daten zu vermeiden :

printf '%s\n' "$JSON"
Stéphane Chazelas
quelle
Cool. Das funktioniert! Könnten Sie vielleicht etwas mehr erklären, warum dies funktioniert? Was ist die Bedeutung der ersten \'. Ich glaube nicht, dass ich das bei einigen Beispielen gesehen habe, die ich bei SO / unix.stackexchange gesehen habe.
Guru Prasad
Backslash vor 'weist die Shell an,' wie jedes normale Zeichen zu behandeln, anstatt es als Zeichenfolgenbegrenzer zu interpretieren. Der Backslash kann vor einigen anderen Zeichen verwendet werden. Zum Beispiel repräsentiert \\ das \ Zeichen selbst und \ "bedeutet das" literarische Zeichen. Siehe zum Beispiel das Argument \ n im obigen Argument printf, wobei printf \ n als Zeilenvorschubzeichen interpretiert.
Rein
1
(1) Ich glaube, Sie hätten klarer sein müssen, dass der Wechsel von "'"zu \'völlig stilistisch (dh willkürlich) war und dass die einzige wesentliche Änderung, die Sie vorgenommen haben, die Anführungszeichen waren $OUTDIR. (Sie könnten auch erwähnt haben, dass die Zahnspangen ${OUTDIR}einfach nicht notwendig waren.) (2) Bitte lesen Sie meinen Kommentar zu der Frage und sagen Sie mir, ob ich halluziniere (dh habe ich etwas übersehen oder haben Sie?).
G-Man sagt "Reinstate Monica"
@ G-Man, ich stimme dir zu.
Stéphane Chazelas
3

Stéphanes Antwort ist großartig und positiv bewertet. Hier ist nur ein Tipp; anstatt zu tun

BIN=$(cat next_entry)

Du kannst tun:

BIN=$(<next_entry)

Und sparen Sie so das Laichen eines zusätzlichen Prozesses. Lesen Sie hier mehr .

maulinglawns
quelle
2
Es spart nur das Laichen eines zusätzlichen Prozesses in ksh (woher diese Syntax stammt) und zsh, nicht in bash. In bash, spart es nur die Ausführung cat, bashnoch einen zusätzlichen Prozess erzeugen. Siehe Grundlegendes Bash Read-a-Datei Befehl Substitution für weitere Details.
Stéphane Chazelas
0

Wenn Sie hier gelandet sind und versucht haben, AWS-Befehle zu verwenden, funktioniert die Antwort von @ Stéphane Chazelas fast. Hier sind die anfänglichen Anführungszeichen (\ ') nicht erforderlich, sie brechen tatsächlich den Befehl.

IP=$(curl ipecho.net/plain ; echo)

aws ec2 authorize-security-group-ingress --group-id sg-**************** \
    --ip-permissions '[{"IpProtocol": "tcp", "FromPort": 15000, "ToPort": 15000, "IpRanges": [{"CidrIp": "'"$IP/32"'", "Description": "Service A"}]}]'

^ Das funktioniert gut

Alan Sikora
quelle