Câu hỏi Làm thế nào để kiểm tra xem một biến được thiết lập trong Bash?


Làm cách nào để biết một biến được đặt trong Bash?

Ví dụ, làm thế nào để kiểm tra xem người dùng đã đưa tham số đầu tiên cho một hàm?

function a {
    # if $1 is set ?
}

1077
2017-08-30 14:54


gốc


if test $# -gt 0; then printf 'arg <%s>\n' "$@"; fi. - Jens
Lưu ý đối với người tìm kiếm giải pháp: Có nhiều câu trả lời được đánh giá cao cho câu hỏi này trả lời câu hỏi "là biến không trống". Các giải pháp sửa chữa nhiều hơn ("là tập hợp biến") được đề cập trong câu trả lời của Jens và Lionel dưới đây. - Nathan Kidd
Ngoài ra Russell Harmon và Seamus là chính xác với -v thử nghiệm, mặc dù điều này dường như chỉ có trên các phiên bản mới của bash và không di chuyển qua vỏ. - Graeme
Như đã chỉ ra bởi @NathanKidd, các giải pháp chính xác được đưa ra bởi Lionel và Jens. prosseek, bạn nên chuyển câu trả lời được chấp nhận của bạn đến một trong số này. - Garrett
... hoặc câu trả lời không chính xác có thể được giảm xuống bởi sự sáng suốt hơn trong số chúng ta, vì @prosseek không giải quyết được vấn đề. - dan3


Các câu trả lời:


(Thông thường) Đúng cách

if [ -z ${var+x} ]; then echo "var is unset"; else echo "var is set to '$var'"; fi

Ở đâu ${var+x} là một mở rộng tham số mà đánh giá là không có gì nếu var không được đặt và thay thế chuỗi x nếu không thì.

Báo giá

Báo giá có thể được bỏ qua (vì vậy chúng tôi có thể nói ${var+x} thay vì "${var+x}") bởi vì cú pháp và cách sử dụng này đảm bảo điều này sẽ chỉ mở rộng đến một thứ không yêu cầu báo giá (vì nó mở rộng đến x (không chứa từ ngắt vì vậy nó không cần trích dẫn), hoặc không có gì (kết quả là [ -z ], thuận tiện đánh giá cùng một giá trị (đúng) [ -z "" ] cũng vậy)).

Tuy nhiên, trong khi dấu ngoặc kép có thể được bỏ qua một cách an toàn, và nó không rõ ràng cho tất cả (nó thậm chí không rõ ràng để tác giả đầu tiên của lời giải thích trích dẫn này ai cũng là một lập trình viên Bash chính), đôi khi sẽ tốt hơn khi viết giải pháp với các dấu ngoặc kép [ -z "${var+x}" ], với chi phí rất nhỏ có thể của một hình phạt O (1). Tác giả đầu tiên cũng đã thêm điều này làm nhận xét bên cạnh mã sử dụng giải pháp này để cung cấp URL cho câu trả lời này, mà bây giờ cũng bao gồm giải thích lý do tại sao các dấu ngoặc kép có thể được bỏ qua một cách an toàn.

(Thường) Cách sai

if [ -z "$var" ]; then echo "var is blank"; else echo "var is set to '$var'"; fi

Điều này thường sai vì nó không phân biệt giữa một biến không được đặt và biến được đặt thành chuỗi rỗng. Đó là để nói, nếu var='', thì giải pháp trên sẽ xuất ra "var là trống".

Sự khác biệt giữa unset và "set to the empty string" là điều cần thiết trong các tình huống mà người dùng phải chỉ định một phần mở rộng hoặc danh sách các thuộc tính bổ sung và không chỉ định chúng mặc định cho giá trị không trống, trong khi chỉ định chuỗi rỗng làm cho tập lệnh sử dụng phần mở rộng trống hoặc danh sách các thuộc tính bổ sung.

Sự khác biệt có thể không cần thiết trong mọi viễn cảnh. Trong những trường hợp đó [ -z "$var" ] sẽ ổn thôi.


1608
2017-12-13 17:04



