Khi tôi hiểu ý của bạn, tôi không tin rằng bất kỳ câu trả lời nào trong số này là đúng. eval
không cần thiết theo bất kỳ cách nào, bạn cũng không có nhu cầu thậm chí hai lần đánh giá các biến của mình.
Đó là sự thật, @Gilles đến rất gần, nhưng anh ta không giải quyết vấn đề có thể ghi đè các giá trị và cách sử dụng chúng nếu bạn cần chúng nhiều lần. Rốt cuộc, một mẫu nên được sử dụng nhiều lần, phải không?
Tôi nghĩ rằng đó là thứ tự mà bạn đánh giá chúng quan trọng hơn. Hãy xem xét những điều sau đây:
HÀNG ĐẦU
Tại đây bạn sẽ đặt một số giá trị mặc định và chuẩn bị in chúng khi được gọi ...
#!/bin/sh
_top_of_script_pr() (
IFS="$nl" ; set -f #only split at newlines and don't expand paths
printf %s\\n ${strings}
) 3<<-TEMPLATES
${nl=
}
${PLACE:="your mother's house"}
${EVENT:="the unspeakable."}
${ACTION:="heroin"}
${RESULT:="succeed."}
${strings:="
I went to ${PLACE} and saw ${EVENT}
If you do ${ACTION} you will ${RESULT}
"}
#END
TEMPLATES
Ở GIỮA
Đây là nơi bạn xác định các chức năng khác để gọi chức năng in của mình dựa trên kết quả của chúng ...
EVENT="Disney on Ice."
_more_important_function() { #...some logic...
[ $((1+one)) -ne 2 ] && ACTION="remedial mathematics"
_top_of_script_pr
}
_less_important_function() { #...more logic...
one=2
: "${ACTION:="calligraphy"}"
_top_of_script_pr
}
CHAI
Bạn đã có tất cả thiết lập ngay bây giờ, vì vậy đây là nơi bạn sẽ thực hiện và lấy kết quả của mình.
_less_important_function
: "${PLACE:="the cemetery"}"
_more_important_function
: "${RESULT:="regret it."}"
_less_important_function
CÁC KẾT QUẢ
Tôi sẽ đi vào lý do tại sao ngay lập tức, nhưng chạy ở trên tạo ra kết quả sau:
_less_important_function()'s
lần chạy đầu tiên:
Tôi đã đến nhà mẹ bạn và thấy Disney trên Ice.
Nếu bạn làm thư pháp bạn sẽ thành công.
sau đó _more_important_function():
Tôi đến nghĩa trang và thấy Disney trên Ice.
Nếu bạn làm toán khắc phục, bạn sẽ thành công.
_less_important_function()
lần nữa:
Tôi đến nghĩa trang và thấy Disney trên Ice.
Nếu bạn làm toán học khắc phục, bạn sẽ hối tiếc.
LÀM THẾ NÀO NÓ HOẠT ĐỘNG:
Tính năng chính ở đây là khái niệm conditional ${parameter} expansion.
Bạn chỉ có thể đặt biến thành giá trị nếu nó không được đặt hoặc null bằng cách sử dụng biểu mẫu:
${var_name
: =desired_value}
Nếu thay vào đó, bạn chỉ muốn đặt một biến không đặt, bạn sẽ bỏ qua các :colon
giá trị null và vẫn giữ nguyên.
TRÊN PHẠM VI:
Bạn có thể nhận thấy rằng trong ví dụ trên $PLACE
và $RESULT
được thay đổi khi được đặt qua parameter expansion
mặc dù _top_of_script_pr()
đã được gọi, có lẽ là đặt chúng khi nó chạy. Lý do công việc này _top_of_script_pr()
là một ( subshelled )
chức năng - Tôi đã đính kèm nó parens
thay vì { curly braces }
sử dụng cho các chức năng khác. Bởi vì nó được gọi trong một lớp con, mọi biến nó đặt locally scoped
và khi nó trở về vỏ mẹ, các giá trị đó sẽ biến mất.
Nhưng khi _more_important_function()
thiết lập $ACTION
thì globally scoped
nó ảnh hưởng đến _less_important_function()'s
đánh giá thứ hai $ACTION
vì chỉ _less_important_function()
thiết lập $ACTION
thông qua${parameter:=expansion}.
:VÔ GIÁ TRỊ
Và tại sao tôi sử dụng :colon?
Giếng hàng đầu , man
trang sẽ cho bạn biết rằng : does nothing, gracefully.
Bạn thấy, parameter expansion
chính xác là nó trông như thế nào - nó expands
có giá trị của ${parameter}.
Vì vậy, khi chúng ta đặt một biến với ${parameter:=expansion}
giá trị còn lại của chúng ta - cái vỏ sẽ cố gắng thực hiện nội tuyến. Nếu nó cố chạy, the cemetery
nó sẽ chỉ nhổ một số lỗi vào bạn. PLACE="${PLACE:="the cemetery"}"
sẽ tạo ra kết quả tương tự, nhưng nó cũng dư thừa trong trường hợp này và tôi thích vỏ đó: ${did:=nothing, gracefully}.
Nó cho phép bạn làm điều này:
echo ${var:=something or other}
echo $var
something or other
something or other
TẠI ĐÂY-TÀI LIỆU
Và nhân tiện - định nghĩa nội tuyến của biến null hoặc unset cũng là lý do tại sao các hoạt động sau:
<<HEREDOC echo $yo
${yo=yoyo}
HEREDOC
yoyo
Cách tốt nhất để nghĩ về một here-document
là một tệp thực tế được truyền đến một bộ mô tả tệp đầu vào. Ít nhiều đó là những gì chúng là, nhưng các vỏ khác nhau thực hiện chúng hơi khác nhau.
Trong mọi trường hợp, nếu bạn không trích dẫn, <<LIMITER
bạn sẽ truyền nó và đánh giá vì expansion.
vậy việc khai báo một biến trong một here-document
có thể hoạt động, nhưng chỉ thông qua expansion
đó giới hạn bạn chỉ đặt các biến chưa được đặt. Tuy nhiên, điều đó hoàn toàn phù hợp với nhu cầu của bạn như bạn đã mô tả về chúng, vì các giá trị mặc định của bạn sẽ luôn được đặt khi bạn gọi chức năng in mẫu của mình.
TẠI SAO KHÔNG eval?
Chà, ví dụ tôi đã trình bày cung cấp một phương tiện chấp nhận an toàn và hiệu quả parameters.
Bởi vì nó xử lý phạm vi, mọi biến trong tập hợp thông qua ${parameter:=expansion}
đều có thể xác định được từ bên ngoài. Vì vậy, nếu bạn đặt tất cả điều này trong một tập lệnh có tên template_pr.sh và chạy:
% RESULT=something_else template_pr.sh
Bạn sẽ nhận được:
Tôi đã đến nhà mẹ bạn và thấy Disney trên Ice
Nếu bạn làm thư pháp, bạn sẽ làm gì đó
Tôi đã đến nghĩa trang và thấy Disney trên Ice
Nếu bạn làm toán học khắc phục, bạn sẽ có một cái gì đó
Tôi đã đến nghĩa trang và thấy Disney trên Ice
Nếu bạn làm toán học khắc phục, bạn sẽ có một cái gì đó
Điều này sẽ không hoạt động đối với các biến được đặt theo đúng nghĩa đen trong tập lệnh, chẳng hạn như $EVENT, $ACTION,
và $one,
tôi chỉ xác định các biến đó theo cách đó để chứng minh sự khác biệt.
Trong mọi trường hợp, việc chấp nhận đầu vào không xác định vào một evaled
câu lệnh vốn đã không an toàn, trong khi đó parameter expansion
được thiết kế đặc biệt để thực hiện nó.