Mở rộng gián tiếp là gì? $ {! Var *} có nghĩa là gì?


85

Tôi đang đọc " Hướng dẫn Bash cho người mới bắt đầu ". Nó nói rằng:

Nếu ký tự đầu tiên của PARAMETERlà dấu chấm than, Bash sử dụng giá trị của biến được hình thành từ phần còn lại PARAMETERlàm tên của biến; biến này sau đó được mở rộng và giá trị đó được sử dụng trong phần thay thế còn lại, thay vì giá trị của PARAMETERchính nó. Đây được gọi là mở rộng gián tiếp.

Ví dụ được đưa ra là:

franky ~> echo ${!N*}
NNTPPORT NNTPSERVER NPX_PLUGIN_PATH

Tôi không hiểu lắm ở đây:

giá trị của biến được hình thành từ phần còn lại của PARAMETER

Như PARAMETERchỉ là !N*, sau đó

phần còn lại của PARAMETER

chỉ là N*. Làm thế nào điều này có thể tạo thành một biến? Bash đã tìm kiếm tất cả các lệnh có thể có ở đó?

Câu trả lời:


110

Nếu bạn đọc bashtrang người đàn ông, về cơ bản nó xác nhận những gì bạn đã nêu:

Nếu ký tự đầu tiên của tham số là dấu chấm than ( !), thì mức chuyển hướng biến được đưa vào. Bash sử dụng giá trị của biến được hình thành từ phần còn lại của tham số làm tên của biến; biến này sau đó được mở rộng và giá trị đó được sử dụng trong phần thay thế còn lại, thay vì giá trị của chính tham số. Đây được gọi là mở rộng gián tiếp.

Tuy nhiên, đọc tiếp từ đó:

Các ngoại lệ cho điều này là các phần mở rộng ${!prefix*}${!name[@]}được mô tả bên dưới.

${!prefix*}Tên phù hợp với tiền tố. Mở rộng đến tên của các biến có tên bắt đầu bằng tiền tố, được phân tách bằng ký tự đầu tiên của IFSbiến đặc biệt.

Nói cách khác, ví dụ cụ thể của bạn ${!N*}là một ngoại lệ đối với quy tắc bạn đã trích dẫn. Nó không , tuy nhiên, làm việc như được quảng cáo trong các trường hợp dự kiến, chẳng hạn như:

$ export xyzzy=plugh ; export plugh=cave

$ echo ${xyzzy}  # normal, xyzzy to plugh
plugh

$ echo ${!xyzzy} # indirection, xyzzy to plugh to cave
cave

1
Cảm ơn vì câu trả lời. Tôi càng đọc "Hướng dẫn bash cho người mới bắt đầu", tôi càng tự hỏi mình liệu tác giả có hiểu những gì cô ấy viết không.
LRDPRDX

23

Dường như có một ngoại lệ khi "hướng dẫn" đã cho kết thúc bằng a *, như ở đây. Trong trường hợp này, nó cung cấp cho tất cả các tên biến bắt đầu bằng phần bạn đã chỉ định ( Ntại đây). Bash có thể làm điều đó vì nó theo dõi các biến và biết những biến nào tồn tại.

Hướng dẫn thực sự là thế này:
Giả sử tôi có một biến $VARIABLEđược đặt thành 42và tôi có một biến khác $NAMEđược đặt thành VARIABLE. ${!NAME}sẽ cho tôi 42. Bạn sử dụng giá trị của một biến để cho bạn biết tên của biến khác:

$ NAME="VARIABLE"
$ VARIABLE=42
$ echo ${!NAME}
42

5
Chà, ai mà biết được câu trả lời về ý nghĩa của cuộc sống, vũ trụ và mọi thứ thật dễ dàng!
KomodoDave

3

Có, nó tìm kiếm tất cả các mở rộng có thể có của các biến sau!. Nếu bạn đã làm:

echo ${!NP*}

bạn sẽ nhận được duy nhất NPX_PLUGIN_PATH.

Hãy xem xét ví dụ sau:

:~> export myVar="hi"
:~> echo ${!my*}
    myVar
:~> export ${!my*}="bye"
:~> echo $myVar
    bye

các biến khác khớp với * của tôi cũng được đặt thành "tạm biệt" không?
Anthony

1
@Anthony Tôi đã thử và nếu ${!my*}mở rộng thành myA, myB, myA được xuất với giá trị hiện tại và myB được đặt thành "tạm biệt" và được xuất. Không hữu ích lắm.
GKFX

3

Bạn đã gặp phải một ngoại lệ trong xử lý hướng, trong đó nếu ký tự cuối cùng là ký tự cuối cùng *, tất cả các biến có tiền tố đã cho trước đó sẽ được trả về.


Vì vậy, ngoài *trường hợp, điều này có giống với ${${VAR}}?
chronospoon

1
@chronospoon,, ${${VAR}}có thể ghi ngắn gọn hơn ${$VAR}là không hợp pháp, vì $VARtrả về một chuỗi không thể theo sau $dấu; để sử dụng một chuỗi làm tên biến, bạn cần giới thiệu một cấp độ hướng dẫn (như được trích dẫn trong chính câu hỏi ban đầu), tức là bạn có thể sử dụng ${!VAR}, thực hiện chính xác những gì bạn mong đợi (sai nhưng dễ hiểu) ${$VAR}.
Enrico

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.