@Garrett, bản chỉnh sửa của bạn đã làm cho câu trả lời này không chính xác, ${var+x} là sự thay thế chính xác để sử dụng. Sử dụng [ -z ${var:+x} ] không tạo ra kết quả khác với [ -z "$var" ]. - Graeme
Điều này không hoạt động. Tôi nhận được "không được thiết lập" bất kể cho dù var được thiết lập để một giá trị hay không (xóa với "unset var", "echo $ var" sản xuất không có đầu ra). - Brent212
Đối với cú pháp của giải pháp $ {parameter + word}, ​​phần hướng dẫn chính thức là gnu.org/software/bash/manual/… ; tuy nhiên, một lỗi trong đó, nó không đề cập rõ ràng cú pháp này nhưng chỉ nói trích dẫn (Bỏ qua dấu hai chấm [":"] kết quả trong một thử nghiệm chỉ cho một tham số không được đặt. .. $ {parameter: + word} [có nghĩa là] Nếu tham số là null hoặc không được đặt, không có gì được thay thế, nếu không thì việc mở rộng từ được thay thế.); trích dẫn pubs.opengroup.org/onlinepubs/9699919799/utilities/… (tốt để biết) có tài liệu rõ ràng hơn nhiều ở đây. - Destiny Architect
Có vẻ như dấu ngoặc kép là bắt buộc khi bạn sử dụng nhiều biểu thức, ví dụ: [ -z "" -a -z ${var+x} ] được bash: [: argument expected trong bash 4.3-ubuntu (nhưng không phải là zsh). Tôi thực sự không thích câu trả lời bằng cách sử dụng cú pháp xảy ra trong một số trường hợp. - FauxFaux
Sử dụng đơn giản [ -z $var ] không còn "sai" hơn là bỏ qua các trích dẫn. Dù bằng cách nào, bạn đang đưa ra các giả định về đầu vào của mình. Nếu bạn đang xử lý một chuỗi trống là không được đặt, [ -z $var ] là tất cả những gì bạn cần. - N13


Để kiểm tra biến chuỗi không null / khác không, tức là nếu được đặt, hãy sử dụng

if [ -n "$1" ]

Nó trái ngược với -z. Tôi thấy mình đang sử dụng -n nhiều hơn -z.


654
2017-08-30 15:17



Tôi thường thích [[ ]] kết thúc [ ], như [[ ]] là mạnh mẽ hơn và gây ra ít vấn đề hơn trong các tình huống nhất định (xem câu hỏi này cho một lời giải thích về sự khác biệt giữa hai). Câu hỏi đặc biệt yêu cầu bash giải pháp và không đề cập đến bất kỳ yêu cầu về tính di động nào. - Flow
Câu hỏi đặt ra là làm thế nào người ta có thể thấy nếu một biến bộ. Sau đó, bạn không thể giả định rằng biến Là bộ. - HelloGoodbye
Tôi đồng ý, [] hoạt động tốt hơn đặc biệt cho các kịch bản shell (non-bash). - Hengjie
Không bật set -u. - Ciro Santilli 新疆改造中心 六四事件 法轮功
Lưu ý rằng -n là thử nghiệm mặc định, vì vậy đơn giản hơn [ "$1" ] hoặc là [[ $1 ]] cũng vậy. Cũng lưu ý rằng với [[ ]]  trích dẫn là không cần thiết. - tne


Dưới đây là cách kiểm tra xem một tham số có bỏ đặt, hoặc là trống ("Null") hoặc là đặt với một giá trị:

+--------------------+----------------------+-----------------+-----------------+
|                    |       parameter      |     parameter   |    parameter    |
|                    |   Set and Not Null   |   Set But Null  |      Unset      |
+--------------------+----------------------+-----------------+-----------------+
| ${parameter:-word} | substitute parameter | substitute word | substitute word |
| ${parameter-word}  | substitute parameter | substitute null | substitute word |
| ${parameter:=word} | substitute parameter | assign word     | assign word     |
| ${parameter=word}  | substitute parameter | substitute null | assign word     |
| ${parameter:?word} | substitute parameter | error, exit     | error, exit     |
| ${parameter?word}  | substitute parameter | substitute null | error, exit     |
| ${parameter:+word} | substitute word      | substitute null | substitute null |
| ${parameter+word}  | substitute word      | substitute word | substitute null |
+--------------------+----------------------+-----------------+-----------------+

Nguồn: POSIX: Mở rộng tham số:

Trong tất cả các trường hợp được hiển thị bằng "thay thế", biểu thức được thay thế bằng giá trị được hiển thị. Trong tất cả các trường hợp được hiển thị bằng "gán", tham số được gán giá trị đó, cũng thay thế biểu thức.


390
2018-05-25 20:20



@ HelloGoodbye Có nó hoạt động: set foo; echo ${1:-set but null or unset} echos "foo"; set --; echo ${1:-set but null or unset} tiếng vang được đặt nhưng không có ... - Jens
@HelloGoodbye Các thông số vị trí có thể được thiết lập với, uh, set :-) - Jens
Câu trả lời này rất khó hiểu. Bất kỳ ví dụ thực tế về cách sử dụng bảng này? - Ben Davis
@BenDavis Các chi tiết được giải thích trong liên kết đến tiêu chuẩn POSIX, tham chiếu đến chương mà bảng được lấy từ đó. Một cấu trúc tôi sử dụng trong hầu hết mọi tập lệnh tôi viết là : ${FOOBAR:=/etc/foobar.conf} để đặt giá trị mặc định cho biến nếu nó không được đặt hoặc không được đặt. - Jens
parameter là bất kỳ tên biến nào. word là một số chuỗi để thay thế tùy thuộc vào cú pháp trong bảng bạn đang sử dụng và liệu biến $parameter được đặt, được đặt nhưng không có hoặc không được đặt. Không làm mọi thứ phức tạp hơn, nhưng word cũng có thể bao gồm các biến! Điều này có thể rất hữu ích khi chuyển các tham số tùy chọn được phân cách bởi một ký tự. Ví dụ: ${parameter:+,${parameter}} đầu ra một dấu phẩy tách ra ,$parameter nếu nó được đặt nhưng không rỗng. Trong trường hợp này, word Là ,${parameter} - TrinitronX


