2012-03-30 27 views
22

vẻ như là cách khuyến khích làm bối cảnh biến gián tiếp trong bash là sử dụng eval:gián tiếp phân công biến trong bash

var=x; val=foo 
eval $var=$val 
echo $x # --> foo 

Vấn đề là thông thường một với eval:

var=x; val=1$'\n'pwd 
eval $var=$val # bad output here 

(và vì nó được khuyến khích ở nhiều nơi, tôi tự hỏi có bao nhiêu kịch bản dễ bị tổn thương vì điều này ...)

Trong mọi trường hợp, giải pháp rõ ràng của usin g (thoát) dấu ngoặc kép không thực sự làm việc:

var=x; val=1\"$'\n'pwd\" 
eval $var=\"$val\" # fail with the above 

Vấn đề là bash đã gián tiếp biến tham chiếu nướng trong (với ${!foo}), nhưng tôi không thấy bất kỳ cách như vậy để làm nhiệm vụ gián tiếp - là có cách nào lành mạnh để làm điều này?

Đối với hồ sơ, tôi đã tìm thấy một giải pháp, nhưng điều này không phải là điều mà tôi muốn xem xét "lành mạnh" ...:

eval "$var='"${val//\'/\'\"\'\"\'}"'" 

Trả lời

2

Điểm chính được rằng cách khuyến khích để làm điều này là:

eval "$var=\$val" 

với RHS thực hiện gián tiếp quá. Vì eval được sử dụng trong cùng một môi trường , nó sẽ bị ràng buộc $val, do đó trì hoãn nó hoạt động và kể từ bây giờ nó chỉ là một biến. Kể từ khi biến $val có một cái tên được biết đến, không có vấn đề với trích dẫn, và nó có thể thậm chí được viết như sau:

eval $var=\$val 

Nhưng vì nó tốt hơn để luôn luôn thêm dấu ngoặc kép, cựu là tốt hơn, hoặc thậm chí này:

eval "$var=\"\$val\"" 

Một lựa chọn tốt hơn trong bash đã được đề cập cho toàn bộ điều đó tránh eval hoàn toàn (và không phải là tinh tế như declare vv):

printf -v "$var" "%s" "$val" 

Mặc dù đây không phải là một câu trả lời trực tiếp những gì tôi ban đầu hỏi ...

13
eval "$var=\$val" 

Đối số cho eval nên luôn là một đơn chuỗi được đính kèm trong dấu nháy đơn hoặc kép. Tất cả mã bị lệch khỏi mẫu này có một số hành vi không mong muốn trong các trường hợp cạnh, chẳng hạn như tên tệp có ký tự đặc biệt.

Khi đối số để eval được mở rộng bởi vỏ, thì $var được thay thế bằng tên biến và \$ được thay thế bằng một đồng đô la đơn giản. Chuỗi được đánh giá do đó sẽ trở thành:

varname=$value 

Đây chính xác là những gì bạn muốn.

Thông thường, tất cả các biểu thức có dạng $varname phải được đặt trong dấu ngoặc kép. Chỉ có hai nơi có thể bỏ qua các dấu ngoặc kép: các bài tập biến và case. Vì đây là một phép gán biến, các dấu ngoặc kép không cần thiết ở đây. Họ không bị tổn thương, tuy nhiên, vì vậy bạn cũng có thể viết mã gốc như:

eval "$var=\"the value is $val\"" 
+0

Các gián tiếp trên RHS không phải là những gì tôi đang tìm kiếm. –

+1

(* trán-slap *) Bah, tôi đã hoàn toàn bỏ lỡ lý do tại sao tôi * muốn * muốn có sự đồng cảm trên RHS. Vì câu trả lời của bạn không nói về nó chút nào, tôi sẽ chỉnh sửa nó ngay bây giờ, thay vì tự trả lời ... –

+0

Tuyệt vời! Trong quá khứ tôi đã làm một số phức tạp 'eval eval export' vô nghĩa. Cảm ơn bạn đã bao giờ rất nhiều. Đối với các googlers, đi với câu trả lời ở trên, không phải là định dạng xuất eval eval. – bgStack15

24

Một cách tốt hơn một chút, tránh những tác động bảo mật tiềm ẩn của việc sử dụng eval, là

declare $var="$val" 

Lưu ý rằng declare là một từ đồng nghĩa với typeset trong bash. Lệnh typeset được hỗ trợ rộng rãi hơn (kshzsh cũng sử dụng nó):

typeset $var="$val" 
+0

Điều này có vẻ không di động đối với vỏ nhỏ hơn bash – MarcH

+0

Thật vậy; trong khi 'declare' là một phần mở rộng của tiêu chuẩn POSIX, nó cũng chỉ là một từ đồng nghĩa cho' typeset', mà * được * hỗ trợ bởi các shell chính khác ('ksh' và' zsh', cụ thể là). Các shell không hỗ trợ cái gì đó tương tự phải sử dụng 'eval' cẩn thận. – chepner

+3

'eval '$ var =' $ val '" 'gần như không đủ cẩn thận: Nếu nội dung chứa các dấu nháy đơn bằng chữ, chúng có thể dễ dàng thoát ra. –

14

Bash có phần mở rộng để printf đó lưu kết quả của nó vào một biến:

printf -v "${VARNAME}" '%s' "${VALUE}" 

Điều này ngăn cản tất cả các vấn đề thoát càng tốt .

Nếu bạn sử dụng một định danh hợp lệ cho $VARNAME, lệnh sẽ thất bại và trở về mã trạng thái 2:

$ printf -v ';;;' foobar; echo $? 
bash: printf: `;;;': not a valid identifier 
2 
Các vấn đề liên quan