108 votes

Échapper les caractères en bash (pour JSON)

Je suis en train d'utiliser git, puis d'envoyer le message de validation et d'autres éléments sous forme de charge utile JSON à un serveur.

Actuellement, j'ai:

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

qui définit MSG à quelque chose comme:

Le calendrier ne peut pas revenir en arrière jusqu'à aujourd'hui

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 quelques autres champs.

Cela fonctionne bien, mais bien sûr lorsque j'ai un message de validation comme celui ci-dessus avec une apostrophe, le JSON n'est pas valide.

Comment puis-je échapper les caractères requis en bash ? Je ne suis pas familier avec le langage, donc je ne sais pas par où commencer. Remplacer ' par \' ferait probablement l'affaire au minimum, je suppose.

136voto

jchook Points 700

jq peut échapper les chaînes pour les utiliser dans les scripts shell ou les documents JSON.

Léger, gratuit et écrit en C, jq bénéficie d'un large soutien de la communauté avec plus de 25 000 étoiles sur GitHub. Personnellement, je le trouve très rapide et utile dans mon flux de travail quotidien.

Convertir une chaîne en JSON

echo -n '猫に小判' | jq -Rsa .

"\u732b\u306b\u5c0f\u5224"

Pour expliquer,

  • -R signifie "entrée brute"
  • -s signifie "inclure les sauts de ligne" (mnémotechnique : "engloutir")
  • -a signifie "sortie en ascii" (optionnel)
  • . signifie "afficher la racine du document JSON"

Cas d'utilisation de Git + Grep

Pour corriger l'exemple de code donné par l'OP, il suffit de rediriger la sortie vers jq.

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

84voto

polm23 Points 622

Utilisation de Python :

Cette solution n'est pas purement bash, mais elle n'est pas invasive et gère les caractères 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 standard de Python depuis longtemps, donc c'est une dépendance Python assez minimale.

Ou en utilisant PHP :

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

Utilisation :

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

67voto

chepner Points 54078

Au lieu de vous inquiéter de la manière de citer correctement les données, enregistrez-les simplement dans un fichier et utilisez la construction @ autorisée par curl 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 depuis l'entrée standard en utilisant -d @-; je laisse cela comme exercice pour le lecteur de construire le pipeline qui lit depuis git et produit le bon message de charge utile à télécharger avec curl.

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

23voto

xsgordon Points 193

J'essayais également d'échapper des caractères en Bash, pour le transfert en utilisant JSON, quand je suis tombé là-dessus. J'ai trouvé qu'en fait il y a une plus grande liste de caractères qui doivent être échappés – en particulier si vous essayez de gérer du texte libre.

J'ai trouvé deux conseils utiles :

  • Utilisez la syntaxe Bash ${string//substring/replacement} décrite dans ce fil.
  • Utilisez les caractères de contrôle réels pour tabulation, retour à la ligne, retour chariot, etc. Dans vim, vous pouvez les entrer en tapant Ctrl+V suivi du code de contrôle réel (Ctrl+I pour la tabulation par exemple).

Les remplacements Bash résultants que j'ai trouvés sont les suivants :

JSON_TOPIC_RAW=${JSON_TOPIC_RAW//\\/\\\\} # \ 
JSON_TOPIC_RAW=${JSON_TOPIC_RAW//\//\\\/} # / 
JSON_TOPIC_RAW=${JSON_TOPIC_RAW//\'/\\\'} # ' (pas nécessaire en stricte)
JSON_TOPIC_RAW=${JSON_TOPIC_RAW//\"/\\\"} # " 
JSON_TOPIC_RAW=${JSON_TOPIC_RAW//   /\\t} # \t (tabulation)
JSON_TOPIC_RAW=${JSON_TOPIC_RAW//
/\\\n} # \n (retour à la ligne)
JSON_TOPIC_RAW=${JSON_TOPIC_RAW//^M/\\\r} # \r (retour chariot)
JSON_TOPIC_RAW=${JSON_TOPIC_RAW//^L/\\\f} # \f (saut de page)
JSON_TOPIC_RAW=${JSON_TOPIC_RAW//^H/\\\b} # \b (retour arrière)

Je n'ai pas encore trouvé comment échapper correctement les caractères Unicode, ce qui est apparemment aussi nécessaire. Je mettrai à jour ma réponse si j'arrive à le faire.

14voto

Rich Bradshaw Points 33598

D'accord, j'ai découvert quoi faire. Bash le supporte nativement comme prévu, bien que, comme toujours, la syntaxe n'est pas vraiment très devinable !

Essentiellement ${string//substring/replacement} retourne ce que vous pouvez imaginer, donc vous pouvez utiliser

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

Pour faire cela. Le prochain problème est que le premier regex ne fonctionne plus, mais cela peut être remplacé par

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

En fin de compte, je n'ai même pas eu besoin de les échapper. Au lieu de cela, j'ai simplement échangé tous les ' dans le JSON par \". Eh bien, on apprend quelque chose chaque jour.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X