Có nhiều cách để làm điều này với những điều sau đây là một trong số chúng:

if [ -z "$1" ]

Điều này thành công nếu $ 1 là null hoặc không được đặt


168
2017-08-30 15:00



Có một sự khác biệt giữa một tham số unset và một tham số với một giá trị null. - chepner
Tôi chỉ muốn trở thành người theo dõi và chỉ ra đây là đối diện trả lời cho câu hỏi đặt ra. Các câu hỏi sẽ hỏi nếu biến IS được đặt, không phải nếu biến không được đặt. - Philluminati
[[ ]] không là gì ngoài một lỗ hổng di động. if [ -n "$1" ] nên được sử dụng ở đây. - Jens
Câu trả lời này không đúng. Câu hỏi đặt ra một cách để cho biết liệu một biến có được đặt hay không, cho dù nó được đặt thành giá trị không trống hay không. Được foo="", $foo có giá trị, nhưng -z sẽ chỉ báo cáo rằng nó trống. Và -z $foo sẽ nổ tung nếu bạn có set -o nounset. - Keith Thompson
Lưu ý rằng nếu -u được đặt, điều này sẽ dẫn đến lỗi. - Daniel C. Sobral


Trong khi hầu hết các kỹ thuật được nêu ở đây là chính xác, bash 4.2 hỗ trợ một thử nghiệm thực tế cho sự hiện diện của một biến (người đàn ông bash), thay vì kiểm tra giá trị của biến.

[[ -v foo ]]; echo $?
# 1

foo=bar
[[ -v foo ]]; echo $?
# 0

foo=""
[[ -v foo ]]; echo $?
# 0

146
2017-07-09 02:28



