จะตรวจสอบว่าตัวแปรถูกตั้งค่าใน Bash ได้อย่างไร?


1567

ฉันจะทราบได้อย่างไรว่าตัวแปรถูกตั้งค่าใน Bash หรือไม่

ตัวอย่างเช่นฉันจะตรวจสอบได้อย่างไรว่าผู้ใช้กำหนดพารามิเตอร์แรกให้กับฟังก์ชันหรือไม่

function a {
    # if $1 is set ?
}

12
if test $# -gt 0; then printf 'arg <%s>\n' "$@"; fi.
Jens

210
หมายเหตุถึงผู้ค้นหาโซลูชัน: มีคำตอบมากมายสำหรับคำถามนี้ที่ตอบคำถาม "เป็นตัวแปรที่ไม่ว่างเปล่า" โซลูชันการแก้ไขเพิ่มเติม ("คือชุดตัวแปร") ถูกกล่าวถึงในคำตอบของ Jens และ Lionel ด้านล่าง
นาธาน Kidd

8
นอกจากนี้รัสเซลฮาร์มอนและเชมัสก็ถูกต้องด้วย-vการทดสอบถึงแม้ว่ามันจะมีเฉพาะในเวอร์ชั่นใหม่เท่านั้นbashและไม่สามารถพกพาข้ามเชลล์ได้
แกรม

5
ตามที่ระบุโดย @NathanKidd โซลูชั่นที่ถูกต้องจะได้รับจาก Lionel และ Jens prosseek คุณควรเปลี่ยนคำตอบที่คุณยอมรับให้เป็นหนึ่งในนั้น
Garrett

3
... หรือคำตอบที่ไม่ถูกต้องอาจถูกลดทอนลงโดยคนที่ฉลาดกว่าในหมู่เราเนื่องจาก @prosseek ไม่ได้แก้ไขปัญหา
dan3

คำตอบ:


2301

(ปกติ) วิธีที่ถูกต้อง

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

โดยที่${var+x}การขยายพารามิเตอร์ซึ่งประเมินเป็นอะไรถ้าvarไม่ได้ตั้งค่าและแทนที่สตริงเป็นxอย่างอื่น

การพูดคำพูด

