Tham chiếu các biến trong tập lệnh shell


10

Trong tập lệnh shell, nếu tôi xác định một biến như FOO=25, có sự khác biệt nào giữa việc tham chiếu nó là $FOO$${FOO}$không?


2
Bạn không được sử dụng $cuối cùng! Nó sẽ được coi là ký tự bình thường và không phải là một phần của tên biến.
Chỉ huy Byte

Câu trả lời:


16

Trong hầu hết các tình huống cả hai $var${var}đều giống nhau. (Lưu ý rằng bạn không được sử dụng $cuối cùng!)

Một ví dụ mà bạn cần niềng răng xoăn là khi bạn cần đặt một biến trong một chuỗi liên tục.

Thí dụ:

var=hel
echo ${var}lo

sẽ đầu ra hello.


11

Để trả lời câu hỏi chính của bạn, ${foo}được gọi là "mở rộng tham số" . Nói chính xác, $chính nó bắt đầu mở rộng tham số, { }thực sự là tùy chọn theo đặc tả POSIX , nhưng có thể hữu ích để chỉ ra phần cuối của tên biến:

$ foo="bar"
$ echo $fooBaz   ## fails, no variable named $fooBaz exists

$ echo ${foo}Baz ## works, $foo is expanded and the string Baz is appended
barBaz

Về cơ bản, $foo${foo}giống hệt nhau. Ngoài các trường hợp như trên hoặc khi bạn đang thực hiện thao tác chuỗi , chúng hoàn toàn tương đương.

Tuy nhiên, bạn không nên thực sự sử dụng một trong số chúng. Nguyên tắc chung là, với rất ít ngoại lệ, bạn nên luôn luôn sử dụng "$foo"hoặc "${foo}"và không bao giờ $foohoặc ${foo}. Bạn phải luôn trích dẫn các biến của mình để tránh gọi toán tử split + global (sẽ nói thêm về điều đó sau). Bạn chắc chắn không muốn $foo$. Trận chung kết $là không liên quan:

$ foo="bar"
$ echo "$foo$"
bar$

Vì vậy, trong khi các biến không được trích dẫn đôi khi vẫn ổn:

$ echo $foo
bar

Chúng thường không và thực sự nên tránh:

$ if [ -n $foo ]; then echo empty; else echo "not empty"; fi ## fails
empty

$ if [ -n "$foo" ]; then echo empty; else echo "not empty"; fi ## works
not empty

Lưu ý rằng dấu ngoặc cũng không giúp được gì ở đây:

$ if [ -n ${foo} ]; then echo empty; else echo "not empty"; fi  ## fails
empty

$ if [ -n "${foo}" ]; then echo empty; else echo "not empty"; fi ## works
not empty

Khi bạn sử dụng $foohoặc ${foo}, shell sẽ phân chia giá trị được lưu trong biến trên khoảng trắng (điều này có thể được thay đổi bằng cách đặt IFSbiến thành một thứ khác) thành một danh sách và sau đó, mỗi phần tử của danh sách được coi là một mẫu hình cầu và được mở rộng thành bất kỳ tập tin hoặc thư mục phù hợp. Điều này được gọi là toán tử chia + toàn cầu . Để minh họa, hãy xem xét một thư mục có hai tệp:

$ ls -l
-rw-r--r-- 1 terdon terdon 0 Oct  9 18:16 file1
-rw-r--r-- 1 terdon terdon 0 Oct  9 18:16 file2

Bây giờ, hãy đặt một biến thành foo *:

$ foo="foo *"

Điều gì xảy ra nếu chúng ta cố gắng kiểm tra xem một tệp có tên đó tồn tại không?

$ if [ -e $foo ]; then echo "file exists"; else echo "no such file"; fi
file exists

Biến được chia thành foo*, vì *là ký tự đại diện khớp với bất kỳ chuỗi nào, trình bao cho bạn biết rằng một tệp có tên là foo *exxists. Tuy nhiên, nếu chúng tôi trích dẫn chính xác, điều này sẽ không xảy ra:

$ if [ -e "$foo" ]; then echo "file exists"; else echo "no such file"; fi
no such file

Đó là một ví dụ tầm thường để minh họa điểm. Hãy tưởng tượng nếu tôi đã sử dụng rmthay vì echomặc dù.

Vì vậy, quy tắc đầu tiên: luôn luôn trích dẫn các biến của bạn. Bạn có thể sử dụng một trong hai "$foo"hoặc "${foo}"nhưng trích dẫn một trong hai cách. Để biết thêm chi tiết về việc sử dụng các biến một cách an toàn, hãy xem các bài đăng sau:


Tôi không muốn chỉnh sửa câu trả lời xuất sắc của bạn, nhưng không $ var="foo *"nên $ foo="foo *"? Bạn không sử dụng varbất cứ nơi nào.
Joe

@Joe oh, đau buồn quá! Vâng, tất nhiên nó nên, cảm ơn vì đã chỉ ra nó. Nhân tiện, hãy sửa chữa những lỗi đó bằng cách đề xuất một chỉnh sửa. Điều đó được khuyến khích rất nhiều, chính xác là để tránh những lỗi ngớ ngẩn như thế này.
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.