Rozwinięcie parametru w wyniku pustego łańcucha traktowane jest inaczej

10

Aktualizacja

Ktoś w liście dyskusyjnej bug-bash został potwierdzony jest to błąd.


Jeśli ktoś jest zainteresowany, poprawka jest dostępna w najnowszej gałęzi commit to devel .


Podczas

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

wypisuje pustą linię,

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

odciski bar.

Nie rozumiem tego ${1##*}rozwija się do pustego ciągu, więc "${1##*}"należy go traktować tak, jak ""jest, ale wydaje się, że bash tak nie uważa.

Wydaje się, że istnieje konsensus w tej sprawie wśród innych popularnych shwdrożeń:

$ 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 (z lub bez --posix) jest jedynym niezgodnym z tym:

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

I bez elementów przetwarzających podciąg zachowanie jest zgodne z oczekiwaniami:

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

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

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

$ 

Naprawdę zastanawiam się, czy jest na to wyjaśnienie, którego nie znalazłem w instrukcji. Czy to błąd, czy błędna interpretacja standardu? Czy to zachowanie jest gdzieś udokumentowane?


PS: Wiem, że szybkim obejściem jest cofnięcie cytowania wewnętrznej PE, ale to nie odpowiada na moje pytanie i może prowadzić do niepożądanych wyników w przypadku ciągów znaków specjalnych.

oguz ismail
źródło
GNU bash, version 3.2.57(1)-release (x86_64-apple-darwin18)wypisuje pusty ciąg
William Pursell
GNU bash, version 4.4.12(1)-release (x86_64-pc-linux-gnu)drukuje „bar”
William Pursell
@William testowany na 4.4.20 i 5.0.11 i oba drukują „pasek”
oguz ismail
Wydaje się, że jest to ogólnie problem z ekspansją. W moim 4.4.12(3)-release, echo "${BASH##*"${BASH##*}"}"-> /bin/bash. Podczas gdy echo "\${BASH##*"${BASH##*}"}"-> ${BASH##*}i eval echo "\${BASH##*"${BASH##*}"}"-> puste.
Jeff Y

Odpowiedzi:

2

To nie jest odpowiedź

Najpierw myślałem, że wynika to ze specjalnych reguł globalnych, ale ostatecznie myślę, że to błąd w bashu. Poniższe cztery przykłady powinny dać ci poczucie, dlaczego uważam, że to błąd:

$ 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

Przypadek 1 i przypadek 3 różnią się cytatami. Jednak rozszerzenie parametrów formularza ${parameter##word}korzysta z reguł interpretacji nazw ścieżek do przetworzenia word. Tak *fooi *"foo"mają identyczne zachowanie jak cudzysłów przy rozwijaniu nazw plików mogą być ignorowane, chyba że objąć specjalne znaki wzorca ( *, ?...). Jest to widoczne w następującym przykładzie:

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

Więc jeśli tak jest, dlaczego przypadek 2 i przypadek 4 miałyby zachowywać się inaczej?

kvantour
źródło
dlaczego przypadek 2 i przypadek 4 powinny zachowywać się inaczej? Nie ma powodu, zarówno ${1+}i ${1+""}rozszerza się na pusty ciąg znaków, ale nie są one traktowane droga ${1##*}jest (patrz mój ostatni Edit). Możemy więc wywnioskować, że to błąd, prawda?
oguz ismail
1
@oguzismail Dokładnie! Jeśli przypadek 1 i przypadek 3 zachowują się identycznie, to przypadek 2 i przypadek 4 powinny również zachowywać się identycznie.
kvantour