Que nécessite POSIX pour citer ici des documents à l'intérieur de la substitution de command?

Dans cette question, quelqu'un signale un problème en utilisant un document ici avec un mot de délimiteur cité dans la substitution de la command $(...) , où une barre oblique inverse \ à la fin d'une ligne à l'intérieur du document triggers la poursuite de la ligne jointe document de substitution de command externe fonctionne comme prévu.

Voici un exemple de document simplifié:

 cat <<'EOT' abc ` def ghi \ jkl EOT 

Cela inclut un backtick et une backslash à la fin d'une ligne. Le délimiteur est cité, donc aucune expansion ne se produit à l'intérieur du corps. Dans tous les Bourne-alikes, je peux find que le contenu du contenu est extrait textuellement. Si je mets le même document à l'intérieur d'une substitution de command comme suit:

 x=$(cat <<'EOT' abc ` def ghi \ jkl EOT ) echo "$x" 

alors ils ne se comportent plus de manière identique:

  • dash , ash , zsh , ksh93 , BusyBox ash , mksh et SunOS 5.10 POSIX sh donnent tous le contenu textuel du document, comme précédemment.
  • Bash 3.2 donne une erreur de syntaxe pour un backtick inégalé. Avec les backticks appariés, il tente d'exécuter le contenu en tant que command.
  • Bash 4.3 efface "ghi" et "jkl" sur une seule ligne, mais n'a pas d'erreur. L' option --posix n'affecte pas cela. Kusalananda me dit (merci!) Que pdksh se comporte de la même façon .

Dans la question initiale, j'ai dit que c'était un bug dans l'parsingur de Bash. Est-ce? [Mise à jour: oui ] Le text pertinent de POSIX (tous de la définition du langage de command de Shell) que je peux find est:

  • §2.6.3 Substitution de commandment :

    Avec le formulaire $ (command), tous les caractères suivant la parenthèse ouvrante à la parenthèse fermante correspondante constituent la command. Tout script shell valide peut être utilisé pour la command , à l'exception d'un script composé uniquement de redirections produisant des résultats non spécifiés.

  • §2.7.4 Ici-Document :

    Si une partie d'un mot est citée, le délimiteur doit être formé en effectuant l'extraction des citations sur le mot et les lignes du document ne doivent pas être développées.

  • §2.2.1 Caractère d'échappement (barre oblique inverse) :

    Si un <newline> suit le <backslash>, le shell doit interpréter cela comme une continuation de ligne. Les <backslash> et <newline> doivent être supprimés avant de fractionner l'input en jetons.

  • §2.3 Reconnaissance des jetons :

    Lorsqu'un jeton io_here a été reconnu par la grammaire (voir la grammaire Shell ), une ou plusieurs des lignes suivantes qui suivent immédiatement le jeton NEWLINE suivant forment le corps d'un ou plusieurs documents ici et doivent être analysées selon les règles de Here- Document .

    Lorsqu'il ne traite pas un io_here , le shell casse son input en jetons en appliquant la première règle applicable ci-dessous au caractère suivant dans son input. …

    1. Si le caractère actuel est <backslash>, un guillemet simple ou un guillemet double et qu'il n'est pas coté, il affecte la cotation des caractères suivants jusqu'à la fin du text cité. Les règles de cotation sont décrites dans la rubrique Cotation . Lors de la reconnaissance de jeton, aucune substitution ne doit être effectuée et le jeton de résultat doit contenir exactement les caractères apparaissant dans l'input (sauf pour la jointure <newline>), non modifiés, y compris les guillemets inclus ou fermés du text cité.

Mon interprétation de ceci est que tous les caractères après $( jusqu'à la terminaison ) include le script shell, verbatim; un document ici apparaît, donc ici le traitement de document se produit au lieu de la tokenisation ordinaire; le document ici a alors un délimiteur cité, ce qui signifie que son contenu est traité textuellement; et le personnage échappé ne vient jamais en elle. Je peux voir un argument, cependant, que ce cas n'est tout simplement pas abordé, et les deux comportements sont autorisés. Il est possible que j'ai oublié un text pertinent quelque part, aussi.


  • Cette situation est-elle rendue plus claire ailleurs?
  • Sur quoi un script portable devrait-il pouvoir countr (en théorie)?
  • Est-ce que le traitement spécifique donné par l'une de ces coquilles (Bash 3.2 / Bash 4.3 / tout le monde) est imposé par la norme? Interdit? Permis?

@MichaelMrozek La réponse précédente n'a pas lien vers un sujet sectionné par le requestur. Le requestur a posé une question sur la list de diffusion et la réponse était que c'était un bug. Le requestur n'a pas suivi cette discussion sur la list de diffusion. J'ai posté un nouveau fil de discussion la nuit dernière pour faire un suivi avec le mainteneur Bash, et il a répondu avec exactement une réponse à cette question. Comment croyez-vous que la réponse suivante ne répond pas à la question?

La substitution de command est un hareng rouge; c'est pertinent seulement en ce qu'il a indiqué où le bogue était.

Le délimiteur du document ci-dessous est cité, de sorte que les lignes ne sont pas développées. Dans ce cas, le shell lit les lignes de l'input comme si elles étaient citées. Si une barre oblique inverse apparaît dans un context où elle est citée, elle n'agit pas comme un caractère d'échappement (voir ci-dessous) et le traitement spécial de backslash-newline n'a pas lieu. En fait, si une partie du délimiteur est citée, les lignes du document sont lues comme si elles étaient cotées.

Le text dans Posix 2.2.1 est écrit maladroitement, mais signifie que la barre oblique inverse n'est traitée que lorsqu'elle n'est pas citée. Vous pouvez citer une barre oblique inverse et interdire toute expansion uniquement avec des guillemets simples ou une autre barre oblique inverse.

La partie de lecture étroite est le text "non développé" impliquant les guillemets simples. La norme stipule en 2.2 que les documents sont ici "une autre forme de citation", mais la seule forme de citation dans laquelle les mots ne sont pas étendus du tout est des guillemets simples. Donc, c'est une forme de citation qui est à peu près exactement comme des guillemets simples, mais pas des guillemets simples.

http://lists.gnu.org/archive/html/bug-bash/2017-02/msg00073.html