ความหมายของข้อผิดพลาด“ [: มีอาร์กิวเมนต์มากเกินไป” จากถ้า [] (วงเล็บเหลี่ยม)


212

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

ข้อผิดพลาด:

-bash: [: too many arguments

รุ่นที่เหมาะกับ bash open square bracket colon too many argumentsGoogle:

บริบท:เงื่อนไข if ในวงเล็บเหลี่ยมเดียวที่มีตัวดำเนินการเปรียบเทียบอย่างง่ายเช่นเท่ากับมากกว่า ฯลฯ ตัวอย่างเช่น:

VARIABLE=$(/some/command);
if [ $VARIABLE == 0 ]; then
  # some action
fi 

1
รหัสที่สร้างข้อผิดพลาดเฉพาะนี้อยู่ที่ไหน
Anderson Green

คำตอบ:


354

หาก$VARIABLEสตริงของคุณมีช่องว่างหรืออักขระพิเศษอื่น ๆและมีการใช้วงเล็บเหลี่ยมเดียว (ซึ่งเป็นทางลัดสำหรับtestคำสั่ง) สตริงนั้นอาจถูกแยกออกเป็นหลายคำ แต่ละข้อถือเป็นอาร์กิวเมนต์แยกต่างหาก

ดังนั้นตัวแปรหนึ่งตัวจะถูกแบ่งออกเป็นหลาย ๆ อาร์กิวเมนต์ :

VARIABLE=$(/some/command);  
# returns "hello world"

if [ $VARIABLE == 0 ]; then
  # fails as if you wrote:
  # if [ hello world == 0 ]
fi 

เช่นเดียวกันจะเป็นจริงสำหรับการเรียกใช้ฟังก์ชันใด ๆ ที่วางสตริงที่มีช่องว่างหรืออักขระพิเศษอื่น ๆ


แก้ไขได้ง่าย

ล้อมรอบตัวแปรเอาต์พุตด้วยอัญประกาศคู่บังคับให้อยู่ในสตริงเดียว (ดังนั้นจึงมีหนึ่งอาร์กิวเมนต์) ตัวอย่างเช่น,

VARIABLE=$(/some/command);
if [ "$VARIABLE" == 0 ]; then
  # some action
fi 

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


หรือการแก้ไขทางเลือกคือการใช้วงเล็บเหลี่ยมสองชั้น (ซึ่งเป็นทางลัดสำหรับnew testคำสั่ง)

สิ่งนี้มีอยู่ใน bash เท่านั้น (และเห็นได้ชัดว่า korn และ zsh) และอาจไม่สามารถทำงานร่วมกับเชลล์เริ่มต้นที่ถูกเรียก/bin/shเป็นต้น

ซึ่งหมายความว่าในบางระบบอาจใช้งานได้จากคอนโซล แต่ไม่ใช่เมื่อมีการโทรไปที่อื่นเช่นจากcronขึ้นอยู่กับการกำหนดค่าทุกอย่าง

มันจะมีลักษณะเช่นนี้:

VARIABLE=$(/some/command);
if [[ $VARIABLE == 0 ]]; then
  # some action
fi 

ถ้าคำสั่งของคุณมีวงเล็บคู่เช่นนี้และคุณได้รับข้อผิดพลาดในบันทึก แต่การทำงานจากคอนโซลลองสลับออก[[หาทางเลือกแนะนำที่นี่หรือตรวจสอบให้แน่ใจว่าสิ่งที่เรียกใช้สคริปต์ของคุณใช้เปลือกที่สนับสนุนอาคา[[new test


ยังระวัง[: unary operator expectedข้อผิดพลาด

หากคุณเห็นข้อผิดพลาด "มีอาร์กิวเมนต์มากเกินไป" โอกาสที่คุณจะได้รับสตริงจากฟังก์ชันที่มีเอาต์พุตที่ไม่สามารถคาดเดาได้ หากเป็นไปได้ที่จะได้รับสตริงว่าง (หรือสตริงช่องว่างทั้งหมด) นี่จะถือว่าเป็นศูนย์อาร์กิวเมนต์แม้ว่าจะมี "การแก้ไขด่วน" ข้างต้นและอาจล้มเหลวด้วย[: unary operator expected

ก็เหมือนกับ 'gotcha' ถ้าคุณคุ้นเคยกับภาษาอื่น - คุณไม่คาดหวังว่าเนื้อหาของตัวแปรจะพิมพ์ลงในรหัสอย่างมีประสิทธิภาพเช่นนี้ก่อนที่จะถูกประเมิน

นี่คือตัวอย่างที่ป้องกันไม่ให้ทั้งสอง[: too many argumentsและ[: unary operator expectedข้อผิดพลาด: เปลี่ยนเอาท์พุทที่มีค่าเริ่มต้นถ้ามันเป็นที่ว่างเปล่า (ในตัวอย่างนี้0) กับคำพูดสองห่อรอบสิ่งทั้งหมด:

VARIABLE=$(/some/command);
if [ "${VARIABLE:-0}" == 0 ]; then
  # some action
fi 

(ที่นี่การกระทำจะเกิดขึ้นหาก $ VARIABLE เป็น 0 หรือว่างเปล่าโดยธรรมชาติคุณควรเปลี่ยน 0 (ค่าเริ่มต้น) เป็นค่าเริ่มต้นอื่นหากต้องการพฤติกรรมที่แตกต่างกัน)


หมายเหตุสุดท้าย:เนื่องจาก[เป็นทางลัดสำหรับtestทั้งหมดข้างต้นจึงเป็นจริงสำหรับข้อผิดพลาดtest: too many arguments(และยังtest: unary operator expected)


วิธีที่ดีกว่าคือi=$(some_command); i=$((i)); if [ "$i" == 0 ] ...
Jo So

1
ฉันประสบปัญหาที่ Shellscript ใช้ BASH เป็นล่ามเมื่อดำเนินการผ่านเทอร์มินัลก็โอเค แต่เมื่อดำเนินการผ่าน Crontab มีความล้มเหลวเช่นนี้และส่งอีเมลท้องถิ่นผ่านทาง Postfix แจ้งข้อผิดพลาดนี้และฉันก็พบว่ามี IF สำหรับตัวแปรที่มีอักขระพิเศษ คำพูดคู่ช่วยชีวิตฉันไว้ ขอบคุณ :)!
ivanleoncz

13

เพิ่งชนกับโพสต์นี้โดยได้รับข้อผิดพลาดเดียวกันพยายามทดสอบว่าตัวแปรทั้งสองนั้นว่างเปล่า (หรือไม่ว่างเปล่า) มันกลายเป็นการเปรียบเทียบแบบผสม - 7.3 ตัวดำเนินการเปรียบเทียบอื่น ๆ - คู่มือการใช้สคริปต์ Bash ขั้นสูง ; และฉันคิดว่าฉันควรทราบสิ่งต่อไปนี้:

  • ฉันเคย-eคิดว่ามันแปลว่า "ว่าง" ในตอนแรก แต่นั่นหมายถึง "ไฟล์ที่มีอยู่" - ใช้-zสำหรับทดสอบตัวแปรว่าง(สตริง)
  • ต้องระบุตัวแปรสตริง
  • สำหรับสารประกอบเชิงตรรกะและการเปรียบเทียบทั้ง:
    • ใช้สองtests และ&&พวกเขา:[ ... ] && [ ... ]
    • หรือใช้-aโอเปอเรเตอร์ในครั้งเดียวtest:[ ... -a ... ]

นี่คือคำสั่งที่ใช้งานได้ (การค้นหาไฟล์ txt ทั้งหมดในไดเรกทอรีและการดัมพ์ไฟล์ที่grepพบมีทั้งสองคำ):

find /usr/share/doc -name '*.txt' | while read file; do \
  a1=$(grep -H "description" $file); \
  a2=$(grep -H "changes" $file); \
  [ ! -z "$a1" -a ! -z "$a2"  ] && echo -e "$a1 \n $a2" ; \
done

แก้ไข 12 สิงหาคม 2556: หมายเหตุปัญหาที่เกี่ยวข้อง:

โปรดทราบว่าเมื่อตรวจสอบความเท่าเทียมกันของสตริงด้วยคลาสสิกtest(วงเล็บสี่เหลี่ยมจัตุรัสเดี่ยว[) คุณต้องมีช่องว่างระหว่างตัวดำเนินการ "เท่ากับ" ซึ่งในกรณีนี้คือเครื่องหมาย "เท่ากับ" เดียว=(แม้ว่าเครื่องหมายทั้งสอง==ดูเหมือนจะยอมรับว่าเท่าเทียมกัน ผู้ประกอบการเกินไป) ดังนั้นสิ่งนี้จึงล้มเหลว (เงียบ ๆ ):

$ if [ "1"=="" ] ; then echo A; else echo B; fi 
A
$ if [ "1"="" ] ; then echo A; else echo B; fi 
A
$ if [ "1"="" ] && [ "1"="1" ] ; then echo A; else echo B; fi 
A
$ if [ "1"=="" ] && [ "1"=="1" ] ; then echo A; else echo B; fi 
A

... แต่เพิ่มพื้นที่ - และทั้งหมดก็ดูดี:

$ if [ "1" = "" ] ; then echo A; else echo B; fi 
B
$ if [ "1" == "" ] ; then echo A; else echo B; fi 
B
$ if [ "1" = "" -a "1" = "1" ] ; then echo A; else echo B; fi 
B
$ if [ "1" == "" -a "1" == "1" ] ; then echo A; else echo B; fi 
B

คุณสามารถให้ตัวอย่างเปลือก bash ของ((A || B) && C)?
jww

โปรดดูคำถาม3826425และ14964805
2559

สิ่งนี้ไม่ได้มีประโยชน์สำหรับคำตอบเพราะมันไม่ได้แสดงวิธีการบรรจุคำสั่งอย่างสมบูรณ์ภายในวงเล็บเหลี่ยมซึ่งเป็นสิ่งจำเป็นหากมีลูป
Timothy Swan

5

สถานการณ์อื่นที่คุณสามารถได้รับ[: too many argumentsหรือ[: a: binary operator expectedข้อผิดพลาดคือถ้าคุณพยายามทดสอบอาร์กิวเมนต์ทั้งหมด"$@"

if [ -z "$@" ]
then
    echo "Argument required."
fi

มันทำงานได้อย่างถูกต้องถ้าคุณโทรหรือfoo.sh foo.sh arg1แต่ถ้าคุณผ่านหลายอย่างเช่นfoo.sh arg1 arg2คุณจะได้รับข้อผิดพลาด นี่เป็นเพราะกำลังขยายไป[ -z arg1 arg2 ]ซึ่งไม่ใช่ไวยากรณ์ที่ถูกต้อง

[ "$#" -eq 0 ]วิธีที่ถูกต้องในการตรวจสอบสำหรับการดำรงอยู่ของการขัดแย้งคือ ( $#คือจำนวนอาร์กิวเมนต์)


2

บางครั้งถ้าคุณสัมผัสแป้นพิมพ์โดยไม่ได้ตั้งใจและลบช่องว่าง

if [ "$myvar" = "something"]; then
    do something
fi

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


1
ฉันคิดว่าผลลัพธ์ในข้อผิดพลาดทางไวยากรณ์ที่แตกต่างกันเช่น: บรรทัดที่ 21: [: ขาดหายไป `] '
โจฮอลโลเวย์

1

ฉันมีปัญหาเดียวกันกับสคริปต์ของฉัน แต่เมื่อฉันทำการแก้ไขมันทำให้ฉัน ฉันทำสิ่งนี้: -

export k=$(date "+%k");
if [ $k -ge 16 ] 
    then exit 0; 
else 
    echo "good job for nothing"; 
fi;

ทางฉันแก้ไขปัญหาของฉัน หวังว่าจะช่วยคุณได้เช่นกัน

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