ข้อผิดพลาดทางไวยากรณ์ใกล้กับโทเค็น `fi 'ที่ไม่คาดคิด


17

ฉันไม่ได้ต้องการคำตอบ แต่ถ้ามีคนสามารถชี้ให้ฉันไปที่วรรณกรรมหรือตัวอย่าง ฉันต้องการที่จะคิดออก

เมื่อฉันเรียกใช้สคริปต์ฉันได้รับข้อผิดพลาด:

ข้อผิดพลาดทางไวยากรณ์ใกล้โทเค็นที่ไม่คาดคิด fi

ฉันได้อนุมานได้ว่าปัญหาของฉันของฉันอยู่ในifคำสั่งโดยการทำของฉันifงบแสดงความคิดเห็นและการเพิ่มซึ่งจะแสดงชื่อที่อยู่ในนั้นecho "$NAME"/etc/

เมื่อฉันทำการเปลี่ยนแปลงให้ลบออก#จากifและfiเพิ่ม#ใน wc -c "$NAME"ฉันได้รับข้อผิดพลาดทางไวยากรณ์ที่ฉันระบุไว้ข้างต้น ฉันได้เพิ่ม;ระหว่าง]นั้น ฉันได้ย้ายไปthenยังบรรทัดถัดไปโดยไม่มีความละเอียด

#!/bin/bash
for NAME in /etc/*
do

     if [ -r "$NAME" -af "$NAME" ] then
          wc -c "$NAME"
     fi
done

9
เมื่อใดก็ตามที่คุณมีข้อผิดพลาดทางไวยากรณ์ของเชลล์ขั้นตอนแรกที่ดีคือการตัดและวางรหัสของคุณลงในshellcheck.netและแก้ไขข้อผิดพลาดที่ระบุ หากคุณมีปัญหาในการทำความเข้าใจข้อความจากนั้นมาที่นี่และถาม
John1024

2
สิ่งที่-afควรทำ
ilkkachu

ขอบคุณสำหรับไซต์ที่ @ John1024 มันมีประโยชน์มากที่สุดฉันได้ทำบุ๊กมาร์กไว้เพื่อใช้อ้างอิงในอนาคต
Christina A Guzman

1
@ChristinaAGuzman ในกรณีเช่นนี้จะซ้ำซ้อนเพราะเงื่อนไขที่รวมอยู่ภายใน-a -f--- หลายเงื่อนไขอย่างไรก็ตามภายใน[ ](คำสั่งนี้ยังมีอยู่เป็นtest) จะต้องมีการเข้าร่วมโดยใช้ดำเนินการทางตรรกะเช่น-a(และ) หรือ-o(หรือ) แต่มันได้รับการแนะนำในการตอบกลับที่อยู่ด้านล่างมันจะดีกว่าที่จะใช้หลาย[ ]( test) คำสั่งและเข้าร่วม พวกเขาใช้ประกอบเปลือกชอบหรือ&& ||
pabouk

2
Christina ดังที่ระบุไว้ @ John1024, shellcheck.netแสดงให้เห็นอย่างชัดเจนว่ามีไวยากรณ์หรือข้อผิดพลาดที่ลึกซึ้งยิ่งขึ้น ฉันยังแนะนำให้อ่าน: mywiki.wooledge.org/BashPitfalls (อ่านอย่างน้อยหนึ่งครั้ง!) และmywiki.wooledge.org/BashFAQและmywiki.wooledge.org/BashGuideก็อ่านได้ดีเช่นกัน
Olivier Dulac

คำตอบ:


46

คำหลักเช่นif, then, else, fi, for, caseและอื่น ๆ ที่จำเป็นต้องอยู่ในสถานที่ที่คาดว่าเปลือกชื่อคำสั่งที่ มิฉะนั้นจะถือว่าเป็นคำทั่วไป ตัวอย่างเช่น,

echo if

เพียงพิมพ์ifมันไม่ได้เริ่มคำสั่งตามเงื่อนไข

ดังนั้นในสาย

if [ -r "$NAME" -af "$NAME" ] then

คำthenนั้นเป็นอาร์กิวเมนต์ของคำสั่ง[(ซึ่งมันจะบ่นเกี่ยวกับว่ามันจะต้องวิ่ง) เชลล์ทำการค้นหาthenและค้นหาfiตำแหน่งคำสั่ง in นับตั้งแต่มีการifที่ยังคงมองหาของthenที่fiไม่คาดคิดมีข้อผิดพลาดทางไวยากรณ์

คุณต้องใส่ตัวยกเลิกคำสั่งก่อนthenเพื่อให้เป็นที่รู้จักว่าเป็นคำหลัก ตัวยกเลิกคำสั่งที่ใช้กันทั่วไปส่วนใหญ่คือตัวแบ่งบรรทัด แต่ก่อนหน้าthenนี้เป็นเรื่องปกติที่จะใช้เครื่องหมายอัฒภาค (ซึ่งมีความหมายเหมือนกับตัวแบ่งบรรทัด)

if [ -r "$NAME" -af "$NAME" ]; then

หรือ

if [ -r "$NAME" -af "$NAME" ]
then

เมื่อคุณแก้ไขปัญหาที่คุณจะได้รับข้อผิดพลาดอื่นจากคำสั่งเพราะมันไม่เข้าใจ[ -afคุณน่าจะหมายถึง

if [ -r "$NAME" -a -f "$NAME" ]; then

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

อย่างไรก็ตามถึง[ -r "$NAME" -a -f "$NAME" ]อย่างไรฉันก็แนะนำให้เขียนเช่นกัน

[ -r "$NAME" ] && [ -f "$NAME" ]

หรือ

[[ -r $NAME && -f $NAME ]]

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

ไวยากรณ์ที่สองใช้โครงสร้างแบบมี[[ … ]]เงื่อนไขซึ่งมีอยู่ใน bash (และ ksh และ zsh แต่ไม่ใช่ sh แบบธรรมดา) โครงสร้างนี้ถูกไวยากรณ์พิเศษในขณะที่[จะแยกกันเช่นคำสั่งอื่นใดที่ทำให้คุณสามารถใช้สิ่งที่ต้องการ&&ทั้งภายในและคุณไม่จำเป็นต้องอ้างตัวแปรยกเว้นในข้อโต้แย้งกับผู้ประกอบการบางสตริง ( =, ==, !=, =~) (ดูเมื่อสองครั้ง quoting จำเป็น ?สำหรับรายละเอียด)


โปรดทราบว่าif [[ 1 ]] then [[ 2 ]] fiทำงานใน ksh, pdksh และ zsh if(:)then(:)fiใช้ได้กับทุกเชลล์
Stéphane Chazelas

12

ดูว่ามีอะไรเปลี่ยนแปลงดังนี้

ถ้า [-r "$ NAME" -a -f "$ NAME"] ; แล้วก็
# ^^^^^ ^ ^
     wc -c "$ NAME"
Fi

หากคุณต้องการลบคำสั่งทั้งหมดใน if block อย่างน้อยคุณต้องเพิ่มโคลอนในคำสั่งนั้น

if [ -r "$NAME" -a -f "$NAME" ]; then
    :
fi

หรือรุ่นหนึ่งบรรทัด

if [ -r "$NAME" -a -f "$NAME" ]; then :; fi


2

คนอื่น ๆ ชี้ไปแล้ว แต่ถ้าคุณกำลังมองหาการอ้างอิงอย่างเป็นทางการแล้วRTM

ถ้ารายการ; จากนั้นทำรายการ [รายการเอลฟ์; จากนั้นทำรายการ ] ... [รายการอื่น;] fi

รายการ if จะถูกดำเนินการ หากสถานะการออกเป็นศูนย์รายการนั้นจะถูกดำเนินการ มิฉะนั้นรายการ elif แต่ละรายการจะถูกดำเนินการตามลำดับและหากสถานะการออกเป็นศูนย์รายการที่เกี่ยวข้องนั้นจะถูกดำเนินการและคำสั่งจะเสร็จสมบูรณ์ มิฉะนั้นรายการอื่นจะถูกดำเนินการถ้ามี สถานะการออกคือสถานะการออกของคำสั่งสุดท้ายที่ดำเนินการหรือเป็นศูนย์หากไม่มีการทดสอบเงื่อนไขจริง

คุณกำลังคิดถึง ;

และไวยากรณ์สำหรับlistอธิบายไว้ในman test

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