Ý tưởng cơ bản là VAR=VALUE some-command
thiết lập VAR
để VALUE
thực hiện some-command
khi nào some-command
là một lệnh bên ngoài và nó không được ưa thích hơn thế. Nếu bạn kết hợp trực giác này với một số kiến thức về cách thức hoạt động của một chiếc vỏ, bạn nên đưa ra câu trả lời đúng trong hầu hết các trường hợp. Tham chiếu POSIX là các lệnh đơn giản của Hồi giáo trong chương Chương trình ngôn ngữ lệnh Shell Shell .
Nếu some-command
là một lệnh bên ngoài , VAR=VALUE some-command
tương đương với env VAR=VALUE some-command
. VAR
được xuất trong môi trường some-command
và giá trị của nó (hoặc thiếu giá trị) trong vỏ không thay đổi.
Nếu some-command
là một hàm , thì VAR=VALUE some-command
tương đương với VAR=VALUE; some-command
, tức là phép gán vẫn giữ nguyên sau khi hàm đã trả về và biến không được xuất ra môi trường. Lý do cho điều đó liên quan đến thiết kế của vỏ Bourne (và sau đó là khả năng tương thích ngược): nó không có cơ sở để lưu và khôi phục các giá trị biến xung quanh việc thực thi hàm. Không xuất biến có ý nghĩa vì một hàm thực thi trong chính shell. Tuy nhiên, ksh (bao gồm cả ATT ksh93 và pdksh / mksh), bash và zsh thực hiện hành vi hữu ích hơn khi chỉ VAR
được đặt trong khi thực hiện chức năng (nó cũng được xuất). Trong ksh , điều này được thực hiện nếu hàm được xác định bằng cú pháp kshfunction NAME …
, không phải nếu nó được xác định với cú pháp tiêu chuẩn NAME ()
. Trong bash , điều này chỉ được thực hiện ở chế độ bash, không phải ở chế độ POSIX (khi chạy với POSIXLY_CORRECT=1
). Trong zsh , điều này được thực hiện nếu posix_builtins
tùy chọn không được đặt; tùy chọn này không được đặt theo mặc định mà được bật bởi emulate sh
hoặc emulate ksh
.
Nếu some-command
là một nội trang, hành vi phụ thuộc vào loại nội dung. Nội dung đặc biệt hoạt động giống như các chức năng. Các phần tử đặc biệt là những phần tử phải được triển khai bên trong lớp vỏ vì chúng ảnh hưởng đến lớp vỏ trạng thái (ví dụ: break
ảnh hưởng đến luồng điều khiển, cd
ảnh hưởng đến thư mục hiện tại, set
ảnh hưởng đến các tham số vị trí và các tùy chọn Vị trí). Các nội dung khác được tích hợp chỉ để thực hiện và thuận tiện (chủ yếu - ví dụ: tính năng bash printf -v
chỉ có thể được thực hiện bởi một nội dung) và chúng hoạt động như một lệnh bên ngoài.
Việc chuyển nhượng diễn ra sau khi mở rộng bí danh, vì vậy nếu some-command
là bí danh , trước tiên hãy mở rộng nó để tìm những gì xảy ra.
Lưu ý rằng trong mọi trường hợp, việc gán được thực hiện sau khi dòng lệnh được phân tích cú pháp, bao gồm mọi thay thế biến trên chính dòng lệnh. Vì vậy, var=a; var=b echo $var
in a
, bởi vì $var
được đánh giá trước khi chuyển nhượng diễn ra. Và do đó IFS=. printf "%s\n" $var
sử dụng IFS
giá trị cũ để phân chia $var
.
Tôi đã bao gồm tất cả các loại lệnh, nhưng có thêm một trường hợp: khi không có lệnh để thực thi , tức là nếu lệnh chỉ bao gồm các nhiệm vụ (và có thể là chuyển hướng). Trong trường hợp đó, nhiệm vụ vẫn được giữ nguyên . VAR=VALUE OTHERVAR=OTHERVALUE
tương đương với VAR=VALUE; OTHERVAR=OTHERVALUE
. Vì vậy, sau IFS=. arr=($var)
, IFS
vẫn được đặt thành .
. Vì bạn có thể sử dụng $IFS
trong chuyển nhượng arr
với kỳ vọng rằng nó đã có giá trị mới, nên có nghĩa là giá trị mới IFS
được sử dụng để mở rộng $var
.
Tóm lại, bạn chỉ có thể sử dụng IFS
để tách trường tạm thời :
- bằng cách bắt đầu một lớp vỏ mới hoặc một lớp con (ví dụ:
third=$(IFS=.; set -f; set -- $var; echo "$3")
một cách làm phức tạp third=${var#*.*.}
ngoại trừ việc chúng hành xử khác nhau khi giá trị var
chứa ít hơn hai .
ký tự);
- trong ksh, với
IFS=. some-function
vị trí some-function
được xác định bằng cú pháp ksh function some-function …
;
- trong bash và zsh,
IFS=. some-function
miễn là chúng hoạt động ở chế độ gốc trái ngược với chế độ tương thích.
IFS
vẫn được đặt thành.
" Eek. Sau khi đọc phần đầu tiên, điều đó có ý nghĩa, nhưng trước khi tôi đăng Q này, tôi sẽ không mong đợi điều đó.