Journal Écrire du JSON dans un script bash

Posté par  .
Étiquettes : aucune
2
13
oct.
2026

J'ai toujours galéré à quoter et échapper correctement les chaînes de caractères compliquées avec bash, donc je me suis dit que j'allais (enfin) regarder la doc.

Je parle de JSON dans le titre, qui est particulièrement pénible car il contient beaucoup de guillemets, mais ça s'applique aussi aux quotes l'une dans l'autre, typiquement quand on veut exécuter une sous-commande. Par exemple un one-liner dans un autre langage de programmation, ou une commande avec ssh ou un sous-shell.

Commençons par regarder les 4 mécanismes de quoting intéressants dans bash, on passera ensuite à des exemples.

Les mécanismes

1. Les apostrophes

C'est le plus simple à expliquer : tout ce qui est entre des apostrophes est traité comme un caractère normal, à l'exception d'un \ suivi d'un retour à la ligne, qui ignore ce retour à la ligne.

Une conséquence pénible de ce fonctionnement est qu'il est impossible de mettre une apostrophe dans ce type de chaîne. Une façon moche de contourner ça est de fermer l'apostrophe, l'échapper puis la rouvrir :

echo 'l'\''animal'

A noter que la commande echo de zsh interprète par défaut les caractères d'échappement commençant par \, ce qui peut donner à tort l'impression que les chaînes entre apostrophes le font.

2. les guillemets

Ils interprètent les séquences commençant par $ (variables, etc.), les séquences avec \ et les apostrophes inversées (commandes).

C'est souvent le plus pratique, mais l'inconvénient est que pour les formats comme le JSON, il faut échapper beaucoup de guillemets.

3. Le quoting ANSI-C

Celui-ci je ne le connaissais pas : c'est la même chose que les guillemets simples, mais il interprète les séquences en \ :

echo $'l\'animal'

C'est vraiment pratique, car ça permet de faire la même chose que des guillemets simples, mais avec la possibilité de mettre des guillemets simples facilement, ou d'autres caractères spéciaux comme les tabulations ou les retours à la ligne.

4. Les here docs

Ce n'est pas un mécanisme de quoting, mais sert à indiquer une chaîne de caractères qui va être envoyé sur stdin. Il est très pratique pour des chaînes de caractères de plusieurs lignes, et on peut tricher pour l'utiliser pour le quoting :

# Ecrit le here document dans fichier.txt
cat > fichier.txt <<EOF
Ligne 1
Ligne 2
EOF

# On triche pour le quoting
echo $(<<EOF
Ligne 1
Ligne 2
EOF
)

À noter que EOF est une chaîne de caractères arbitraire : on peut utiliser n'importe quelle chaîne qui ne sera pas une ligne du here document.

En pratique

Sans variables

Admettons que l'on veuille consulter une API de météo. Commençons par la façon pénible de faire :

curl --json '{"city": "L'\''Isle d'\''Abeau"}' https://example.com/weather

Maintenant, avec ce qu'on a appris on peut utiliser le quoting ANSI-C :

curl --json $'{"city": "L\'Isle d\'Abeau"}' https://example.com/weather

Ou les here documents :

curl --json @- https://example.com/weather <<EOF
{"city": "L'Isle d'Abeau"}
EOF

Note : @- est une option spécifique à curl lui disant de lire les données sur stdin.

Avec des variables

Commençons cette fois-ci aussi par la façon pénible de faire. Vu qu'on ne peut pas utiliser des variables avec des apostrophes, utilisons des guillemets :

curl --json "{\"city\":\"$CITY\"}" https://example.com/weather

On peut faire mieux avec un here document :

curl --json @- https://example.com/weather <<EOF
{"city": "$CITY"}
EOF

Ou avec des guillemets simples et printf :

printf '{"city":"%s"}' "$CITY" | curl --json @- https://example.com/weather <<EOF

Ou, si on veut une solution qui marche avec une ville arbitraire pouvant contenir des guillemets dans son nom :

jq -n '{city: $CITY}' --arg CITY "$CITY" | curl --json @- https://example.com/weather <<EOF
  • # Bash

    Posté par  (site web personnel, Mastodon) . Évalué à 2 (+0/-0).

    Si je puis me permettre, Bash est hasbeen. J'entends bien que bash est indispensable, mais il doit être réduit au minimum (lancement basic de l'application dans son environnement, quelques commandes d'init au besoin). Après il faut passer au Perl ou, plus moderne, Python. En fait je dirais même que Bash est à réservé pour l'admin sys.

    Clairement Bash est une horreur et pas seulement pour les chaines de caractères, mais aussi pour les conditions. Non seulement, c'est plus simple de s'en passer quand on peut, mais aussi c'est plus sécurisé. Combien de fois un script bash qui fonctionnait bien se met à planter à cause d'un paramètre, ou un chemin avec un accent, un espace, un dollar… quand ce n'est pas un hacker qui l'exploite.

    Sous licence Creative common. Lisez, copiez, modifiez faites en ce que vous voulez.

    • [^] # Re: Bash

      Posté par  . Évalué à 1 (+0/-0).

      Autant je suis d'accord que bash est inadapté à des scripts trop compliqués et qu'il a beaucoup de footguns, autant il a deux avantages très importants :

      • Il est installé partout
      • Il permet de passer très facilement de commandes lancées manuellement dans un terminal à un script

      Pour les footguns, shellcheck est un très bon linter et permet d'identifier facilement la plupart des commentaires.

      Quant à la remarque "Bash est hasbeen", je ne sais pas quoi y répondre vu que dans la foulée tu proposes d'utiliser Perl.

  • # Here-doc et pipe sur les deux derniers exemples

    Posté par  . Évalué à -6 (+0/-3).

    Les deux derniers exemples ont un <<EOF sans corps, après le pipe. @- lit le stdin de curl, et ce here-doc le remplace : le JSON du printf ou de jq n’arrive pas. Sans le <<EOF, le pipe suffit.

Envoyer un commentaire

Suivre le flux des commentaires

Note : les commentaires appartiennent à celles et ceux qui les ont postés. Nous n’en sommes pas responsables.