giá trị tạm thời của bash script


11

Giống như lệnh dưới đây,

if true; then
   IFS=":" read a b c d e f <<< "$test"

Cuốn sách cho biết khi lệnh gán giá trị ( IFS ":") được sử dụng trước lệnh chính ( read a b c d e f <<< "$value"), giá trị của nó tạm thời có hiệu lực trên lệnh chính. Vì vậy, readlệnh sử dụng dấu phân cách :.

Nhưng, giống như lệnh này,

if true; then
   HOME="hello" echo "$HOME"

Tin nhắn Echo không phải là xin chào. Ý nghĩa thực sự của lệnh trên là gì?

Câu trả lời:


5

Điều này dẫn đến một câu hỏi về cách đánh giá hoạt động. Cả hai ví dụ đều hoạt động theo cùng một cách, vấn đề xảy ra do cách shell (bash, ở đây) mở rộng các biến.

Khi bạn viết lệnh này:

HOME="foo" echo $HOME

Các $HOMEđược mở rộng trước khi lệnh được chạy . Do đó, nó được mở rộng thành giá trị ban đầu chứ không phải giá trị mới mà bạn đã đặt cho lệnh. Các HOMEbiến đã thực sự được thay đổi trong môi trường mà các echolệnh đang chạy trong, tuy nhiên, bạn đang in $HOMEtừ công ty mẹ.

Để minh họa, hãy xem xét điều này:

$ HOME="foo" bash -c 'echo $HOME'
foo
$ echo $HOME
/home/terdon

Như bạn có thể thấy ở trên, lệnh đầu tiên in giá trị thay đổi tạm thời HOMEvà lệnh thứ hai in bản gốc, chứng minh rằng biến chỉ được thay đổi tạm thời. Bởi vì bash -c ...lệnh được đặt trong dấu ngoặc đơn ( ' ') thay vì dấu ngoặc kép ( ) " ", biến không được mở rộng và được chuyển như nguyên trạng của quy trình bash mới. Quá trình mới này sau đó mở rộng nó và in giá trị mới mà nó đã được đặt thành. Bạn có thể thấy điều này xảy ra nếu bạn sử dụng set -x:

$ set -x
$ HOME="hello" echo "$HOME"
+ HOME=hello         
+ echo hello
hello

Như bạn có thể thấy ở trên, biến $HOME không bao giờ được chuyển đến echo. Nó chỉ thấy giá trị mở rộng của nó. So sánh với:

$ HOME="hello" bash -c 'echo $HOME'
+ HOME=hello
+ bash -c 'echo $HOME'
hello

Ở đây, vì các dấu ngoặc đơn, biến và không phải giá trị của nó được chuyển sang quy trình mới.


7

Khi shell đang phân tích cú pháp một dòng, nó sẽ mã hóa dòng thành các từ, thực hiện các mở rộng khác nhau (theo thứ tự) trên các từ, sau đó thực hiện lệnh.

Giả sử test=1:2:3:4:5:6

Hãy xem lệnh này: IFS=":" read a b c d e f <<< "$test"

Sau khi mã thông báomở rộng tham số xảy ra:IFS=":" read a b c d e f <<< "1:2:3:4:5:6"

Shell sẽ đặt biến IFS trong khoảng thời gian của lệnh đọc và readbiết cách áp dụng $ IFS cho đầu vào của nó và đưa ra các giá trị cho các tên biến.

Lệnh này có một câu chuyện tương tự, nhưng kết quả khác nhau: HOME="hello" echo "$HOME"

Vì việc mở rộng tham số xảy ra trước khi lệnh bắt đầu, shell có:

HOME="hello" echo "/home/username"

Và sau đó, trong quá trình thực thi lệnh echo, giá trị mới của $ HOME hoàn toàn không được sử dụng.

Để đạt được những gì bạn đang cố gắng làm, hãy chọn một trong

# Delay expansion of the variable until its new value is set
HOME="hello" eval 'echo "$HOME"'

hoặc là

# Using a subshell, so the altered env variable does not affect the parent.
# The semicolon means that the variable assignment will occur before
# the variable expansion
(HOME="hello"; echo "$HOME")

nhưng đừng chọn cái đầu tiên


Có lẽ tốt hơn để chọn cái đầu tiên. Ít nhất là nó nhanh hơn đáng kể. Khi eval là câu trả lời, đôi khi bạn có thể hỏi sai câu hỏi. Nhưng nếu ai đó phải làm điều đó vì một số lý do, việc thay đổi câu trả lời sẽ không làm cho câu hỏi trở nên ít sai hơn. Một giải pháp khác là bọc nó trong một chức năng và sử dụng local.
dùng23013

Tại sao nên evaltránh giải pháp?
DarkHeart

Nếu bạn không kiểm soát chặt chẽ đầu vào, bạn phải rất cẩn thận về mã bạn cho phép người khác tiêm vào chương trình của bạn.
glenn jackman

-1

Có hai phạm vi: biến môi trường và biến cục bộ. Các biến môi trường có giá trị cho mọi quá trình (xem setenv, getenv), trong khi các biến cục bộ chỉ hoạt động trong phiên shell này. (Đây không phải là một sự phân biệt rõ ràng ...)

Implied env(như trong ví dụ của bạn) sửa đổi môi trường, trong khi echo ...sử dụng các môi trường cục bộ - vì vậy envkhông có hiệu lực.

Để sửa đổi các biến cục bộ sử dụng, giả sử,

( HOME="foo" ; echo "$HOME" )

Ở đây các dấu ngoặc đơn xác định phạm vi của nhiệm vụ này.


1
Điều này không liên quan gì đến phạm vi biến, vấn đề là biến đang được mở rộng trước khi nó được chuyển sang shell con.
terdon
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.