Trong bash 4.1.2, bất kể biến có được đặt hay không, [[ -v aaa ]]; echo $? ==> -bash: conditional binary operator expected  -bash: syntax error near 'aaa' - Dan
Đối số '-v' cho nội trang 'test' được thêm vào bash 4.2. - Ti Strga
đối số -v được thêm vào như là một bổ sung cho tùy chọn -u shell (nounset). Khi 'nounset' được bật (set -u), shell sẽ trả về lỗi và kết thúc, nếu nó không tương tác. $ # tốt cho việc kiểm tra các tham số vị trí. Tuy nhiên, các biến được đặt tên cần một số cách khác, không phải là clobbering, để xác định chúng là không được đặt. Thật không may là tính năng này đã đến muộn vì nhiều người bị ràng buộc là phiên bản tương thích trước đó, trong trường hợp đó họ không thể sử dụng nó. Lựa chọn duy nhất khác là sử dụng thủ thuật hoặc 'hack' để có được xung quanh nó như được hiển thị ở trên nhưng nó là không phù hợp nhất. - osirisgothra
Tôi nghĩ rằng nhận xét của osirisgothra về việc sử dụng $ # để kiểm tra các thông số vị trí nên được thêm vào câu trả lời. Thật không may -v không hoạt động với các tham số vị trí (ví dụ [[-v 2]] không giống với [[$ # -ge 2]]), ít nhất là trong bash 4.3.11 của tôi. - Jaan
Lưu ý điều này không hoạt động đối với các biến được khai báo nhưng không được đặt. ví dụ. declare -a foo - miken32


Để xem một biến không phải là không, tôi sử dụng

if [[ $var ]]; then ...       # `$var' expands to a nonempty string

Các kiểm tra ngược lại nếu một biến không được đặt hoặc bị trống:

if [[ ! $var ]]; then ...     # `$var' expands to the empty string (set or not)

Để xem nếu biến được đặt (trống hoặc không trống), tôi sử dụng

if [[ ${var+x} ]]; then ...   # `var' exists (empty or nonempty)
if [[ ${1+x} ]]; then ...     # Parameter 1 exists (empty or nonempty)

Các kiểm tra ngược lại nếu một biến không được đặt:

if [[ ! ${var+x} ]]; then ... # `var' is not set at all
if [[ ! ${1+x} ]]; then ...   # We were called with no arguments

54
2018-05-08 08:32



Tôi cũng đã sử dụng nó một lúc; chỉ trong một cách giảm: [ $isMac ] && param="--enable-shared"
@Bhaskar Tôi nghĩ đó là vì câu trả lời này đã cung cấp bản chất cùng một câu trả lời (sử dụng ${variable+x} để có được x iff $variable được thiết lập) gần nửa năm trước đó. Ngoài ra nó có nhiều chi tiết hơn giải thích lý do tại sao nó đúng. - Mark Haferkamp


Trên một phiên bản hiện đại của Bash (4.2 hoặc mới hơn tôi nghĩ, tôi không biết chắc chắn), tôi sẽ cố gắng này:

if [ ! -v SOMEVARIABLE ] #note the lack of a $ sigil
then
    echo "Variable is unset"
elif [ -z "$SOMEVARIABLE" ]
then
    echo "Variable is set to an empty string"
else
    echo "Variable is set to some string"
fi

30
2017-08-26 16:24



