Một cách tốt để làm việc eval
là thay thế nó echo
để thử nghiệm. echo
và eval
hoạt động tương tự (nếu chúng ta dành riêng phần \x
mở rộng được thực hiện bởi một số echo
triển khai như bash
trong một số điều kiện).
Cả hai lệnh tham gia đối số của chúng với một khoảng trắng ở giữa. Sự khác biệt là echo
hiển thị kết quả trong khi eval
đánh giá / diễn giải dưới dạng mã vỏ kết quả.
Vì vậy, để xem mã shell nào
eval $(echo $var_name=$var_value)
sẽ đánh giá, bạn có thể chạy:
$ echo $(echo $var_name=$var_value)
fruit=blue orange
Đó không phải là những gì bạn muốn, những gì bạn muốn là:
fruit=$var_value
Ngoài ra, sử dụng $(echo ...)
ở đây không có ý nghĩa.
Để xuất ra ở trên, bạn sẽ chạy:
$ echo "$var_name=\$var_value"
fruit=$var_value
Vì vậy, để giải thích nó, đó chỉ đơn giản là:
eval "$var_name=\$var_value"
Lưu ý rằng nó cũng có thể được sử dụng để đặt các thành phần mảng riêng lẻ:
var_name='myarray[23]'
var_value='something'
eval "$var_name=\$var_value"
Như những người khác đã nói, nếu bạn không quan tâm mã của mình là bash
cụ thể, bạn có thể sử dụng declare
như:
declare "$var_name=$var_value"
Tuy nhiên lưu ý rằng nó có một số tác dụng phụ.
Nó giới hạn phạm vi của biến đối với chức năng nơi nó chạy. Vì vậy, bạn không thể sử dụng nó trong ví dụ như:
setvar() {
var_name=$1 var_value=$2
declare "$var_name=$var_value"
}
setvar foo bar
Bởi vì điều đó sẽ khai báo một foo
biến cục bộ để setvar
như vậy sẽ vô dụng.
bash-4.2
đã thêm một -g
tùy chọn declare
để khai báo một biến toàn cục, nhưng đó không phải là điều chúng ta muốn vì chúng ta setvar
sẽ đặt một biến toàn cục trái ngược với biến của người gọi nếu người gọi là một hàm, như trong:
setvar() {
var_name=$1 var_value=$2
declare -g "$var_name=$var_value"
}
foo() {
local myvar
setvar myvar 'some value'
echo "1: $myvar"
}
foo
echo "2: $myvar"
mà sẽ xuất ra:
1:
2: some value
Ngoài ra, lưu ý rằng trong khi declare
được gọi declare
(thực tế đã bash
mượn khái niệm từ typeset
nội dung của vỏ Korn ), nếu biến đã được đặt, declare
sẽ không khai báo một biến mới và cách thực hiện chuyển nhượng phụ thuộc vào loại biến.
Ví dụ:
varname=foo
varvalue='([PATH=1000]=something)'
declare "$varname=$varvalue"
sẽ tạo ra một kết quả khác (và có khả năng có tác dụng phụ khó chịu) nếu varname
trước đây được khai báo là mảng vô hướng , mảng hoặc mảng kết hợp .
eval
cách đó là sai. Bạn đang mở rộng$var_value
trước khi chuyển nó sangeval
điều đó có nghĩa là nó sẽ được hiểu là mã shell! (thử ví dụ vớivar_value="';:(){ :|:&};:'"
)