L'expansion des paramètres entraînant une chaîne vide est traitée différemment

10

Mise à jour

Un membre de la liste de diffusion bug-bash a confirmé qu'il s'agit d'un bogue.


Si quelqu'un est intéressé, un correctif est disponible dans la dernière branche commit to devel .


Tandis que

bash -c 'echo "${1##*""}"' _ bar

imprime une ligne vide,

bash -c 'echo "${1##*"${1##*}"}"' _ bar

impressions bar .

Je ne comprends pas ça. ${1##*}se développe en une chaîne vide, "${1##*}"doit donc être traité comme"" tel quel, mais il semble que bash ne le pense pas.

Il semble y avoir un consensus à ce sujet parmi les autres shimplémentations populaires :

$ sh -c 'echo "${1##*"${1##*}"}"' _ bar

$ ash -c 'echo "${1##*"${1##*}"}"' _ bar

$ dash -c 'echo "${1##*"${1##*}"}"' _ bar

$ ksh -c 'echo "${1##*"${1##*}"}"' _ bar

$ ksh93 -c 'echo "${1##*"${1##*}"}"' _ bar

$ mksh -c 'echo "${1##*"${1##*}"}"' _ bar

$ posh -c 'echo "${1##*"${1##*}"}"' _ bar

$ yash -c 'echo "${1##*"${1##*}"}"' _ bar

$ zsh -c 'echo "${1##*"${1##*}"}"' _ bar

$

bash (avec ou sans --posix) est le seul non conforme à cela:

$ bash -c 'echo "${1##*"${1##*}"}"' _ bar
bar

Et sans trucs de traitement de sous-chaîne, le comportement est comme prévu:

$ bash -c 'echo "${1##*"${1+}"}"' _ bar

$ bash -c 'echo "${1##*"${2}"}"' _ bar

$ bash -c 'echo "${1##*"${2}"}"' _ bar ''

$ 

Je me demande vraiment s'il y a une explication à cela, que je n'ai pas pu trouver dans le manuel. Est-ce un bug ou une mauvaise interprétation de la norme? Ce comportement est-il documenté quelque part?


PS: Je sais qu'une solution rapide consiste à ne pas citer le PE interne, mais cela ne répond pas à ma question et peut conduire à des résultats indésirables avec des chaînes contenant des caractères spéciaux.

oguz ismail
la source
GNU bash, version 3.2.57(1)-release (x86_64-apple-darwin18)imprime une chaîne vide
William Pursell
GNU bash, version 4.4.12(1)-release (x86_64-pc-linux-gnu)imprime "bar"
William Pursell
@William testé sur 4.4.20 et 5.0.11 et les deux "barre" d'impression
oguz ismail
Cela semble être un problème avec l'expansion en général. Dans mon 4.4.12(3)-release, echo "${BASH##*"${BASH##*}"}"-> /bin/bash. Alors que echo "\${BASH##*"${BASH##*}"}"-> ${BASH##*}et eval echo "\${BASH##*"${BASH##*}"}"-> vide.
Jeff Y

Réponses:

2

Ce n'est pas une réponse

Je pensais d'abord que cela était dû à des règles globales spéciales, mais à la fin je pense que c'est un bug dans bash. Les quatre exemples suivants devraient vous donner une idée pourquoi je pense que c'est un bug:

$ bash -c 'echo "${1##*${1%%bar}}"' _ foobar        # case 1
bar
$ bash -c 'echo "${1##*${1%%foobar}}"' _ foobar     # case 2

$ bash -c 'echo "${1##*"${1%%bar}"}"' _ foobar      # case 3
bar
$ bash -c 'echo "${1##*"${1%%foobar}"}"' _ foobar   # case 4
foobar

Le cas 1 et le cas 3 diffèrent dans les citations. Mais l'expansion des paramètres du formulaire ${parameter##word}utilise des règles d'expansion des noms de chemin à traiter word. Donc , *fooet *"foo"ont un comportement identique des guillemets doubles dans l' expansion du chemin peut être ignorée à moins qu'ils embrassent des caractères spéciaux motif ( *, ?, ...). Cela se voit dans l'exemple suivant:

$ bash -c 'echo "${1##*${2%%b*r}}"' _ 'foobar' 'f*ob*r'
bar
$ bash -c 'echo "${1##*"${2%%b*r}"}"' _ 'foobar' 'f*ob*r'
foobar

Si tel est le cas, pourquoi le cas 2 et le cas 4 devraient-ils se comporter différemment?

kvantour
la source
pourquoi le cas 2 et le cas 4 devraient-ils se comporter différemment? Aucune raison, à la fois ${1+}et se ${1+""}développe en chaîne vide, mais ils ne sont pas traités de la même façon ${1##*}(voir ma dernière modification). On peut donc en déduire que c'est un bug, non?
oguz ismail
1
@oguzismail Exactement! Si le cas 1 et le cas 3 se comportent de manière identique, le cas 2 et le cas 4 doivent également se comporter de manière identique.
kvantour