Cũng lưu ý rằng [ -v "$VARNAME" ] không chính xác, nhưng chỉ cần thực hiện một thử nghiệm khác. Giả sử VARNAME=foo; sau đó nó sẽ kiểm tra nếu có một biến có tên foo được đặt. - chepner
Lưu ý cho những người muốn tính di động, -v không tuân thủ POSIX - kzh
Nếu một người được [: -v: unexpected operator, người ta phải đảm bảo sử dụng bash thay vì sh. - koppor


Tôi luôn tìm thấy bảng POSIX trong câu trả lời khác chậm để grok, vì vậy đây là của tôi đưa vào nó:

   +----------------------+------------+-----------------------+-----------------------+
   |   if VARIABLE is:    |    set     |         empty         |        unset          |
   +----------------------+------------+-----------------------+-----------------------+
 - |  ${VARIABLE-default} | $VARIABLE  |          ""           |       "default"       |
 = |  ${VARIABLE=default} | $VARIABLE  |          ""           | $(VARIABLE="default") |
 ? |  ${VARIABLE?default} | $VARIABLE  |          ""           |       exit 127        |
 + |  ${VARIABLE+default} | "default"  |       "default"       |          ""           |
   +----------------------+------------+-----------------------+-----------------------+
:- | ${VARIABLE:-default} | $VARIABLE  |       "default"       |       "default"       |
:= | ${VARIABLE:=default} | $VARIABLE  | $(VARIABLE="default") | $(VARIABLE="default") |
:? | ${VARIABLE:?default} | $VARIABLE  |       exit 127        |       exit 127        |
:+ | ${VARIABLE:+default} | "default"  |          ""           |          ""           |
   +----------------------+------------+-----------------------+-----------------------+

Lưu ý rằng mỗi nhóm (có và không có dấu hai chấm trước) có cùng bộ và bỏ đặt trường hợp, vì vậy điều duy nhất khác biệt là cách trống các trường hợp được xử lý.

Với dấu hai chấm trước, trống và bỏ đặt các trường hợp giống hệt nhau, vì vậy tôi sẽ sử dụng những trường hợp có thể (ví dụ: sử dụng :=, không chỉ =, bởi vì trường hợp trống không phù hợp).

Tiêu đề:

  • bộ có nghĩa VARIABLE không trống (VARIABLE="something")
  • trống có nghĩa VARIABLE rỗng / không (VARIABLE="")
  • bỏ đặt có nghĩa VARIABLE không tồn tại (unset VARIABLE)

Giá trị:

  • $VARIABLE có nghĩa là kết quả là giá trị ban đầu của biến.
  • "default" có nghĩa là kết quả là chuỗi thay thế được cung cấp.
  • "" có nghĩa là kết quả là null (một chuỗi rỗng).
  • exit 127 nghĩa là tập lệnh ngừng thực thi với mã thoát 127.
  • $(VARIABLE="default") có nghĩa là kết quả là giá trị ban đầu của biến  chuỗi thay thế được cung cấp được gán cho biến để sử dụng sau này.

30
2018-06-17 15:19



Bạn cố định chỉ những lỗi thực sự là lỗi mã hóa (các cá thể không mong muốn khi làm việc với các biến). Tôi đã thực hiện chỉnh sửa để sửa một vài trường hợp khác mà đồng đô la tạo sự khác biệt trong việc diễn giải mô tả. BTW, tất cả các biến shell (ngoại trừ mảng) là các biến chuỗi; nó có thể xảy ra rằng chúng chứa một chuỗi có thể được hiểu là một số. Nói về dây chỉ làm mờ tin nhắn. Báo giá không liên quan gì đến chuỗi, chúng chỉ là một cách thay thế để thoát. VARIABLE="" có thể được viết là VARIABLE=. Tuy nhiên, trước đây là dễ đọc hơn. - Palec
Ah, điều đó làm cho nó rõ ràng hơn - đánh giá cao lời khuyên! - deizel


if [ "$1" != "" ]; then
  echo \$1 is set
else
  echo \$1 is not set
fi

Mặc dù đối với các đối số thì tốt nhất là thử $ #, đó là số lượng đối số, theo ý kiến ​​của tôi.

if [ $# -gt 0 ]; then
  echo \$1 is set
else
  echo \$1 is not set
fi

18
2017-08-30 15:00



Thử nghiệm đầu tiên là lạc hậu; Tôi nghĩ bạn muốn [ "$1" != "" ] (hoặc là [ -n "$1" ]) ... - Gordon Davisson
@Gordon, đã sửa! - Paul Creasey
Điều này sẽ thất bại nếu $1 được đặt thành chuỗi trống. - HelloGoodbye
Phần thứ hai của câu trả lời (các tham số đếm) là một giải pháp hữu ích cho phần đầu của câu trả lời không hoạt động khi $1 được đặt thành một chuỗi trống. - Mark Berry
Điều này sẽ thất bại nếu set -o nounset đang bật. - Flimm