Biến môi trường và thông số vị trí
Trước khi chúng ta bắt đầu thảo luận về $INTEGERloại biến, chúng ta cần hiểu chúng thực sự là gì và chúng khác với các biến môi trường như thế nào. Các biến như $INTEGERđược gọi là tham số vị trí. Điều này được mô tả trong tiêu chuẩn POSIX (Giao diện hệ điều hành di động), phần 2.1 (nhấn mạnh của tôi):
- Shell thực thi một hàm (xem Lệnh Định nghĩa Hàm), tích hợp sẵn (xem Tiện ích tích hợp đặc biệt), tệp thực thi hoặc tập lệnh, đặt tên của các đối số là tham số vị trí được đánh số từ 1 đến n và tên của lệnh (hoặc trong trường hợp hàm trong tập lệnh, tên của tập lệnh) làm tham số vị trí được đánh số 0 (xem Tìm kiếm và Thực thi lệnh).
Ngược lại, các biến như $HOMEvà $PATHlà biến môi trường. Định nghĩa của chúng được mô tả trong phần 8 của tiêu chuẩn :
Các biến môi trường được định nghĩa trong chương này ảnh hưởng đến hoạt động của nhiều tiện ích, chức năng và ứng dụng. Có các biến môi trường khác chỉ được quan tâm đến các tiện ích cụ thể. Các biến môi trường chỉ áp dụng cho một tiện ích duy nhất được xác định là một phần của mô tả tiện ích.
Chú ý mô tả của họ. Các tham số vị trí có nghĩa là xuất hiện trước một lệnh, tức là command positional_arg_1 positional_arg_2.... Chúng được cung cấp bởi người dùng để ra lệnh cho những gì cụ thể phải làm. Khi bạn làm như vậy echo 'Hello' 'World', nó sẽ in ra các chuỗi Hellovà Worldbởi vì đây là các tham số vị trí để echo- những thứ bạn muốn thao tác echo. Và echođược xây dựng sao cho nó hiểu các tham số vị trí là các chuỗi được in (trừ khi chúng là một trong những cờ tùy chọn như -n). Nếu bạn làm điều này với lệnh khác, nó có thể không hiểu gì HellovàWorldlà bởi vì có lẽ nó mong đợi một con số Lưu ý rằng các tham số vị trí không được "kế thừa" - một quy trình con không biết về các tham số vị trí của cha mẹ trừ khi được truyền rõ ràng cho quy trình con. Thường thì bạn thấy các tham số vị trí được truyền bằng các tập lệnh bao bọc - những tham số có thể kiểm tra phiên bản đã có của lệnh hoặc thêm tham số vị trí bổ sung vào lệnh thực sẽ được gọi.
Ngược lại, các biến môi trường có nghĩa là ảnh hưởng đến nhiều chương trình. Chúng là các biến môi trường , vì chúng được đặt bên ngoài chương trình (nhiều hơn về điều này bên dưới). Một số biến môi trường nhất định như HOMEhoặc PATHcó định dạng cụ thể, ý nghĩa cụ thể và chúng sẽ có nghĩa giống nhau cho từng chương trình. HOMEbiến sẽ có nghĩa tương tự với tiện ích bên ngoài như /usr/bin/findhoặc shell của bạn (và do đó là tập lệnh) - đó là thư mục chính của tên người dùng theo quy trình chạy. Lưu ý rằng các biến môi trường có thể được sử dụng để tính toán cho hành vi lệnh cụ thể, ví dụUIDbiến môi trường có thể được sử dụng để kiểm tra xem tập lệnh có chạy với quyền root hay không và phân nhánh cho các hành động cụ thể tương ứng. Các biến môi trường có thể kế thừa - các tiến trình con có được bản sao môi trường của cha mẹ. Xem thêm Nếu các quy trình kế thừa môi trường của cha mẹ, tại sao chúng ta cần xuất khẩu?
Nói tóm lại, sự khác biệt chính là các biến môi trường được đặt bên ngoài lệnh và không có nghĩa là thay đổi (thông thường), trong khi các tham số vị trí là những thứ được xử lý bởi lệnh và chúng thay đổi.
Không chỉ khái niệm vỏ
Điều tôi nhận thấy từ các bình luận là bạn đang trộn lẫn thiết bị đầu cuối và vỏ, và thực sự sẽ khuyên bạn nên đọc về các thiết bị đầu cuối thực sự mà trước đây là các thiết bị vật lý. Ngày nay, "thiết bị đầu cuối" mà chúng ta thường đề cập đến, cửa sổ có nền đen và văn bản màu xanh lá cây thực sự là một phần mềm, một quá trình. Terminal là một chương trình chạy shell, trong khi shell cũng là một chương trình nhưng là chương trình đọc những gì bạn nhập vào để thực thi (nghĩa là, nếu đó là shell tương tác; shell không tương tác là các tập lệnh và sh -c 'echo foo'kiểu gọi). Thêm về vỏ ở đây .
Đây là một sự khác biệt quan trọng, nhưng cũng quan trọng để nhận ra rằng thiết bị đầu cuối là một chương trình và do đó tuân thủ các quy tắc tương tự về môi trường và các tham số vị trí. gnome-terminalKhi bạn bắt đầu sẽ xem xét SHELLbiến môi trường của bạn và sinh ra lớp vỏ mặc định phù hợp cho bạn, trừ khi bạn chỉ định một số lệnh khác với -e. Giả sử tôi đã thay đổi shell mặc định của mình thành ksh - gnome-terminal sau đó sẽ sinh ra kshthay vì bash. Đó cũng là một ví dụ về cách môi trường được sử dụng bởi các chương trình. Nếu tôi nói rõ ràng gnome-terminalvới -eviệc chạy shell cụ thể - nó sẽ làm điều đó, nhưng nó sẽ không vĩnh viễn. Ngược lại, môi trường có nghĩa là hầu hết không thay đổi (nhiều hơn về sau).
Vì vậy, như bạn có thể thấy, các biến môi trường và vị trí là cả hai thuộc tính của một tiến trình / lệnh, không chỉ là shell. Khi nói đến shell script, chúng cũng tuân theo mô hình được thiết lập bởi ngôn ngữ lập trình C. Ví dụ như mainhàm C thường trông giống như
int main(int argc, char **argv)
, trong đó argcsố lượng đối số dòng lệnh và argvlà mảng tham số dòng lệnh hiệu quả, và sau đó có environchức năng (trên Linux đó man -e 7 environ) để truy cập vào những thứ như đường dẫn thư mục chính của người dùng, danh sách các thư mục PATHnơi chúng ta có thể tìm kiếm tệp thực thi, v.v. Các kịch bản Shell cũng được mô hình hóa theo cách tương tự. Trong thuật ngữ shell, chúng ta có các tham số vị trí $1, $2v.v., trong khi đó $#là số lượng tham số vị trí. Thế còn $0? Đó là tên của bản thực thi, một lần nữa cũng được mô hình hóa từ ngôn ngữ lập trình C - argv[0]sẽ là tên của C "thực thi" của bạn. Và điều này khá đúng với hầu hết các ngôn ngữ lập trình và viết kịch bản .
Shell tương tác và không tương tác
Một trong những điều tôi đã gợi ý là sự khác biệt giữa các vỏ tương tác và không tương tác . Lời nhắc nơi bạn nhập lệnh - tương tác, nó tương tác với người dùng. Ngược lại khi bạn có một tập lệnh shell hoặc bạn chạy bash -c''không tương tác.
Và đây là nơi phân biệt trở nên quan trọng. Shell mà bạn đã chạy là một tiến trình, được sinh ra với các tham số vị trí (đối với bashshell đăng nhập là một "... có ký tự đầu tiên của đối số 0 là - hoặc bắt đầu bằng tùy chọn --login." ( Tham khảo ) )
Ngược lại, các kịch bản và shell được khởi chạy với -ctùy chọn có thể tận dụng lợi thế $1và $2đối số. Ví dụ,
$ bash -c 'echo $1; stat $2' sh 'Hello World' /etc/passwd
Hello World
File: '/etc/passwd'
Size: 2913 Blocks: 8 IO Block: 4096 regular file
Device: 801h/2049d Inode: 6035604 Links: 1
Access: (0644/-rw-r--r--) Uid: ( 0/ root) Gid: ( 0/ root)
Access: 2017-08-12 14:48:37.125879962 -0600
Modify: 2017-08-12 14:48:37.125879962 -0600
Change: 2017-08-12 14:48:37.137879811 -0600
Birth: -
Lưu ý rằng tôi cũng đã sử dụng shở đó, bởi vì -ctùy chọn nhỏ là lấy tham số vị trí đầu tiên và gán cho nó $0, không giống như thường là một tên của chương trình.
Một điều quan trọng cần chú ý là các tham số vị trí là cái mà tôi gọi là "framable". Lưu ý cách thức, lần đầu tiên chúng tôi khởi chạy bashvới các tham số vị trí của riêng nó, nhưng các tham số vị trí đó đã trở thành tham số echovà stat. Và mỗi chương trình hiểu nó theo cách riêng của nó. Nếu chúng tôi đưa ra statmột chuỗi Hello Worldvà không có tệp nào Hello Worldthì nó sẽ tạo ra lỗi; bashcoi nó như một chuỗi đơn giản nhưng stathy vọng chuỗi đó là một tên tệp hiện có. Ngược lại, tất cả các chương trình sẽ đồng ý rằng biến môi trường HOMElà một thư mục (trừ khi lập trình viên mã hóa nó theo cách không hợp lý).
Chúng ta có thể loay hoay với các biến môi trường và các tham số vị trí không?
Về mặt kỹ thuật, chúng ta có thể loay hoay với cả hai, nhưng chúng ta không nên loay hoay với các biến môi trường, trong khi chúng ta thường phải cung cấp các tham số vị trí. Ví dụ, chúng ta có thể chạy các lệnh trong shell với việc thêm một biến:
$ hello=world bash -c 'echo $hello'
world
Chúng ta cũng có thể đặt các biến vào môi trường chỉ bằng cách sử dụng export variable=valuetừ trong shell hoặc script. Hoặc chúng ta có thể chạy một lệnh với môi trường hoàn toàn trống rỗng với env -c command arg1 arg2. Tuy nhiên, thông thường không nên loay hoay với môi trường, đặc biệt là sử dụng các biến chữ hoa hoặc ghi đè các biến môi trường hiện có. Lưu ý rằng mặc dù không phải là một tiêu chuẩn.
Đối với các tham số vị trí, cách đặt chúng là rõ ràng, chỉ cần thêm chúng vào lệnh, nhưng cũng có những cách để đặt chúng thông minh khác , cũng như thay đổi danh sách các tham số đó thông qua shiftlệnh.
Tóm lại, mục đích của hai điều này là khác nhau, và chúng tồn tại vì một lý do. Tôi hy vọng mọi người có được cái nhìn sâu sắc từ câu trả lời này, và thật vui khi đọc nó giống như tôi đã viết câu trả lời này.
Lưu ý về lệnh set
Các setlệnh, theo cư xử của nhãn hiệu như vậy (từ bash dẫn sử dụng, nhấn mạnh thêm):
Không có tùy chọn, tên và giá trị của từng biến shell được hiển thị theo định dạng có thể được sử dụng lại làm đầu vào để đặt hoặc đặt lại các biến hiện được đặt.
Nói cách khác, setxem xét các biến cụ thể cho shell, ví dụ, một số trong số đó xảy ra trong môi trường HOME. Bằng cách tương phản các lệnh như envvà printenvnhìn vào biến môi trường thực tế mà lệnh chạy. Xem thêm này .
export 3thể biến$3thành một biến môi trường. Bạn không thểunset 3; và bạn không thể gán$3giá trị mới bằng cách sử dụng3=val.