La expansión de parámetros que resulta en una cadena vacía se trata de manera diferente

10

Actualizar

Alguien en la lista de correo bug-bash ha confirmado que se trata de un error.


Si alguien está interesado, hay una solución disponible en la última versión de commit to devel branch .


Mientras

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

imprime una línea vacía,

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

impresiones bar.

No entiendo esto ${1##*}se expande a una cadena vacía, por lo que "${1##*}"debe tratarse tal como ""está, pero parece que bash no lo cree así.

Parece haber un consenso sobre esto entre otras shimplementaciones populares :

$ 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 (con o sin --posix) es el único que no se ajusta a eso:

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

Y sin cosas de procesamiento de subcadenas, el comportamiento es el esperado:

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

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

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

$ 

Realmente me pregunto si hay una explicación para esto, que no pude encontrar en el manual. ¿Es esto un error o una mala interpretación del estándar? ¿Está este comportamiento documentado en alguna parte?


PD: Sé que una solución rápida es quitar el PE interno, pero eso no responde a mi pregunta y puede dar lugar a resultados no deseados con cadenas que contienen caracteres especiales.

oguz ismail
fuente
GNU bash, version 3.2.57(1)-release (x86_64-apple-darwin18)imprime una cadena vacía
William Pursell
GNU bash, version 4.4.12(1)-release (x86_64-pc-linux-gnu)imprime "bar"
William Pursell
@William probado en 4.4.20 y 5.0.11 y ambos imprimen "barra"
oguz ismail
Esto parece ser un problema con la expansión en general. En mi 4.4.12(3)-release, echo "${BASH##*"${BASH##*}"}"-> /bin/bash. Mientras que echo "\${BASH##*"${BASH##*}"}"-> ${BASH##*}y eval echo "\${BASH##*"${BASH##*}"}"-> en blanco.
Jeff Y

Respuestas:

2

Esta no es una respuesta

Primero estaba pensando que esto se debe a reglas especiales de glob, pero al final creo que esto es un error en bash. Los siguientes cuatro ejemplos deberían darle una idea de por qué creo que esto es un error:

$ 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

El caso 1 y el caso 3 difieren en las comillas. Pero la expansión de parámetros del formulario ${parameter##word}utiliza reglas de expansión de nombre de ruta para procesar word. Por lo tanto *fooy *"foo"tienen un comportamiento idéntico al de las comillas dobles en expansión ruta puede ser ignorado a menos que abrazan caracteres de patrón especiales ( *, ?, ...). Esto se ve en el siguiente ejemplo:

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

Entonces, si este es el caso, ¿por qué el Caso 2 y el Caso 4 deberían comportarse de manera diferente?

kvantour
fuente
¿Por qué los casos 2 y 4 deberían comportarse de manera diferente? No hay razón, tanto ${1+}y se ${1+""}expande para vaciar la cadena, pero no se tratan de la manera que ${1##*}es (ver mi última edición). Por lo tanto, podemos deducir que esto es un error, ¿verdad?
oguz ismail
1
@oguzismail ¡Exactamente! Si el caso 1 y el caso 3 se comportan de manera idéntica, el caso 2 y el caso 4 también deberían comportarse de manera idéntica.
kvantour