สามารถละเว้นเครื่องหมายอัญประกาศ(เพื่อให้เราสามารถพูด${var+x}แทนได้"${var+x}") เนื่องจากไวยากรณ์และการใช้งานนี้รับประกันได้ว่าจะขยายไปยังบางสิ่งที่ไม่จำเป็นต้องมีเครื่องหมายอัญประกาศเท่านั้น (เนื่องจากอาจขยายเป็นx(ซึ่งไม่มีการแบ่งคำ ไม่มีสิ่งใด (ซึ่งส่งผล[ -z ]ให้ประเมินสิ่งอำนวยความสะดวกให้เป็นค่าเดียวกัน (จริง) ที่[ -z "" ]ทำได้เช่นกัน)

อย่างไรก็ตามในขณะที่ราคาสามารถละเว้นได้อย่างปลอดภัยและมันก็ไม่ได้ชัดเจนทันทีที่ทุกคน (มันไม่ได้ชัดเจนแม้แต่กับผู้เขียนคนแรกของคำอธิบายคำพูดนี้ใครยังเป็น Bash coder ที่สำคัญ) บางครั้งมันจะดีกว่าที่จะเขียนทางออก ด้วยราคาที่เป็น[ -z "${var+x}" ]ไปได้ของการลงโทษความเร็ว O (1) น้อยมาก ผู้เขียนคนแรกยังเพิ่มสิ่งนี้เป็นความคิดเห็นถัดจากโค้ดโดยใช้วิธีแก้ปัญหานี้ซึ่งให้ URL ของคำตอบนี้ซึ่งในขณะนี้ยังมีคำอธิบายสำหรับสาเหตุที่สามารถละเว้นคำพูดได้อย่างปลอดภัย

(บ่อยครั้ง) วิธีที่ผิด

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

สิ่งนี้มักจะผิดเพราะมันไม่ได้แยกความแตกต่างระหว่างตัวแปรที่ไม่ได้ตั้งค่าและตัวแปรที่ถูกตั้งค่าเป็นสตริงว่าง กล่าวคือถ้าvar=''แก้ปัญหาข้างต้นจะส่งออก "var ว่างเปล่า"

ความแตกต่างระหว่าง unset และ "set to string ว่างเปล่า" เป็นสิ่งจำเป็นในสถานการณ์ที่ผู้ใช้ต้องระบุส่วนขยายหรือรายการคุณสมบัติเพิ่มเติมและไม่ได้ระบุค่าเริ่มต้นให้เป็นค่าที่ไม่ว่างเปล่าในขณะที่ระบุสตริงว่างควร ทำให้สคริปต์ใช้ส่วนขยายที่ว่างเปล่าหรือรายการคุณสมบัติเพิ่มเติม

ความแตกต่างอาจไม่จำเป็นในทุกสถานการณ์ ในกรณีเหล่านั้น [ -z "$var" ]จะไม่เป็นไร


29
@Garrett การแก้ไขของคุณทำให้คำตอบนี้ไม่ถูกต้อง${var+x}เป็นการทดแทนที่ถูกต้องที่จะใช้ ใช้ผลิตไม่มีผลแตกต่างกว่า[ -z ${var:+x} ] [ -z "$var" ]
แกรม

11
มันใช้งานไม่ได้ ฉันได้รับ "ไม่ได้ตั้งค่า" โดยไม่คำนึงว่า var ถูกตั้งค่าเป็นค่าหรือไม่ (ลบด้วย "unset var", "echo $ var" จะไม่สร้างเอาต์พุต)
Brent212

10
สำหรับไวยากรณ์ของโซลูชัน $ {parameter + word} ส่วนคู่มืออย่างเป็นทางการคือgnu.org/software/bash/manual/… ; อย่างไรก็ตามข้อผิดพลาดในนั้นไม่ได้กล่าวถึงอย่างชัดเจนไวยากรณ์นี้ แต่พูดเพียงแค่อัญประกาศ (ละเว้นโคลอน [":"] ผลลัพธ์ในการทดสอบเฉพาะสำหรับพารามิเตอร์ที่ไม่ได้ตั้งค่า .. $ {พารามิเตอร์: + คำ} [หมายถึง] หากพารามิเตอร์เป็นโมฆะหรือไม่มีการตั้งค่าจะไม่มีสิ่งใดถูกแทนที่มิฉะนั้นการขยายตัวของคำจะถูกแทนที่); อ้างอิง ref pubs.opengroup.org/onlinepubs/9699919799/utilities/… (ควรรู้) มีเอกสารที่ชัดเจนกว่ามากที่นี่
Destiny Architect

7
ดูเหมือนว่าจำเป็นต้องใช้อัญประกาศเมื่อคุณใช้หลายนิพจน์เช่น[ -z "" -a -z ${var+x} ]รับbash: [: argument expectedใน bash 4.3-ubuntu (แต่ไม่ใช่เช่น zsh) ฉันไม่ชอบคำตอบจริงๆโดยใช้ไวยากรณ์ที่เกิดขึ้นกับการทำงานในบางกรณี
FauxFaux

41
การใช้แบบง่าย[ -z $var ]ไม่ "ผิด" มากกว่าการละเว้นคำพูด ไม่ว่าจะด้วยวิธีใดคุณกำลังตั้งสมมติฐานเกี่ยวกับข้อมูลที่คุณป้อน หากคุณจัดการกับสตริงว่างเปล่าเป็น unset [ -z $var ]เป็นสิ่งที่คุณต้องการ
nshew

909

ในการตรวจสอบตัวแปรสตริงที่ไม่เป็นนัล / ไม่เป็นศูนย์เช่นถ้าตั้งให้ใช้

if [ -n "$1" ]

-zมันตรงข้ามของ ฉันพบตัวเองโดยใช้มากกว่า-n-z

คุณจะใช้มันเหมือน:

if [ -n "$1" ]; then
  echo "You supplied the first parameter!"
else
  echo "First parameter not supplied."
fi

86
ฉันมักจะชอบ[[ ]]มากกว่า[ ]เพราะ[[ ]]มีประสิทธิภาพมากขึ้นและทำให้เกิดปัญหาน้อยลงในบางสถานการณ์ (ดูคำถามนี้สำหรับคำอธิบายความแตกต่างระหว่างสอง) คำถามนี้ถามถึงโซลูชันทุบตีโดยเฉพาะและไม่ได้กล่าวถึงข้อกำหนดความสะดวกในการพกพาใด ๆ
Flow

18
คำถามคือวิธีการหนึ่งที่สามารถดูได้ว่าตัวแปรเป็นชุด แล้วคุณจะไม่สามารถสรุปได้ว่าตัวแปรมีการตั้งค่า
HelloGoodbye

7
ฉันเห็นด้วย[]ทำงานได้ดีขึ้นโดยเฉพาะกับสคริปต์ shell (non-bash)
Hengjie

73
set -uล้มเหลวใน
Ciro Santilli 冠状病毒审查六四事件法轮功

63
โปรดทราบว่า-nนี่คือการทดสอบเริ่มต้นดังนั้นง่ายขึ้น[ "$1" ]หรือ[[ $1 ]]ทำงานได้ดีขึ้น นอกจากนี้ทราบว่ามีข้อความที่ไม่จำเป็น[[ ]]
tne

478

ต่อไปนี้เป็นวิธีทดสอบว่าพารามิเตอร์ไม่มีการตั้งค่าหรือว่างเปล่า ("Null")หรือตั้งค่าด้วยค่า :

+--------------------+----------------------+-----------------+-----------------+
|   Expression       |       parameter      |     parameter   |    parameter    |
|   in script:       |   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 |
+--------------------+----------------------+-----------------+-----------------+

ที่มา: POSIX: การขยายพารามิเตอร์ :

ในทุกกรณีที่แสดงด้วย "ทดแทน" นิพจน์จะถูกแทนที่ด้วยค่าที่แสดง ในทุกกรณีที่แสดงด้วย "assign" พารามิเตอร์จะถูกกำหนดค่านั้นซึ่งจะแทนที่นิพจน์

หากต้องการแสดงสิ่งนี้ให้ดำเนินการ:

+--------------------+----------------------+-----------------+-----------------+
|   Expression       |  FOO="world"         |     FOO=""      |    unset FOO    |
|   in script:       |  (Set and Not Null)  |  (Set But Null) |     (Unset)     |
+--------------------+----------------------+-----------------+-----------------+
| ${FOO:-hello}      | world                | hello           | hello           |
| ${FOO-hello}       | world                | ""              | hello           |
| ${FOO:=hello}      | world                | FOO=hello       | FOO=hello       |
| ${FOO=hello}       | world                | ""              | FOO=hello       |
| ${FOO:?hello}      | world                | error, exit     | error, exit     |
| ${FOO?hello}       | world                | ""              | error, exit     |
| ${FOO:+hello}      | hello                | ""              | ""              |
| ${FOO+hello}       | hello                | hello           | ""              |
+--------------------+----------------------+-----------------+-----------------+

5
@HelloGoodbye ใช่มันใช้งานได้: set foo; echo ${1:-set but null or unset}echos "foo"; set --; echo ${1:-set but null or unset}ก้องชุด แต่ null ...
Jens

4
@HelloGoodbye พารามิเตอร์ตำแหน่งสามารถตั้งค่าด้วยเอ่อset:-)
Jens

95
คำตอบนี้ทำให้สับสนมาก ตัวอย่างใด ๆ ที่ใช้งานได้จริงเกี่ยวกับวิธีใช้ตารางนี้?
Ben Davis

12
@BenDavis รายละเอียดมีการอธิบายในลิงก์ไปยังมาตรฐาน POSIX ซึ่งอ้างอิงถึงบทที่นำมาจากตาราง สิ่งปลูกสร้างหนึ่งที่ฉันใช้ในเกือบทุกสคริปต์ที่ฉันเขียนคือ: ${FOOBAR:=/etc/foobar.conf}การตั้งค่าเริ่มต้นสำหรับตัวแปรหากไม่ได้ตั้งค่าไว้
Jens

1
parameterเป็นชื่อตัวแปรใด ๆ wordเป็นสตริงที่จะแทนที่โดยขึ้นอยู่กับว่าไวยากรณ์ใดในตารางที่คุณกำลังใช้และไม่ว่า$parameterจะตั้งค่าตัวแปรตั้งค่าเป็นโมฆะหรือไม่ได้ตั้งค่า เพื่อไม่ให้สิ่งที่ซับซ้อนมากขึ้น แต่wordยังสามารถรวมตัวแปร! สิ่งนี้มีประโยชน์มากสำหรับการผ่าน args ที่เป็นทางเลือกคั่นด้วยอักขระ ตัวอย่างเช่น: ${parameter:+,${parameter}}เอาต์พุตคั่นด้วยเครื่องหมายจุลภาค,$parameterหากตั้งค่า แต่ไม่เป็นค่าว่าง ในกรณีนี้wordคือ,${parameter}
TrinitronX

260

แม้ว่าเทคนิคส่วนใหญ่ที่ระบุไว้ในที่นี้จะถูกต้อง แต่bash 4.2รองรับการทดสอบจริงสำหรับการปรากฏตัวของตัวแปร ( man bash ) แทนที่จะทดสอบค่าของตัวแปร

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

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

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

โดยเฉพาะอย่างยิ่งวิธีการนี้จะไม่ทำให้เกิดข้อผิดพลาดเมื่อนำมาใช้ในการตรวจสอบล้างค่าตัวแปรในset -u/ set -o nounsetโหมดซึ่งแตกต่างจากวิธีอื่น ๆ [ -zอีกมากมายเช่นการใช้


9
ใน bash 4.1.2 ไม่ว่าตัวแปรจะถูกตั้งค่าไว้หรือไม่ก็ตาม[[ -v aaa ]]; echo $?==>-bash: conditional binary operator expected -bash: syntax error near 'aaa'
Dan

32
อาร์กิวเมนต์ '-v' สำหรับ buildin 'test' ถูกเพิ่มใน bash 4.2
Ti Strga

19
อาร์กิวเมนต์ -v ถูกเพิ่มเป็นส่วนเสริมให้กับตัวเลือกเชลล์ -u (คำนาม) เมื่อเปิดใช้ 'คำนาม' (set -u) เชลล์จะส่งคืนข้อผิดพลาดและยุติหากไม่สามารถโต้ตอบได้ $ # ดีสำหรับการตรวจสอบพารามิเตอร์ตำแหน่ง อย่างไรก็ตามตัวแปรที่มีชื่อจำเป็นต้องใช้วิธีอื่นนอกเหนือจากการปิดบังเพื่อระบุว่าไม่มีการตั้งค่า โชคไม่ดีที่ฟีเจอร์นี้มาช้าเพราะมีหลายรุ่นที่เข้ากันได้กับเวอร์ชั่นก่อนหน้าซึ่งในกรณีนี้พวกเขาไม่สามารถใช้งานได้ ตัวเลือกอื่น ๆ เท่านั้นคือการใช้ลูกเล่นหรือ 'แฮ็ก' เพื่อหลีกเลี่ยงมันดังที่แสดงไว้ด้านบน แต่มันไม่เหมาะสมที่สุด
osirisgothra

2
หมายเหตุสิ่งนี้ใช้ไม่ได้กับตัวแปรที่ประกาศ แต่ไม่ได้ตั้งค่า เช่นdeclare -a foo
miken32

17
นี่คือเหตุผลที่ฉันอ่านต่อไปหลังจากคำตอบที่ยอมรับ / โหวตสูงสุด
Joe

176

มีหลายวิธีในการทำเช่นนี้โดยการเป็นหนึ่งในนั้น:

if [ -z "$1" ]

สิ่งนี้จะสำเร็จถ้า $ 1 เป็นโมฆะหรือไม่มีการตั้งค่า


46
มีความแตกต่างระหว่างพารามิเตอร์ unset และพารามิเตอร์ที่มีค่า Null
chepner

21
ฉันแค่อยากจะอวดรู้และชี้ให้เห็นว่านี่เป็นคำตอบที่ตรงกันข้ามกับสิ่งที่คำถามเกิดขึ้น คำถามจะถามว่ามีการตั้งค่าตัวแปรหรือไม่ถ้าไม่ได้ตั้งค่าตัวแปร
Philluminati

47
[[ ]]ไม่มีอะไรนอกจากเป็นข้อผิดพลาดในการพกพา if [ -n "$1" ]ควรใช้ที่นี่
Jens

73
คำตอบนี้ไม่ถูกต้อง คำถามถามถึงวิธีที่จะบอกว่าตัวแปรถูกตั้งค่าหรือไม่ไม่ว่ามันจะถูกตั้งเป็นค่าที่ไม่ว่างเปล่าหรือไม่ ป.ร. ให้ไว้foo="", $fooมีค่า แต่-zเพียงจะรายงานว่ามันเป็นที่ว่างเปล่า และจะพัดขึ้นถ้าคุณมี-z $foo set -o nounset
Keith Thompson

4
ขึ้นอยู่กับคำจำกัดความของ "ตัวแปรชุด" หากคุณต้องการตรวจสอบว่าตัวแปรถูกตั้งค่าเป็นสตริงที่ไม่ใช่ศูนย์หรือไม่คำตอบ mbranningนั้นถูกต้อง แต่ถ้าคุณต้องการตรวจสอบว่ามีการประกาศตัวแปร แต่ไม่ได้เริ่มต้น (เช่นfoo=) คำตอบของรัสเซลนั้นถูกต้อง
Flow

77

ฉันมักจะพบตาราง POSIX ในคำตอบอื่น ๆช้าไป grok ดังนั้นนี่คือของฉันใช้มัน:

   +----------------------+------------+-----------------------+-----------------------+
   |   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"  |          ""           |          ""           |
   +----------------------+------------+-----------------------+-----------------------+

โปรดทราบว่าแต่ละกลุ่ม (ที่มีและไม่มีก่อนลำไส้ใหญ่) มีเดียวกันชุดและล้างกรณีดังนั้นสิ่งเดียวที่แตกต่างกันเป็นวิธีการที่ว่างกรณีที่ได้รับการจัดการ

ด้วยโคลอนก่อนหน้านี้กรณีที่ว่างเปล่าและไม่ได้ตั้งเหมือนกันดังนั้นฉันจะใช้กรณีที่เป็นไปได้ (เช่นใช้:=ไม่ใช่เพียง=เพราะกรณีที่ว่างเปล่าไม่สอดคล้องกัน)

หัวเรื่อง:

  • หมายถึงชุดVARIABLEไม่ว่างเปล่า ( VARIABLE="something")
  • emptyหมายถึงVARIABLEempty / null ( VARIABLE="")
  • unsetหมายถึงVARIABLEไม่มีอยู่ ( unset VARIABLE)

ค่า:

  • $VARIABLE หมายความว่าผลลัพธ์คือค่าดั้งเดิมของตัวแปร
  • "default" หมายความว่าผลลัพธ์เป็นสตริงการแทนที่ที่จัดเตรียมไว้
  • "" หมายความว่าผลลัพธ์เป็นโมฆะ (สตริงว่าง)
  • exit 127 หมายความว่าสคริปต์หยุดทำงานด้วยรหัสออก 127
  • $(VARIABLE="default")หมายความว่าผลลัพธ์คือค่าดั้งเดิมของตัวแปรและสตริงการแทนที่ที่ระบุถูกกำหนดให้กับตัวแปรสำหรับใช้ในอนาคต

1
คุณได้แก้ไขข้อผิดพลาดในการเขียนโค้ดจริง (อินสแตนซ์ของการเปลี่ยนทิศทางที่ไม่พึงประสงค์เมื่อทำงานกับตัวแปร) ฉันได้ทำการแก้ไขเพื่อแก้ไขกรณีเพิ่มเติมไม่กี่กรณีที่เงินดอลลาร์สร้างความแตกต่างในการตีความคำอธิบาย BTW ตัวแปรเชลล์ทั้งหมด (ยกเว้นอาร์เรย์) เป็นตัวแปรสตริง มันอาจเกิดขึ้นที่พวกเขามีสตริงที่สามารถตีความได้ว่าเป็นตัวเลข การพูดเกี่ยวกับสายจะทำให้ข้อความเกิดความสับสน เครื่องหมายคำพูดไม่มีส่วนเกี่ยวข้องกับสตริง แต่เป็นเพียงทางเลือกหนึ่งในการหลบหนี VARIABLE=""สามารถเขียนเป็นVARIABLE=. ยังคงอดีตสามารถอ่านได้มากขึ้น
Palec

ขอบคุณสำหรับตารางที่มีประโยชน์มาก แต่ฉันพยายามที่จะออกจากสคริปต์หากไม่ได้ตั้งค่าหรือว่างเปล่า แต่รหัสทางออกที่ฉันได้รับคือ 1 ไม่ใช่ 127
นักบินอวกาศ

64

เพื่อดูว่าตัวแปรไม่ว่างเปล่าฉันใช้

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

การทดสอบตรงข้ามถ้าตัวแปรไม่ได้ตั้งค่าหรือว่างเปล่า:

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

เพื่อดูว่ามีการตั้งค่าตัวแปร (ว่างหรือไม่ว่าง) ฉันใช้

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

การทดสอบตรงข้ามถ้าตัวแปรไม่ได้ตั้งค่า:

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

ฉันก็ใช้สิ่งนี้มาระยะหนึ่งแล้ว ในวิธีที่ลดลง:[ $isMac ] && param="--enable-shared"

@ Bhaskar ฉันคิดว่าเป็นเพราะคำตอบนี้ได้ให้คำตอบเดียวกันโดยพื้นฐานแล้ว (ใช้${variable+x}เพื่อให้ได้รับxiff $variableตั้ง) เกือบครึ่งปีก่อนหน้านี้ นอกจากนี้ยังมีรายละเอียดมากขึ้นอธิบายว่าทำไมมันถูกต้อง
Mark Haferkamp

แต่${variable+x}อ่านไม่ได้ (& ชัดเจน)
knocte

35

ในเวอร์ชันที่ทันสมัยของ Bash (ฉันคิดว่า 4.2 ขึ้นไปฉันไม่รู้แน่) ฉันจะลองทำสิ่งนี้:

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

5
นอกจากนี้โปรดทราบว่า[ -v "$VARNAME" ]ไม่ถูกต้อง แต่เพียงดำเนินการทดสอบที่แตกต่างกัน สมมติว่าVARNAME=foo; จากนั้นจะตรวจสอบว่ามีชื่อตัวแปรfooที่ตั้งค่าไว้หรือไม่
chepner

5
หมายเหตุสำหรับผู้ที่ต้องการพกพา-vไม่เป็นไปตาม POSIX
kzh

หากใครได้รับ[: -v: unexpected operatorหนึ่งมีเพื่อให้แน่ใจว่าจะใช้แทนbash sh
koppor

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

ถึงแม้ว่าสำหรับข้อโต้แย้งมันเป็นสิ่งที่ดีที่สุดในการทดสอบ $ # ซึ่งเป็นจำนวนข้อโต้แย้งในความคิดของฉัน

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

1
การทดสอบครั้งแรกย้อนกลับ ฉันคิดว่าคุณต้องการ[ "$1" != "" ](หรือ[ -n "$1" ]) ...
Gordon Davisson

10
สิ่งนี้จะล้มเหลวหาก$1ตั้งค่าเป็นสตริงว่าง
HelloGoodbye

2
ส่วนที่สองของคำตอบ (พารามิเตอร์การนับ) เป็นวิธีแก้ปัญหาที่มีประโยชน์สำหรับส่วนแรกของคำตอบที่ไม่ทำงานเมื่อ$1ตั้งค่าเป็นสตริงว่าง
Mark Berry

สิ่งนี้จะล้มเหลวหากset -o nounsetเปิดอยู่
Flimm

21

บันทึก

ฉันให้คำตอบที่เน้นแรงมากเพราะbashแท็ก

คำตอบสั้น ๆ

ตราบใดที่คุณจัดการกับตัวแปรที่มีชื่อใน Bash ฟังก์ชันนี้ควรจะบอกคุณเสมอว่าตัวแปรนั้นถูกตั้งค่าไว้หรือไม่แม้ว่ามันจะเป็นอาร์เรย์ที่ว่างเปล่าก็ตาม

variable-is-set() {
    declare -p "$1" &>/dev/null
}

ทำไมถึงใช้งานได้

ใน Bash (อย่างน้อยที่สุดกลับมาที่ 3.0) หากvarเป็นตัวแปรที่ประกาศ / ตั้งค่าจะdeclare -p varแสดงdeclareคำสั่งที่จะตั้งค่าตัวแปรvarตามชนิดและค่าปัจจุบันของมันและส่งคืนรหัสสถานะ0(สำเร็จ) ถ้าvarจะไม่ได้ประกาศแล้วdeclare -p varแสดงข้อความแสดงข้อผิดพลาดไปและรหัสสถานะผลตอบแทนstderr 1ใช้&>/dev/null, เปลี่ยนทิศทางทั้งปกติstdoutและstderrส่งออกไป/dev/nullเป็นไม่เคยเห็นและไม่มีการเปลี่ยนรหัสสถานะ ดังนั้นฟังก์ชั่นจะส่งคืนรหัสสถานะเท่านั้น

สาเหตุที่วิธีการอื่น (บางครั้ง) ล้มเหลวใน Bash

  • [ -n "$var" ]:สิ่งนี้จะตรวจสอบว่า${var[0]}ไม่มีข้อมูลหรือไม่ (ใน Bash $varเป็นเช่นเดียวกับ${var[0]}.)
  • [ -n "${var+x}" ]:สิ่งนี้จะตรวจสอบว่า${var[0]}มีการตั้งค่าหรือไม่
  • [ "${#var[@]}" != 0 ]:สิ่งนี้จะตรวจสอบว่า$varมีการตั้งค่าอย่างน้อยหนึ่งดัชนี

เมื่อวิธีนี้ล้มเหลวใน Bash

นี้จะทำงานเฉพาะสำหรับตัวแปรชื่อ (รวม$_) ตัวแปรพิเศษไม่แน่ใจ ( $!, $@, $#, $$, $*, $?, $-, $0, $1, $2, ... , และที่ฉันอาจจะลืม) เนื่องจากไม่มีสิ่งเหล่านี้เป็นอาร์เรย์สไตล์ POSIX จึงใช้[ -n "${var+x}" ]งานได้กับตัวแปรพิเศษเหล่านี้ทั้งหมด แต่ระวังการห่อไว้ในฟังก์ชั่นเนื่องจากตัวแปรพิเศษจำนวนมากเปลี่ยนค่า / การดำรงอยู่เมื่อเรียกใช้ฟังก์ชั่น

บันทึกการทำงานร่วมกันของเชลล์

ถ้าสคริปต์ของคุณมีอาร์เรย์และคุณกำลังพยายามที่จะทำให้มันเข้ากันได้กับเปลือกหอยให้มากที่สุดเท่าที่เป็นไปได้แล้วพิจารณาใช้แทนtypeset -p declare -pฉันอ่านแล้วว่า ksh รองรับเฉพาะรุ่นก่อนหน้า แต่ไม่สามารถทดสอบได้ ฉันรู้ว่า Bash 3.0+ และ Zsh 5.5.1 แต่ละตัวรองรับทั้งคู่typeset -pและdeclare -pต่างกันเพียงอันเดียวที่เป็นตัวเลือกสำหรับอีกอันหนึ่ง แต่ฉันไม่ได้ทดสอบความแตกต่างจากคำหลักสองคำเหล่านั้นและฉันยังไม่ได้ทดสอบเชลล์อื่น ๆ

หากคุณต้องการให้สคริปต์ของคุณใช้งานร่วมกับ POSIX ได้คุณจะไม่สามารถใช้อาร์เรย์ได้ โดยไม่ต้องอาร์เรย์[ -n "{$var+x}" ]ทำงาน

รหัสเปรียบเทียบสำหรับวิธีการต่างๆใน Bash

ฟังก์ชั่นนี้จะยกเลิกการตั้งค่าตัวแปรvarซึ่งevalเป็นรหัสที่ผ่านแล้วทำการทดสอบเพื่อตรวจสอบว่าvarมีการตั้งค่าด้วยevalรหัส d หรือไม่และสุดท้ายจะแสดงรหัสสถานะที่ได้สำหรับการทดสอบที่แตกต่างกัน

ฉันกระโดดข้ามtest -v var, [ -v var ]และ[[ -v var ]]เพราะพวกเขาให้ผลลัพธ์ที่เหมือนกันกับมาตรฐาน POSIX [ -n "${var+x}" ]ในขณะที่ต้องทุบตีเวอร์ชัน 4.2 ขึ้นไป ฉันยังข้ามtypeset -pเพราะมันเหมือนกับdeclare -pเชลล์ที่ฉันทดสอบ (Bash 3.0 ถึง 5.0 และ Zsh 5.5.1)

is-var-set-after() {
    # Set var by passed expression.
    unset var
    eval "$1"

    # Run the tests, in increasing order of accuracy.
    [ -n "$var" ] # (index 0 of) var is nonempty
    nonempty=$?
    [ -n "${var+x}" ] # (index 0 of) var is set, maybe empty
    plus=$?
    [ "${#var[@]}" != 0 ] # var has at least one index set, maybe empty
    count=$?
    declare -p var &>/dev/null # var has been declared (any type)
    declared=$?

    # Show test results.
    printf '%30s: %2s %2s %2s %2s\n' "$1" $nonempty $plus $count $declared
}

รหัสกรณีทดสอบ

โปรดทราบว่าผลการทดสอบอาจไม่คาดคิดเนื่องจาก Bash ใช้ดัชนีอาร์เรย์ที่ไม่ใช่ตัวเลขเป็น "0" หากตัวแปรไม่ได้ถูกประกาศเป็นอาร์เรย์ที่เชื่อมโยง นอกจากนี้อาร์เรย์ที่เชื่อมโยงจะใช้ได้ใน Bash 4.0+ เท่านั้น

# Header.
printf '%30s: %2s %2s %2s %2s\n' "test" '-n' '+x' '#@' '-p'
# First 5 tests: Equivalent to setting 'var=foo' because index 0 of an
# indexed array is also the nonindexed value, and non-numerical
# indices in an array not declared as associative are the same as
# index 0.
is-var-set-after "var=foo"                        #  0  0  0  0
is-var-set-after "var=(foo)"                      #  0  0  0  0
is-var-set-after "var=([0]=foo)"                  #  0  0  0  0
is-var-set-after "var=([x]=foo)"                  #  0  0  0  0
is-var-set-after "var=([y]=bar [x]=foo)"          #  0  0  0  0
# '[ -n "$var" ]' fails when var is empty.
is-var-set-after "var=''"                         #  1  0  0  0
is-var-set-after "var=([0]='')"                   #  1  0  0  0
# Indices other than 0 are not detected by '[ -n "$var" ]' or by
# '[ -n "${var+x}" ]'.
is-var-set-after "var=([1]='')"                   #  1  1  0  0
is-var-set-after "var=([1]=foo)"                  #  1  1  0  0
is-var-set-after "declare -A var; var=([x]=foo)"  #  1  1  0  0
# Empty arrays are only detected by 'declare -p'.
is-var-set-after "var=()"                         #  1  1  1  0
is-var-set-after "declare -a var"                 #  1  1  1  0
is-var-set-after "declare -A var"                 #  1  1  1  0
# If 'var' is unset, then it even fails the 'declare -p var' test.
is-var-set-after "unset var"                      #  1  1  1  1

ทดสอบผลลัพธ์

จำการทดสอบในตรงส่วนหัวแถว[ -n "$var" ], [ -n "${var+x}" ], [ "${#var[@]}" != 0 ]และdeclare -p varตามลำดับ

                         test: -n +x #@ -p
                      var=foo:  0  0  0  0
                    var=(foo):  0  0  0  0
                var=([0]=foo):  0  0  0  0
                var=([x]=foo):  0  0  0  0
        var=([y]=bar [x]=foo):  0  0  0  0
                       var='':  1  0  0  0
                 var=([0]=''):  1  0  0  0
                 var=([1]=''):  1  1  0  0
                var=([1]=foo):  1  1  0  0
declare -A var; var=([x]=foo):  1  1  0  0
                       var=():  1  1  1  0
               declare -a var:  1  1  1  0
               declare -A var:  1  1  1  0
                    unset var:  1  1  1  1

สรุป

  • declare -p var &>/dev/null (100%) น่าเชื่อถือสำหรับการทดสอบตัวแปรที่มีชื่อใน Bash ตั้งแต่อย่างน้อย 3.0
  • [ -n "${var+x}" ] เชื่อถือได้ในสถานการณ์ที่สอดคล้องกับ POSIX แต่ไม่สามารถจัดการอาร์เรย์ได้
  • มีการทดสอบอื่นเพื่อตรวจสอบว่าตัวแปรไม่ว่างเปล่าหรือไม่และตรวจสอบตัวแปรที่ประกาศในเชลล์อื่น ๆ แต่การทดสอบเหล่านี้เหมาะสำหรับสคริปต์ Bash หรือ POSIX

3
จากคำตอบที่ฉันลอง, อันนี้ ( declare -p var &>/dev/null) เป็นคำเดียวที่ใช้ได้ ขอบคุณ!
user1387866

2
@ mark-haferkamp ฉันพยายามแก้ไขคำตอบของคุณเพื่อเพิ่มความสำคัญก่อนหน้า "/" ในโค้ดฟังก์ชั่นของคุณดังนั้นมันจึงอ่านได้... &> /dev/nullแต่ดังนั้นจะไม่ให้ฉันแก้ไขตัวอักษรเดียว🙄 (ต้อง> 6 ตัวอักษร - แม้แต่พยายามเพิ่มพื้นที่สีขาว แต่มันไม่ทำงาน) นอกจากนี้อาจเป็นการเปลี่ยนฟังก์ชั่นเพื่อเปลี่ยน$1สำหรับตัวอย่างชื่อตัวแปร (เช่นOUTPUT_DIR) เนื่องจากคุณชี้ให้เห็นว่าตัวแปรพิเศษเช่น$1ไม่ทำงานที่นี่ อย่างไรก็ตามมันเป็นแก้ไขที่สำคัญมิฉะนั้นรหัสที่กำลังมองหาที่จะสร้างไฟล์ที่เรียกว่าในไดเรกทอรีญาติเรียกว่าnull devBTW - คำตอบที่ยอดเยี่ยม!
joehanna

นอกจากนี้การใช้ชื่อของตัวแปรโดยไม่มีคำนำหน้า $ ยังใช้งานได้: declare -p PATH &> /dev/nullคืน 0 โดยให้declare -p ASDFASDGFASKDF &> /dev/nullผลตอบแทนเป็น1 (ใน bash 5.0.11 (1) - ปล่อย)
joehanna

1
การทำงานที่ดี! 1 คำเตือน: declare varประกาศตัวแปรหลายตัว แต่ไม่ได้ตั้งค่าเป็นset -o nounset: ทดสอบด้วยdeclare foo bar=; set -o nounset; echo $bar; echo $foo
xebeche

@ Joehanna ขอบคุณที่ติดตามสิ่งที่ขาดไป/! ฉันแก้ไขแล้ว แต่ฉันคิดว่าตรรกะนั้นน่าสับสนพอที่จะรับประกันฟังก์ชั่นโดยเฉพาะอย่างยิ่งในแง่ของความคิดเห็นของ @ xebeche @xebeche นั่นคือไม่สะดวกสำหรับคำตอบของฉัน ... . มันดูเหมือนว่าฉันจะต้องลองสิ่งที่ต้องการหรือdeclare -p "$1" | grep = test -v "$1"
Mark Haferkamp

19

สำหรับผู้ที่ต้องการตรวจสอบว่าไม่มีการกำหนดหรือว่างเปล่าเมื่ออยู่ในสคริปต์ด้วย set -u:

if [ -z "${var-}" ]; then
   echo "Must provide var environment variable. Exiting...."
   exit 1
fi

การ[ -z "$var" ]ตรวจสอบปกติจะล้มเหลวvar; unbound variableหากset -uแต่[ -z "${var-}" ] ขยายเป็นสตริงว่างถ้าvarไม่ได้ตั้งค่าโดยไม่ล้มเหลว


คุณไม่มีโคลอน มันควรจะเป็นไม่ได้${var:-} ${var-}แต่ใน Bash ฉันสามารถยืนยันได้แม้ไม่มีเครื่องหมายโคลอน
Palec

3
${var:-}และ${var-}หมายถึงสิ่งต่าง ๆ ${var:-}จะขยายเป็นสตริงว่างถ้าvarไม่มีการตั้งค่าหรือเป็นโมฆะและ${var-}จะขยายเป็นสตริงว่างถ้าไม่ได้ตั้งค่า
RubenLaguna

เพิ่งเรียนรู้สิ่งใหม่ขอบคุณ! การข้ามโคลอนไปจะส่งผลให้มีการทดสอบเฉพาะพารามิเตอร์ที่ไม่ได้ตั้งค่าไว้ ใส่อีกวิธีหนึ่งถ้ามีเครื่องหมายโคลอนอยู่ด้วยโอเปอเรเตอร์จะทดสอบการมีอยู่ของพารามิเตอร์ทั้งสองและค่านั้นไม่เป็นโมฆะ หากไม่ใส่เครื่องหมายจุดคู่ผู้ปฏิบัติงานจะทดสอบเฉพาะการมีอยู่จริง มันทำให้ไม่แตกต่างที่นี่ แต่ดีที่จะรู้
Palec

17

คุณต้องการออกหากยังไม่ได้ตั้งค่า

สิ่งนี้ใช้ได้สำหรับฉัน ฉันต้องการให้สคริปต์ของฉันออกจากพร้อมข้อความแสดงข้อผิดพลาดหากไม่ได้ตั้งค่าพารามิเตอร์

#!/usr/bin/env bash

set -o errexit

# Get the value and empty validation check all in one
VER="${1:?You must pass a version of the format 0.0.0 as the only argument}"

สิ่งนี้จะส่งคืนพร้อมข้อผิดพลาดเมื่อเรียกใช้

peek@peek:~$ ./setver.sh
./setver.sh: line 13: 1: You must pass a version of the format 0.0.0 as the only argument

ตรวจสอบเท่านั้นไม่มีทางออก - ว่างเปล่าและไม่ได้ตั้งค่าเป็นไม่ถูกต้อง

ลองใช้ตัวเลือกนี้ถ้าคุณเพียงต้องการตรวจสอบว่าค่า set = VALID หรือ unset / empty = INVALID

TSET="good val"
TEMPTY=""
unset TUNSET

if [ "${TSET:-}" ]; then echo "VALID"; else echo "INVALID";fi
# VALID
if [ "${TEMPTY:-}" ]; then echo "VALID"; else echo "INVALID";fi
# INVALID
if [ "${TUNSET:-}" ]; then echo "VALID"; else echo "INVALID";fi
# INVALID

หรือแม้กระทั่งการทดสอบสั้น ๆ ;-)

[ "${TSET:-}"   ] && echo "VALID" || echo "INVALID"
[ "${TEMPTY:-}" ] && echo "VALID" || echo "INVALID"
[ "${TUNSET:-}" ] && echo "VALID" || echo "INVALID"

ตรวจสอบเท่านั้นไม่มีทางออก - ว่างเปล่าเท่านั้นคือไม่ถูกต้อง

และนี่คือคำตอบของคำถาม ใช้สิ่งนี้หากคุณต้องการตรวจสอบว่าค่า set / empty = VALID หรือ unset = INVALID

หมายเหตุตัว "1" ใน "..- 1}" นั้นไม่มีนัยสำคัญมันสามารถเป็นอะไรก็ได้ (เช่น x)

TSET="good val"
TEMPTY=""
unset TUNSET

if [ "${TSET+1}" ]; then echo "VALID"; else echo "INVALID";fi
# VALID
if [ "${TEMPTY+1}" ]; then echo "VALID"; else echo "INVALID";fi
# VALID
if [ "${TUNSET+1}" ]; then echo "VALID"; else echo "INVALID";fi
# INVALID

การทดสอบสั้น ๆ

[ "${TSET+1}"   ] && echo "VALID" || echo "INVALID"
[ "${TEMPTY+1}" ] && echo "VALID" || echo "INVALID"
[ "${TUNSET+1}" ] && echo "VALID" || echo "INVALID"

ฉันอุทิศคำตอบนี้ให้กับ @ mklement0 (ความคิดเห็น) ที่ท้าทายให้ฉันตอบคำถามอย่างถูกต้อง

การอ้างอิงhttp://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_06_02


15

ในการตรวจสอบว่าตัวแปรถูกตั้งค่าด้วยค่าที่ไม่ว่างหรือไม่ให้ใช้[ -n "$x" ]ตามที่คนอื่น ๆ ระบุไว้แล้ว

ส่วนใหญ่แล้วมันเป็นความคิดที่ดีที่จะจัดการกับตัวแปรที่มีค่าว่างในแบบเดียวกับตัวแปรที่ไม่ได้ตั้งค่า แต่คุณสามารถแยกความแตกต่างระหว่างสองสิ่งนี้ได้หากคุณต้องการ: [ -n "${x+set}" ]( "${x+set}"ขยายเป็นsetหากxตั้งค่าและเป็นสตริงว่างถ้าxไม่ได้ตั้งค่า)

ในการตรวจสอบว่าพารามิเตอร์ผ่านการทดสอบ$#หรือไม่ซึ่งเป็นจำนวนพารามิเตอร์ที่ส่งผ่านไปยังฟังก์ชัน (หรือไปยังสคริปต์เมื่อไม่ได้อยู่ในฟังก์ชัน) (ดูคำตอบของ Paul )


14

อ่านส่วน "การขยายพารามิเตอร์" ของbashหน้า man การขยายพารามิเตอร์ไม่ได้ให้การทดสอบทั่วไปสำหรับตัวแปรที่กำลังตั้งค่า แต่มีหลายสิ่งที่คุณสามารถทำได้กับพารามิเตอร์หากยังไม่ได้ตั้งค่า

ตัวอย่างเช่น:

function a {
    first_arg=${1-foo}
    # rest of the function
}

จะตั้งค่าfirst_argเท่ากับ$1หากได้รับมอบหมายมิฉะนั้นจะใช้ค่า "foo" หากaต้องใช้พารามิเตอร์ตัวเดียวอย่างแน่นอนและไม่มีค่าเริ่มต้นที่ดีอยู่คุณสามารถออกโดยมีข้อความแสดงข้อผิดพลาดเมื่อไม่มีการระบุพารามิเตอร์:

function a {
    : ${1?a must take a single argument}
    # rest of the function
}

(โปรดสังเกตว่าการใช้:คำสั่ง null ซึ่งเพิ่งขยายค่าของอาร์กิวเมนต์เราไม่ต้องการทำอะไรกับ$1ในตัวอย่างนี้เพียงแค่ออกหากไม่ได้ตั้งค่าไว้)


1
ฉันงงงันว่าไม่มีคำตอบอื่น ๆ : ${var?message}พูดถึงง่ายและสง่างาม
tripleee

คุณเอาสิ่งนี้มาจากไหน ยอดเยี่ยม! มันใช้งานได้! และมันก็สั้นและสง่างาม! ขอบคุณ!
Roger

13

ในทุบตีคุณสามารถใช้ -vภายใน[[ ]]builtin:

#! /bin/bash -u

if [[ ! -v SOMEVAR ]]; then
    SOMEVAR='hello'
fi

echo $SOMEVAR

8

การใช้[[ -z "$var" ]]เป็นวิธีที่ง่ายที่สุดที่จะทราบว่าตัวแปรถูกตั้งค่าหรือไม่ แต่ตัวเลือก-zนั้นไม่แยกความแตกต่างระหว่างตัวแปรที่ไม่ได้ตั้งค่าและตัวแปรที่ตั้งค่าเป็นสตริงว่าง:

$ set=''
$ [[ -z "$set" ]] && echo "Set" || echo "Unset" 
Unset
$ [[ -z "$unset" ]] && echo "Set" || echo "Unset"
Unset

ควรตรวจสอบตามประเภทของตัวแปร: ตัวแปร env, พารามิเตอร์หรือตัวแปรปกติ

สำหรับตัวแปร env:

[[ $(env | grep "varname=" | wc -l) -eq 1 ]] && echo "Set" || echo "Unset"

สำหรับพารามิเตอร์ (ตัวอย่างเช่นเพื่อตรวจสอบการมีอยู่ของพารามิเตอร์$5):

[[ $# -ge 5 ]] && echo "Set" || echo "Unset"

สำหรับตัวแปรปกติ (ใช้ฟังก์ชั่นเสริมให้ทำอย่างหรูหรา):

function declare_var {
   declare -p "$1" &> /dev/null
}
declare_var "var_name" && echo "Set" || echo "Unset"

หมายเหตุ:

  • $#:ช่วยให้คุณจำนวนพารามิเตอร์ตำแหน่ง
  • declare -p:ให้นิยามของตัวแปรที่ส่งผ่านเป็นพารามิเตอร์ หากมีอยู่ให้ส่งคืน 0 ถ้าไม่ส่งคืน 1 และพิมพ์ข้อความแสดงข้อผิดพลาด
  • &> /dev/null:ระงับเอาต์พุตจากdeclare -pโดยไม่มีผลกระทบกับโค้ดส่งคืน

5

คำตอบข้างต้นไม่ทำงานเมื่อset -uเปิดใช้งานตัวเลือก Bash นอกจากนี้ยังไม่มีการเปลี่ยนแปลงเช่นจะกำหนดตัวแปรด้วยชื่อ "จำลอง" ได้อย่างไร ลองสิ่งนี้:

is_var_defined()
{
    if [ $# -ne 1 ]
    then
        echo "Expected exactly one argument: variable name as string, e.g., 'my_var'"
        exit 1
    fi
    # Tricky.  Since Bash option 'set -u' may be enabled, we cannot directly test if a variable
    # is defined with this construct: [ ! -z "$var" ].  Instead, we must use default value
    # substitution with this construct: [ ! -z "${var:-}" ].  Normally, a default value follows the
    # operator ':-', but here we leave it blank for empty (null) string.  Finally, we need to
    # substitute the text from $1 as 'var'.  This is not allowed directly in Bash with this
    # construct: [ ! -z "${$1:-}" ].  We need to use indirection with eval operator.
    # Example: $1="var"
    # Expansion for eval operator: "[ ! -z \${$1:-} ]" -> "[ ! -z \${var:-} ]"
    # Code  execute: [ ! -z ${var:-} ]
    eval "[ ! -z \${$1:-} ]"
    return $?  # Pedantic.
}

ที่เกี่ยวข้อง: ใน Bash ฉันจะทดสอบได้อย่างไรว่าตัวแปรถูกกำหนดในโหมด "-u"


1
ฉันอยากรู้มากว่าทำไมคำตอบนี้จึงลดลง ... ใช้งานได้ดีสำหรับฉัน
LavaScornedOven

ในทุบตีคุณสามารถทำเช่นเดียวกันโดยไม่ต้อง EVAL: การเปลี่ยนแปลงที่จะประเมินผลทางอ้อม:eval "[ ! -z \${$1:-} ]" [ ! -z ${!1:-} ];

@BinaryZebra: แนวคิดที่น่าสนใจ ฉันแนะนำให้คุณโพสต์เป็นคำตอบที่แยกต่างหาก
kevinarpe

การใช้ "eval" ทำให้วิธีนี้มีความเสี่ยงต่อการฉีดโค้ด: $ is_var_defined 'x}]; echo "gotcha"> & 2; # 'gotcha
tetsujin

4

คุณทำได้:

function a {
        if [ ! -z "$1" ]; then
                echo '$1 is set'
        fi
}

9
หรือคุณอาจจะทำและไม่ได้คัดค้าน-n -z
หยุดชั่วคราวจนกว่าจะมีการแจ้งให้ทราบต่อไป

1
คุณต้องการคำพูดรอบคือ$1 [ ! -z "$1" ]หรือคุณสามารถเขียนเป็น[[ ! -z $1 ]]bash / ksh / zsh
Gilles 'หยุดความชั่วร้าย'

5
สิ่งนี้จะล้มเหลวหาก$1ตั้งค่าเป็นสตริงว่าง
HelloGoodbye

4

วิธีที่ฉันชอบคือ:

$ var=10
$ if ! ${var+false};then echo "is set";else echo "NOT set";fi
is set
$ unset -v var
$ if ! ${var+false};then echo "is set";else echo "NOT set";fi
NOT set

โดยพื้นฐานแล้วหากตั้งค่าตัวแปรมันจะกลายเป็น "การปฏิเสธของผลลัพธ์false" (สิ่งที่จะเป็นtrue = "ถูกตั้งค่า")

และหากไม่ได้ตั้งค่ามันจะกลายเป็น "การปฏิเสธของผลลัพธ์true" (เมื่อผลลัพธ์ว่างเปล่าประเมินเป็นtrue) (ดังนั้นจะสิ้นสุดเป็นfalse= "ไม่ได้ตั้งค่า")



1

ในเชลล์คุณสามารถใช้-zโอเปอเรเตอร์ซึ่งเป็น True หากความยาวของสตริงเป็นศูนย์

ซับในแบบง่ายเพื่อตั้งค่าเริ่มต้นMY_VARหากยังไม่ได้ตั้งค่ามิฉะนั้นคุณสามารถแสดงข้อความได้:

[[ -z "$MY_VAR" ]] && MY_VAR="default"
[[ -z "$MY_VAR" ]] && MY_VAR="default" || echo "Variable already set."

0
if [[ ${1:+isset} ]]
then echo "It was set and not null." >&2
else echo "It was not set or it was null." >&2
fi

if [[ ${1+isset} ]]
then echo "It was set but might be null." >&2
else echo "It was was not set." >&2
fi

$1, $2และขึ้นไป$Nตั้งเสมอ ขออภัยนี่ล้มเหลว

ฉันลองแล้วและใช้งานไม่ได้บางทีเวอร์ชันทุบตีของฉันอาจขาดการสนับสนุน IDk ขออภัยถ้าฉันผิด :)

0

ผมพบว่า (มาก) $@รหัสดีกว่าที่จะทำเช่นนี้หากคุณต้องการที่จะตรวจสอบอะไรใน

ถ้า [[1 $ = ""]]
แล้วก็
  echo '$ 1 ว่างเปล่า'
อื่น
  echo '$ 1 เต็มแล้ว'
Fi

ทำไมทั้งหมดนี้ ทุกอย่างใน$@ที่มีอยู่ในทุบตี แต่โดยปกติก็ว่างเปล่าดังนั้นtest -zและtest -nไม่สามารถช่วยคุณ

อัปเดต:คุณยังสามารถนับจำนวนอักขระในพารามิเตอร์

ถ้า [$ {# 1} = 0]
แล้วก็
  echo '$ 1 ว่างเปล่า'
อื่น
  echo '$ 1 เต็มแล้ว'
Fi

ฉันรู้ แต่นั่นมัน หากบางสิ่งว่างเปล่าคุณจะได้รับข้อผิดพลาด! ขอโทษ : P

0
if [[ ${!xx[@]} ]] ; then echo xx is defined; fi

11
ยินดีต้อนรับสู่ StackOverflow ในขณะที่คำตอบของคุณได้รับการชื่นชมจะดีที่สุดที่จะให้มากกว่าแค่รหัส คุณสามารถเพิ่มการให้เหตุผลกับคำตอบหรือคำอธิบายเล็กน้อยได้หรือไม่? ดูหน้านี้สำหรับแนวคิดอื่น ๆ เกี่ยวกับการขยายคำตอบของคุณ
Celeo

0

นี่คือสิ่งที่ฉันใช้ทุกวัน:

#
# Check if a variable is set
#   param1  name of the variable
#
function is_set()
{
    [[ -n "${1}" ]] && test -n "$(eval "echo "\${${1}+x}"")"
}

สิ่งนี้ทำงานได้ดีภายใต้ Linux และ Solaris จนถึง bash 3.0

bash-3.00$ myvar="TEST"
bash-3.00$ is_set myvar ; echo $?
0
bash-3.00$ mavar=""
bash-3.00$ is_set myvar ; echo $?
0
bash-3.00$ unset myvar
bash-3.00$ is_set myvar ; echo $?
1

1
เนื่องจากมีการขยาย Bash 2.0+ โดยอ้อม คุณสามารถแทนที่ความยาวและความซับซ้อน (ด้วยการรวม eval) test -n "$(eval "echo "\${${1}+x}"")"สำหรับเทียบเท่า:[[ ${!1+x} ]]

0

ฉันชอบฟังก์ชั่นเสริมเพื่อซ่อนรายละเอียดที่หยาบของ bash ในกรณีนี้การทำเช่นนั้นจะเพิ่มความหยาบ (ซ่อนเร้น) ให้มากขึ้น:

# The first ! negates the result (can't use -n to achieve this)
# the second ! expands the content of varname (can't do ${$varname})
function IsDeclared_Tricky
{
  local varname="$1"
  ! [ -z ${!varname+x} ]
}

เนื่องจากฉันมีข้อบกพร่องในการใช้งานครั้งแรก (ได้รับแรงบันดาลใจจากคำตอบของ Jens และ Lionel) ฉันจึงคิดวิธีแก้ปัญหาที่แตกต่างกัน:

# Ask for the properties of the variable - fails if not declared
function IsDeclared()
{
  declare -p $1 &>/dev/null
}

ฉันคิดว่ามันจะตรงไปตรงมามากขึ้น bashy และง่ายต่อการเข้าใจ / จำ กรณีทดสอบแสดงให้เห็นว่ามันเทียบเท่า:

function main()
{
  declare -i xyz
  local foo
  local bar=
  local baz=''

  IsDeclared_Tricky xyz; echo "IsDeclared_Tricky xyz: $?"
  IsDeclared_Tricky foo; echo "IsDeclared_Tricky foo: $?"
  IsDeclared_Tricky bar; echo "IsDeclared_Tricky bar: $?"
  IsDeclared_Tricky baz; echo "IsDeclared_Tricky baz: $?"

  IsDeclared xyz; echo "IsDeclared xyz: $?"
  IsDeclared foo; echo "IsDeclared foo: $?"
  IsDeclared bar; echo "IsDeclared bar: $?"
  IsDeclared baz; echo "IsDeclared baz: $?"
}

main

กรณีการทดสอบยังแสดงให้เห็นว่าlocal varไม่ไม่ประกาศ var (เว้นแต่ตามด้วย '=') สำหรับบางครั้งที่ฉันคิดว่าฉันประกาศตัวแปรด้วยวิธีนี้เพียงเพื่อค้นพบตอนนี้ที่ฉันเพียงแสดงความตั้งใจของฉัน ... มันเป็นไม่มี -op ฉันเดา

IsDeclared_Tricky xyz: 1
foo IsDeclared_Tricky: 1
IsDeclared_Tricky บาร์: 0
IsDeclared_Tricky baz: 0
IsDeclared xyz: 1
foo IsDeclared: 1
บาร์ IsDeclared: 0
baz IsDeclared: 0

โบนัส: usecase

ฉันส่วนใหญ่ใช้การทดสอบนี้เพื่อให้ (และกลับ) พารามิเตอร์การทำงานในค่อนข้าง "สง่างาม" และวิธีที่ปลอดภัย (เกือบคล้ายอินเทอร์เฟซ ... ):

#auxiliary functions
function die()
{
  echo "Error: $1"; exit 1
}

function assertVariableDeclared()
{
  IsDeclared "$1" || die "variable not declared: $1"
}

function expectVariables()
{
  while (( $# > 0 )); do
    assertVariableDeclared $1; shift
  done
}

# actual example
function exampleFunction()
{
  expectVariables inputStr outputStr
  outputStr="$inputStr world!"
}

function bonus()
{
  local inputStr='Hello'
  local outputStr= # remove this to trigger error
  exampleFunction
  echo $outputStr
}

bonus

หากเรียกด้วยตัวแปรทั้งหมดจะต้องมีการประกาศ:

สวัสดีชาวโลก!

อื่น:

ข้อผิดพลาด: ไม่ได้ประกาศตัวแปร: outputStr


0

หลังจากอ่านคำตอบทั้งหมดแล้วก็สามารถใช้งานได้:

if [[ -z $SOME_VAR ]]; then read -p "Enter a value for SOME_VAR: " SOME_VAR; fi
echo "SOME_VAR=$SOME_VAR"

หากคุณไม่ใส่SOME_VARแทนสิ่งที่ฉันมี$SOME_VARมันจะตั้งเป็นค่าว่าง $จำเป็นสำหรับสิ่งนี้ในการทำงาน


จะไม่ทำงานเมื่อคุณมีset -uผลบังคับใช้ซึ่งจะพิมพ์unboud variableข้อผิดพลาด
Michael Heuberger

-1

เพื่อตรวจสอบว่ามีการตั้งค่า var หรือไม่

var=""; [[ $var ]] && echo "set" || echo "not set"

3
สิ่งนี้จะล้มเหลวหาก$varตั้งค่าเป็นสตริงว่าง
HelloGoodbye

-1

หากคุณต้องการทดสอบว่าตัวแปรถูกผูกไว้หรือไม่ถูกผูกมัดสิ่งนี้จะทำงานได้ดีแม้หลังจากที่คุณเปิดใช้งานตัวเลือกคำนาม:

set -o noun set

if printenv variableName >/dev/null; then
    # variable is bound to a value
else
    # variable is unbound
fi

ฉันคิดว่าคุณหมายถึงไม่ได้set -o nounset set -o noun setใช้งานได้กับตัวแปรที่มีการexportแก้ไขเท่านั้น นอกจากนี้ยังเปลี่ยนการตั้งค่าของคุณในลักษณะที่ไม่เหมาะสมที่จะเลิกทำ
Keith Thompson

-1

ฉันมักจะใช้อันนี้ตามความจริงที่ว่าทุกคนที่เห็นรหัสเป็นเรื่องง่ายที่จะเข้าใจได้ง่าย:

if [ "$variable" = "" ]
    then
    echo "Variable X is empty"
fi

และหากต้องการตรวจสอบว่าไม่ว่างเปล่า

if [ ! "$variable" = "" ]
    then
    echo "Variable X is not empty"
fi

แค่นั้นแหละ.


4
คำถามจะถามว่าจะตรวจสอบว่ามีการตั้งค่าตัวแปรหรือไม่หากตัวแปรนั้นว่างเปล่า
HelloGoodbye

คุณอาจจะต้องใช้แทน[[ ... ]] [ ... ]อันที่จริงแล้วเป็นคำสั่งภายนอกและจะไม่สามารถมองเห็นได้ว่ามีการตั้งค่าตัวแปรหรือไม่
solidsnack
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.