webentwicklung-frage-antwort-db.com.de

Zeichen in bash (für JSON) entkommen

Ich verwende git und poste dann die Festschreibungsnachricht und andere Bits als JSON-Payload auf einem Server.

Zur Zeit habe ich:

MSG=`git log -n 1 --format=oneline | grep -o ' .\+'`

was setzt MSG auf etwas wie:

Calendar can't go back past today

dann

curl -i -X POST \
  -H 'Accept: application/text' \
  -H 'Content-type: application/json' \
  -d "{'payload': {'message': '$MSG'}}" \
  'https://example.com'

Mein echter JSON hat noch ein paar Felder.

Das funktioniert gut, aber wenn ich eine Commit-Nachricht wie die oben stehende mit einem Apostroph darin habe, ist die JSON natürlich ungültig.

Wie kann ich die in bash benötigten Zeichen entziehen? Ich bin nicht mit der Sprache vertraut, daher bin ich mir nicht sicher, wo ich anfangen soll. Das Ersetzen von ' durch \' würde die Aufgabe zumindest erfüllen, was ich vermute.

38
Rich Bradshaw

OK, herausgefunden, was zu tun ist. Bash unterstützt dies nativ wie erwartet, allerdings ist die Syntax wie immer nicht wirklich erraten!

Im Wesentlichen gibt ${string//substring/replacement} das Bild zurück, das Sie erstellt haben, sodass Sie es verwenden können

MSG=${MSG//\'/\\\'}

Um dies zu tun. Das nächste Problem ist, dass der erste Regex nicht mehr funktioniert, der aber durch ersetzt werden kann

git log -n 1 --pretty=format:'%s'

Am Ende musste ich ihnen nicht einmal entkommen. Stattdessen habe ich einfach alle 'in der JSON zu\"ausgetauscht.

10
Rich Bradshaw

Python verwenden:

Diese Lösung ist keine reine Bash, aber sie ist nicht invasiv und verarbeitet Unicode.

json_escape () {
    printf '%s' "$1" | python -c 'import json,sys; print(json.dumps(sys.stdin.read()))'
}

Beachten Sie, dass JSON bereits seit langer Zeit Teil der Standard-Python-Bibliotheken ist. Daher ist dies eine ziemlich geringe Abhängigkeit von Python. 

Oder mit PHP:

json_escape () {
    printf '%s' "$1" | php -r 'echo json_encode(file_get_contents("php://stdin"));'
}

Gebrauch wie folgt:

$ json_escape "ヤホー"
"\u30e4\u30db\u30fc"
49
polm23

Statt sich darum zu kümmern, wie die Daten korrekt zitiert werden sollen, speichern Sie sie einfach in einer Datei und verwenden Sie das @-Konstrukt, das curl mit der Option --data zulässt. Um sicherzustellen, dass die Ausgabe von git für die Verwendung als JSON-Wert korrekt escape ist, verwenden Sie ein Tool wie jq, um den JSON zu generieren, anstatt ihn manuell zu erstellen.

jq -n --arg msg "$(git log -n 1 --format=oneline | grep -o ' .\+')" \
   '{payload: { message: $msg }}' > git-tmp.txt

curl -i -X POST \
  -H 'Accept: application/text' \
  -H 'Content-type: application/json' \
  -d @git-tmp.txt \
  'https://example.com'

Sie können mit -d @- auch direkt aus der Standardeingabe lesen. Ich lasse das als Übung für den Leser, um die Pipeline zu erstellen, die aus git liest und die korrekte Nutzlastnachricht erzeugt, die mit curl hochgeladen wird.

(Hinweis: es ist jq ... | curl ... [email protected] 'https://example.com')

34
chepner

JSON, когда натолкнулся экранировать символы Bash для передачи с помощью JSON, когда натолкнулся нато. Я обнаружил, что на самом деле есть больший список символов, которые должны быть экранированы - особенно если вы пытаетесь обрабатывать текст произвольной формы.

Weitere Informationen zu diesem Produkt:

  • Используйте синтаксис Bash ${string//substring/replacement}, описанный в этой теме.
  • Используйте фактические управляющие символы для табуляции, новой строки, возврата каретки и т.д. Vim Vim Vim Vim Vim Vim VimCtrl+Vсопровождается фактическим контрольным кодом (Ctrl+Iдля вкладки например).

Weitere Informationen zu Bash:

JSON_TOPIC_RAW=${JSON_TOPIC_RAW//\\/\\\\} # \ 
JSON_TOPIC_RAW=${JSON_TOPIC_RAW//\//\\\/} # / 
JSON_TOPIC_RAW=${JSON_TOPIC_RAW//\'/\\\'} # ' (not strictly needed ?)
JSON_TOPIC_RAW=${JSON_TOPIC_RAW//\"/\\\"} # " 
JSON_TOPIC_RAW=${JSON_TOPIC_RAW//   /\\t} # \t (tab)
JSON_TOPIC_RAW=${JSON_TOPIC_RAW//
/\\\n} # \n (newline)
JSON_TOPIC_RAW=${JSON_TOPIC_RAW//^M/\\\r} # \r (carriage return)
JSON_TOPIC_RAW=${JSON_TOPIC_RAW//^L/\\\f} # \f (form feed)
JSON_TOPIC_RAW=${JSON_TOPIC_RAW//^H/\\\b} # \b (backspace)

In diesem Fall können Sie den Artikel (in englischer Sprache) von (in englischer Sprache) von (in englischer Sprache) von (in englischer Sprache) eingeben. Я обновлю свой ответ, если я решу это.

16
xsgordon

jq kann dies tun.

Leicht, kostenlos und in C geschrieben, genießt jq weit verbreitete Community-Unterstützung mit über 12,5.000 Sternen auf GitHub . Ich persönlich finde es sehr schnell und nützlich in meinem täglichen Arbeitsablauf.

Konvertieren Sie den String in JSON

jq -aR . <<< '猫に小判'

Erklären,

  • -a bedeutet "ASCII-Ausgabe"
  • -R bedeutet "rohe Eingabe"
  • . bedeutet "Ausgabe des Stammes des JSON-Dokuments"
  • <<< übergibt einen String an stdin (nur bash?)

Git + Curl-Anwendungsfall

Um das vom OP angegebene Codebeispiel zu korrigieren, leiten Sie einfach jq durch.

MSG=`git log -n 1 --format=oneline | grep -o ' .\+' | jq -aR .`
9
jchook

Ich habe so etwas gefunden:

MSG=`echo $MSG | sed "s/'/\\\\\'/g"`
4
user907860

Der einfachste Weg ist die Verwendung von jshon , einem Befehlszeilentool zum Analysieren, Lesen und Erstellen von JSON.

jshon -s 'Your data goes here.' 2>/dev/null

4
m-szalik
git log -n 1 --format=oneline | grep -o ' .\+' | jq --Slurp --raw-input

Die obige Zeile funktioniert für mich. Weitere jq-Tools finden Sie unter https://github.com/stedolan/jq

4
wcy

Dies ist eine Escape-Lösung, die Perl verwendet und Backslash (\), Anführungszeichen (") und Steuerzeichen U+0000 bis U+001F:

$ echo -ne "Hello, ????\n\tBye" | \
  Perl -pe 's/(\\(\\\\)*)/$1$1/g; s/(?!\\)(["\x00-\x1f])/sprintf("\\u%04x",ord($1))/eg;'
Hello, ????\u000a\u0009Bye
0
Josh Bode

Ich hatte die gleiche Idee, eine Nachricht mit Commit-Nachricht nach Commit zu verschicken . Zuerst versuchte ich es ähnlich wie hier als Autor. Aber später eine bessere und einfachere Lösung gefunden.

Erstellte gerade eine PHP-Datei, die eine Nachricht sendet, und rufe sie mit wget . In hooks/post-receive auf: 

wget -qO - "http://localhost/git.php" 

in git.php:

chdir("/opt/git/project.git");
$git_log = exec("git log -n 1 --format=oneline | grep -o ' .\+'");

Erstellen Sie anschließend JSON und rufen Sie CURL im Stil PHP auf

0
KirillDE