Nếu tôi chạy
export TEST=foo
echo $TEST
Nó xuất ra foo.
Nếu tôi chạy
TEST=foo echo $TEST
Nó không. Làm thế nào tôi có thể có được chức năng này mà không cần sử dụng xuất hoặc tập lệnh?
Nếu tôi chạy
export TEST=foo
echo $TEST
Nó xuất ra foo.
Nếu tôi chạy
TEST=foo echo $TEST
Nó không. Làm thế nào tôi có thể có được chức năng này mà không cần sử dụng xuất hoặc tập lệnh?
Câu trả lời:
Điều này là do shell mở rộng biến trong dòng lệnh trước khi nó thực sự chạy lệnh và tại thời điểm đó biến không tồn tại. Nếu bạn dùng
TEST=foo; echo $TEST
nó sẽ làm việc
export
sẽ làm cho biến xuất hiện trong môi trường của các lệnh được thực hiện sau đó (để biết cách thức hoạt động của bash này help export
). Nếu bạn chỉ cần biến xuất hiện trong môi trường của một lệnh, hãy sử dụng những gì bạn đã thử, tức là:
TEST=foo your-application
$TEST
trước khi dòng lệnh được thực thi. Khi echo
đang chạy (cũng lưu ý rằng echo
thường sẽ dịch sang lệnh tích hợp shell chứ không phải /bin/echo
) nó sẽ thấy biến được đặt trong môi trường của nó. Tuy nhiên, echo $TEST
không cho biết echo
để xuất nội dung của biến TEST
từ môi trường của nó. Nó bảo shell chạy echo
với đối số là bất cứ thứ gì hiện có trong biến được gọi TEST
- và đó là hai thứ rất khác nhau.
var=value sh -c 'echo "$var"'
?
"… $var …"
:) nhưng không nằm trong dấu ngoặc đơn (ví dụ '… $var …'
:). Vì echo "$var"
nằm trong dấu ngoặc đơn, toàn bộ chuỗi được chuyển sang trình bao ( sh -c
) mới mà không bị hiểu bởi lớp vỏ tương tác bên ngoài. Tiết (Cont'd)
sh -c
lớp vỏ con ( ) mới .
Tôi nghi ngờ bạn muốn có các biến shell để có phạm vi giới hạn, thay vì các biến môi trường. Biến môi trường là một danh sách các chuỗi được truyền cho các lệnh khi chúng được thực thi .
Trong
var=value echo whatever
Bạn đang truyền var=value
chuỗi đến môi trường mà tiếng vang nhận được. Tuy nhiên, echo
không làm bất cứ điều gì với danh sách môi trường của nó và dù sao trong hầu hết các shell, echo
được tích hợp và do đó không được thực thi .
Nếu bạn đã viết
var=value sh -c 'echo "$var"'
Đó sẽ là một vấn đề khác. Ở đây, chúng ta đang chuyển var=value
đến sh
lệnh và sh
thực sự sử dụng môi trường của nó. Shell chuyển đổi từng biến mà chúng nhận được từ môi trường của chúng thành biến shell, vì vậy var
biến môi trường sh
nhận được sẽ được chuyển đổi thành $var
biến và khi nó mở rộng nó trong echo
dòng lệnh đó, nó sẽ trở thành echo value
. Bởi vì môi trường theo mặc định được kế thừa, echo
cũng sẽ nhận được var=value
trong môi trường của nó (hoặc nếu nó được thực thi), nhưng một lần nữa, echo
không quan tâm đến môi trường.
Bây giờ, nếu như tôi nghi ngờ, điều bạn muốn là giới hạn phạm vi của các biến shell, có một số cách tiếp cận có thể.
Có thể di chuyển (Bourne và POSIX):
(var=value; echo "1: $var"); echo "2: $var"
(...) ở trên bắt đầu một lớp vỏ phụ (một quy trình shell mới trong hầu hết các shell), do đó, bất kỳ biến nào được khai báo ở đó sẽ chỉ ảnh hưởng đến lớp vỏ phụ đó, vì vậy tôi mong mã ở trên sẽ xuất ra "1: value" và "2:" hoặc "2: anything-var-was-set-to-before".
Với hầu hết các shell giống như Bourne, bạn có thể sử dụng các hàm và hàm dựng sẵn "cục bộ":
f() {
local var
var=value
echo "1: $var"
}
f
echo "2: $var"
Với zsh, bạn có thể sử dụng các hàm nội tuyến:
(){ local var=value; echo "1: $var"; }; echo "2: $var"
hoặc là:
function { local var=value; echo "1: $var"; }; echo "2: $var"
Với bash và zsh (nhưng không phải tro, pdksh hoặc AT & T ksh), thủ thuật này cũng hoạt động:
var=value eval 'echo "1: $var"'; echo "2: $var"
Một biến thể mà làm việc trong một vài vỏ hơn ( dash
, mksh
, yash
) nhưng không zsh
(trừ trường hợp trong sh
/ ksh
thi đua):
var=value command eval 'echo "1: $var"'; echo "2: $var"
(sử dụng command
trước một nội dung đặc biệt (ở đây eval
) trong các vỏ POSIX sẽ loại bỏ tính đặc biệt của chúng (ở đây, các phép gán biến trong số chúng vẫn có hiệu lực sau khi chúng quay trở lại))
Bạn đang làm điều đó một cách chính xác, nhưng cú pháp bash rất dễ hiểu sai: bạn có thể nghĩ rằng đó là echo $TEST
nguyên nhân echo
để tìm nạp TEST
var sau đó in nó, nhưng không. Vì vậy
export TEST=123
sau đó
TEST=456 echo $TEST
liên quan đến trình tự sau:
Shell phân tích toàn bộ dòng lệnh và thực hiện tất cả các thay thế biến, vì vậy dòng lệnh trở thành
TEST=456 echo 123
Nó tạo ra các lọ tạm thời được đặt trước lệnh, vì vậy nó lưu giá trị hiện tại của TEST
và ghi đè lên nó bằng 456; dòng lệnh bây giờ
echo 123
Nó thực thi lệnh còn lại, trong trường hợp này sẽ in 123 thành stdout (vì vậy lệnh shell vẫn không sử dụng giá trị tạm thời của TEST
)
Nó khôi phục giá trị của TEST
Sử dụng printenv thay vào đó, vì nó không liên quan đến việc thay thế biến:
>> export TEST=123
>> printenv TEST
123
>> TEST=456 printenv TEST
456
>> printenv TEST && TEST=456 printenv TEST && TEST=789 printenv TEST && printenv TEST
123
456
789
123
>>
printenv
hữu ích cho việc thử nghiệm / bằng chứng về khái niệm (hoạt động giống như một kịch bản, trái ngược với echo
)
Bạn có thể làm việc này bằng cách sử dụng:
TEST=foo && echo $TEST
TEST=foo
đang chạy như một câu lệnh riêng - nó không chỉ được đặt trong ngữ cảnh echo
.