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
exportsẽ 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
$TESTtrước khi dòng lệnh được thực thi. Khi echođang chạy (cũng lưu ý rằng echothườ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 $TESTkhông cho biết echođể xuất nội dung của biến TESTtừ môi trường của nó. Nó bảo shell chạy echovớ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 -clớ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=valuechuỗi đến môi trường mà tiếng vang nhận được. Tuy nhiên, echokhô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 shlệnh và shthự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 varbiến môi trường shnhận được sẽ được chuyển đổi thành $varbiến và khi nó mở rộng nó trong echodò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, echocũng sẽ nhận được var=valuetrong môi trường của nó (hoặc nếu nó được thực thi), nhưng một lần nữa, echokhô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/ kshthi đua):
var=value command eval 'echo "1: $var"'; echo "2: $var"
(sử dụng commandtrướ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 $TESTnguyên nhân echođể tìm nạp TESTvar 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 123Nó 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 TESTvà ghi đè lên nó bằng 456; dòng lệnh bây giờ
echo 123Nó 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
>>
printenvhữ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.