web-dev-qa-db-fra.com

Caractères d'échappement en bash (pour JSON)

J'utilise git, puis je poste le message de validation et d'autres bits sous la forme d'une charge JSON sur un serveur.

Actuellement j'ai:

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

qui définit MSG comme suit:

Calendar can't go back past today

puis

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

Mon vrai JSON a un autre couple de champs.

Cela fonctionne bien, mais bien sûr, lorsque j'ai un message de validation tel que celui ci-dessus avec une apostrophe, le JSON est invalide.

Comment puis-je échapper aux caractères requis dans bash? Je ne connais pas bien la langue, alors je ne sais pas par où commencer. Remplacer ' par \' ferait le travail au minimum, je suppose.

38
Rich Bradshaw

OK, a découvert quoi faire. Bash supporte cela nativement comme prévu, bien que, comme toujours, la syntaxe ne soit pas vraiment concevable!

${string//substring/replacement} renvoie essentiellement ce que vous voulez une image, de sorte que vous pouvez utiliser

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

Pour faire ça. Le problème suivant est que la première regex ne fonctionne plus, mais cela peut être remplacé par

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

Finalement, je n'ai même pas eu besoin de leur échapper. Au lieu de cela, j’ai simplement échangé tous les "éléments du JSON" contre "". Vous apprenez quelque chose tous les jours.

10
Rich Bradshaw

Utilisation de Python:

Cette solution n’est pas pure bash, mais elle est non invasive et gère unicode.

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

Notez que JSON fait partie des bibliothèques python standard depuis longtemps, ce qui en fait une dépendance minimale pour Python. 

Ou en utilisant PHP:

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

Utilisez comme si:

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

Au lieu de vous demander comment citer correctement les données, enregistrez-les dans un fichier et utilisez la construction @ que curl autorise avec l'option --data. Pour vous assurer que la sortie de git est correctement échappée pour être utilisée comme valeur JSON, utilisez un outil tel que jq pour générer le JSON au lieu de le créer manuellement.

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'

Vous pouvez également lire directement à partir de l'entrée standard en utilisant -d @-; Je laisse cela au lecteur comme un exercice pour construire le pipeline qui lit de git et produit le message de charge utile correct à télécharger avec curl.

(Indice: c'est jq ... | curl ... -d@- 'https://example.com')

34
chepner

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

Сть два совета, которые я нашел полезными:

  • Nom d'utilisateur: Bash ${string//substring/replacement}, описанный в этой теме.
  • Cliquez ici pour télécharger et télécharger le logiciel de votre ordinateur portable, de votre ordinateur portable, de votre ordinateur portable, de votre ordinateur portable, de votre ordinateur portable, de votre ordinateur portable, de votre ordinateur portable ou de votre ordinateur portable. В vim вы можете ввести их, набравCtrl+Vсопровождается фактическим контрольным кодом (Ctrl+Iдля вкладки например).

В результате были получены следующие замены 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)

На данном тапе я не разобрался, как парильно экранировать, как правильно экранировать, как правильно Обновлю свой ответ, если я решу это.

16
xsgordon

jq peut le faire.

Léger, gratuit et écrit en C, jq bénéficie du soutien de nombreuses communautés avec plus de 12,5k étoiles sur GitHub . Personnellement, je le trouve très rapide et utile dans mon flux de travail quotidien.

Convertir une chaîne en JSON

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

Expliquer,

  • -a signifie "sortie ascii"
  • -R signifie "entrée brute"
  • . signifie "sortie de la racine du document JSON"
  • <<< passe une chaîne dans stdin (bash seulement?)

Cas d'utilisation Git + Curl

Pour corriger l'exemple de code donné par l'OP, lancez simplement jq.

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

J'ai trouvé quelque chose comme ça:

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

Le moyen le plus simple consiste à utiliser jshon , un outil de ligne de commande pour analyser, lire et créer du 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

La ligne ci-dessus fonctionne pour moi. reportez-vous à https://github.com/stedolan/jq pour plus d'outils jq

4
wcy

C'est une solution d'échappement utilisant Perl qui échappe aux barres obliques inverses (\), aux guillemets doubles (") et aux caractères de contrôle U+0000 à 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

J'ai eu la même idée d'envoyer un message avec le message commit après commit ... J'ai d'abord essayé de la même manière que l'auteur. Mais plus tard, nous avons trouvé une solution meilleure et plus simple.

Vous venez de créer un fichier php qui envoie un message et appelez-le avec wget . Dans hooks/post-receive: 

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

dans git.php:

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

Et puis créez JSON et appelez CURL dans le style PHP

0
KirillDE