Mở rộng tham số dẫn đến chuỗi rỗng được xử lý khác nhau


10

Cập nhật

Một số người trong danh sách gửi thư của bug-bash đã xác nhận đây là một lỗi.


Nếu bất cứ ai quan tâm, một bản sửa lỗi có sẵn trong cam kết mới nhất cho chi nhánh phát triển .


Trong khi

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

in một dòng trống,

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

bản in bar.

Tôi không hiểu điều này. ${1##*}mở rộng thành một chuỗi rỗng, do đó, "${1##*}"nên được xử lý như vậy "", nhưng có vẻ như bash không nghĩ như vậy.

Dường như có một sự đồng thuận về điều này trong số các shtriển khai phổ biến khác :

$ 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 (có hoặc không có --posix) là người duy nhất không tuân thủ điều đó:

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

Và không có xử lý chuỗi con, hành vi như mong đợi:

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

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

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

$ 

Tôi thực sự tự hỏi nếu có một lời giải thích cho điều này, mà tôi không thể tìm thấy trong hướng dẫn. Đây có phải là một lỗi, hoặc giải thích sai về tiêu chuẩn? Là hành vi này được ghi nhận ở đâu đó?


Tái bút: Tôi biết một cách giải quyết nhanh là bỏ qua PE bên trong, nhưng điều đó không trả lời câu hỏi của tôi và có thể dẫn đến kết quả không mong muốn với các chuỗi chứa các ký tự đặc biệt.


GNU bash, version 3.2.57(1)-release (x86_64-apple-darwin18)in một chuỗi trống
William Pursell

GNU bash, version 4.4.12(1)-release (x86_64-pc-linux-gnu)in "thanh"
William Pursell

@William đã thử nghiệm vào ngày 4.4.20 và 5.0.11 và cả in "thanh"
oguz ismail

Điều này dường như là một vấn đề với việc mở rộng nói chung. Trong tôi 4.4.12(3)-release, echo "${BASH##*"${BASH##*}"}"-> /bin/bash. Trong khi echo "\${BASH##*"${BASH##*}"}"-> ${BASH##*}eval echo "\${BASH##*"${BASH##*}"}"-> để trống.
Jeff Y

Câu trả lời:


2

Đây không phải là một câu trả lời

Đầu tiên tôi đã nghĩ rằng điều này là do các quy tắc toàn cầu đặc biệt, nhưng cuối cùng tôi nghĩ rằng đây là một lỗi trong bash. Bốn ví dụ sau đây sẽ cho bạn cảm giác tại sao tôi tin rằng đây là một lỗi:

$ 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

Trường hợp 1 và trường hợp 3 khác nhau trong dấu ngoặc kép. Nhưng mở rộng tham số của biểu mẫu ${parameter##word}sử dụng quy tắc mở rộng tên đường dẫn để xử lý word. Vì vậy, *foo*"foo"có hành vi giống hệt như hai dấu ngoặc kép trong việc mở rộng tên đường dẫn có thể được bỏ qua trừ khi họ nắm lấy nhân vật mô hình đặc biệt ( *, ?, ...). Điều này được thấy trong ví dụ sau:

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

Vậy nếu đây là trường hợp, tại sao Trường hợp 2 và Trường hợp 4 phải hành xử khác nhau?


Tại sao Trường hợp 2 và Trường hợp 4 hành xử khác nhau? Không có lý do, cả hai ${1+}${1+""}mở rộng thành chuỗi rỗng, nhưng chúng không được xử lý theo cách ${1##*}này (xem bản chỉnh sửa mới nhất của tôi). Vì vậy, chúng ta có thể suy luận đây là một lỗi, phải không?
oguz ismail

1
@oguzismail Chính xác! Nếu trường hợp 1 và trường hợp 3 hành xử giống hệt nhau, thì trường hợp 2 và trường hợp 4 cũng nên cư xử giống hệt nhau.
kaugeour
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.