Ekspansi parameter yang menghasilkan string kosong diperlakukan berbeda

10

Memperbarui

Seseorang di milis bug-bash telah mengkonfirmasi bahwa ini adalah bug.


Jika ada yang tertarik, perbaikan tersedia di komit terbaru untuk mengembangkan cabang .


Sementara

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

mencetak garis kosong,

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

cetakan bar.

Saya tidak mengerti ini. ${1##*}mengembang ke string kosong, jadi "${1##*}"harus diperlakukan sama seperti sebelumnya "", tetapi sepertinya bash tidak berpikir begitu.

Tampaknya ada konsensus mengenai ini di antara shimplementasi populer lainnya :

$ 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 (dengan atau tanpa --posix) adalah satu-satunya yang tidak sesuai dengan itu:

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

Dan tanpa mengolah hal-hal pemrosesan perilaku seperti yang diharapkan:

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

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

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

$ 

Saya benar-benar bertanya-tanya apakah ada penjelasan untuk ini, yang tidak dapat saya temukan di manual. Apakah ini bug, atau kesalahan interpretasi standar? Apakah perilaku ini didokumentasikan di suatu tempat?


PS: Saya tahu solusi cepat adalah dengan menghapus tanda kutip dalam PE, tetapi itu tidak menjawab pertanyaan saya, dan dapat menyebabkan hasil yang tidak diinginkan dengan string yang berisi karakter khusus.

oguz ismail
sumber
GNU bash, version 3.2.57(1)-release (x86_64-apple-darwin18)mencetak string kosong
William Pursell
GNU bash, version 4.4.12(1)-release (x86_64-pc-linux-gnu)cetakan "bar"
William Pursell
@ Willill diuji pada 4.4.20 dan 5.0.11 dan keduanya mencetak "bar"
oguz ismail
Ini tampaknya menjadi masalah dengan ekspansi secara umum. Di saya 4.4.12(3)-release, echo "${BASH##*"${BASH##*}"}"-> /bin/bash. Sementara echo "\${BASH##*"${BASH##*}"}"-> ${BASH##*}dan eval echo "\${BASH##*"${BASH##*}"}"-> kosong.
Jeff Y

Jawaban:

2

Ini bukan jawaban

Pertama saya berpikir bahwa ini adalah karena aturan glob khusus, tetapi pada akhirnya saya pikir ini adalah bug di bash. Empat contoh berikut ini akan memberi Anda perasaan mengapa saya percaya ini adalah 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

Kasus 1 dan kasus 3 berbeda dalam kutipan. Tapi parameter ekspansi formulir ${parameter##word}menggunakan aturan ekspansi pathname untuk diproses word. Jadi *foodan *"foo"memiliki perilaku yang identik sebagai tanda kutip ganda dalam ekspansi pathname bisa diabaikan kecuali mereka memeluk karakter pola khusus ( *, ?, ...). Ini terlihat pada contoh berikut:

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

Jadi jika ini masalahnya, mengapa Kasus 2 dan Kasus 4 harus berperilaku berbeda?

Kvantour
sumber
mengapa Kasus 2 dan Kasus 4 harus berperilaku berbeda? Tidak ada alasan, baik ${1+}dan ${1+""}memperluas ke string kosong, tetapi mereka tidak diperlakukan sebagaimana ${1##*}adanya (lihat edit terbaru saya). Jadi kita dapat menyimpulkan bahwa ini adalah bug, kan?
oguz ismail
1
@oguzismail Persis! Jika case 1 dan case 3 berperilaku identik, maka case 2 dan case 4 juga harus berperilaku identik.
kvantour