Khi nào `_` là biến môi trường của bash shell?


10

Bash Manual nói (manpage, nhấn mạnh của tôi):

Khi Bash gọi một lệnh bên ngoài, biến $_được đặt thành tên đường dẫn đầy đủ của lệnh và được truyền cho lệnh đó trong môi trường của nó.

Và ( Thông số đặc biệt ):

_

( $_, một dấu gạch dưới.) Khi khởi động shell, được đặt thành tên đường dẫn tuyệt đối được sử dụng để gọi tập lệnh shell hoặc shell đang được thực thi như được truyền trong môi trường hoặc danh sách đối số. Sau đó, mở rộng đến đối số cuối cùng cho lệnh trước đó, sau khi mở rộng. Cũng được đặt thành tên đường dẫn đầy đủ được sử dụng để gọi từng lệnh được thực thi và được đặt trong môi trường được xuất sang lệnh đó. Khi kiểm tra thư, tham số này giữ tên của tệp thư.

  1. Trong một bash shell, tôi chạy:

    $ bash
    $ export | grep '_=' 
    

    Theo hướng dẫn, _nên là một biến môi trường của vỏ bash mới. exportđược cho là xuất tất cả các biến môi trường của shell bash mới, nhưng nó không xuất ra _. Vì vậy, tôi tự hỏi liệu _một biến môi trường của vỏ bash mới?

  2. Trên thực tế trong bất kỳ bash shell, điều tương tự xảy ra

    $ export | grep '_='

    không đầu ra bất cứ điều gì. Vì vậy, tôi tự hỏi nếu _bao giờ là một biến môi trường của một vỏ bash?

  3. Để so sánh:

    $ dash
    $ export  | grep '_='        
    export _='/bin/dash'
    

Bài viết của tôi được lấy cảm hứng từ bình luận của Miketrả lời của Stephane .


1
Đó là một biến shell và nó được truyền vào môi trường của lệnh ; nó không nhất thiết phải xuất khẩu sang môi trường của vỏ . exportlà một nội trang, nhưng nếu bạn sử dụng printenv _, nó sẽ cho bạn thấy nó đã được gọi như thế nào: /usr/bin/printenvtrên hệ thống này.
Toby Speight

Lưu ý rằng bash -c export | grep _=(từ Bash), sẽ hiển thị cách shell cha gọi bashlệnh, mặc dù $_không được đặt trong cha.
Toby Speight

Câu trả lời:


13

Vâng, _là một biến môi trường của vỏ Bash mới; bạn có thể thấy điều đó bằng cách chạy

tr '\0' '\n' < /proc/$$/environ | grep _=

bên trong vỏ: cho thấy nội dung của môi trường ban đầu của vỏ. Bạn sẽ không nhìn thấy nó trong lớp vỏ đầu tiên bởi vì không có lớp vỏ trước để đặt nó trước khi nó bắt đầu.

Mở rộng $_bên trong Bash đề cập đến _tham số đặc biệt, mở rộng đến đối số cuối cùng của lệnh trước đó. (Bên trong Bash xử lý điều này bằng cách sử dụng một _biến vỏ, được cập nhật mỗi khi một lệnh được phân tích cú pháp, nhưng đó thực sự là một chi tiết thực hiện. Đó là “unexported” mỗi khi một lệnh được phân tách. ) exportKhông hiển thị _bởi vì nó không phải là một biến được đánh dấu là xuất khẩu; tuy nhiên bạn có thể thấy nó trong đầu ra của set.

Trong ví dụ đầu tiên, shell Bash mới phân tích cú pháp và thực thi các lệnh trong các tệp khởi động của nó, vì vậy khi chạy explore | grep '-=', _đã bị ghi đè và được đánh dấu là không xuất.

Trong dashví dụ này, nó dường như không thực thi bất kỳ tệp khởi động nào, vì vậy bạn đang xem biến là biến môi trường được Bash đặt trước khi chạy dash.


Cảm ơn. Trong bash shell mới, tại sao không export | grep '_='xuất ra bất cứ thứ gì? Trong bash shell ban đầu, tại sao không tr '\0' '\n' < /proc/$$/environ | grep _=xuất ra bất cứ thứ gì?
Tim


9

exportkhông có đối số liệt kê tất cả các biến được xuất . _không phải là một biến, nhưng được liệt kê như một tham số đặc biệt .

Hơi khó hiểu, _cũng sẽ là một tên hợp lệ cho một biến , không giống như tên của các tham số đặc biệt khác. Ít nhất Bash 4.4 cho phép gán cho nó, mà không có khiếu nại. Nó chỉ không hữu ích vì hiệu ứng đặc biệt ngay lập tức ghi đè giá trị.


2
Hãy vui vẻ cố gắng sử dụng _như một biến mặc dù ;-). Nó thực sự chỉ ghi và giá trị bị mất ngay lập tức.
Stephen Kitt

1
Ngoài ra, Bash bên trong coi _như một biến, đó là lý do tại sao nó xuất hiện trong đầu ra của set. Tuy nhiên, nó không thể được đánh dấu là xuất khẩu theo như tôi có thể xác định.
Stephen Kitt

2
@StephenKitt, nhưng Bash 4.4 cho phép đánh dấu nó chỉ đọc. Hoặc một số nguyên. Với kết quả có phần vui nhộn.
ilkkachu

1
Ha, tìm thấy tốt đẹp, đó là thú vị!
Stephen Kitt

5

Không phải tất cả các biến shell es được đánh dấu là xuất như bạn có thể thấy trong đầu ra của declare -p.

Nó không có ý nghĩa gì bashđể đánh dấu $_là xuất vì nó tự động thêm biến này vào môi trường của các tiến trình con nhưng có giá trị khác với giá trị mà nó có trong trình bao (tại thời điểm đó).

Hiển thị nó dưới dạng xuất sẽ khiến người dùng nhầm lẫn về những gì sẽ xảy ra với môi trường của các lệnh bên ngoài.

Tất cả các "biến thời gian chạy" BASH*không được xuất.

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.