ใช้ $ หรือเปล่า ในคำสั่ง if


12
function foo {
   (cd $FOOBAR;
   <some command>
   if [$? -ne 0]
   then
      echo "Nope!"
   else
      echo "OK!"
   fi
   )
}

ฉันพยายามเขียนฟังก์ชั่นแบบเดียวกับข้างบนและวางไว้ในไฟล์. bashrc ของฉัน หลังจากที่ฉันส่งไฟล์และเรียกใช้ฉันจะได้รับ:

เวลาทั้งหมด: 51 วินาที
-bash: [1: ไม่พบคำสั่ง
ตกลง!

มีใครช่วยฉันเข้าใจสิ่งที่ฉันทำผิดหรือเปล่า?


4
การทดสอบว่า$?เท่ากับ 0 โดยที่ifstatement นั้นไม่มีจุดหมายifคาดว่าจะมีคำสั่งและถ้าคำสั่งดังกล่าวส่งคืน0จะรันรหัสในบล็อก เพื่อif true; then echo hello; fiจะสะท้อนสวัสดีตั้งแต่คำสั่งกลับtrue 0
llua

1
@llua มันไม่มีจุดหมาย $?มีสถานะเป็นสุดท้ายท่อซึ่งไม่ได้test( [คำสั่ง) ในifคำสั่ง ตัวอย่างคือการทดสอบว่าsome commandสำเร็จหรือไม่ คุณสามารถทำเช่นเดียวกันกับ&&และแต่ก็สามารถทำให้ยาวสายไม่สามารถอ่านได้เมื่อเทียบกับ|| if [ $? -eq 0 ]อาร์กิวเมนต์เดียวกันเริ่มต้นif some command
bonsaiviking

@bonsaiviking ฉันตระหนักดีถึงสิ่งที่$?ขยายออกไปฉันกำลังชี้ให้เห็นว่าไม่มีประโยชน์ในtestการใช้; ตั้งแต่if some commandสิ่งเดียวกันกับหนึ่งคำสั่งเมื่อเทียบกับที่มีสองคำสั่งแยกกัน หากคำสั่งนั้นมีความยาวอยู่แล้วการเพิ่มตัวละครอีกสามตัวจะไม่ทำให้ 'อ่านไม่ได้' ยิ่งกว่านั้นอ่านไม่ได้อีกมาก
llua

คำตอบ:


33

เพิ่มช่องว่างหลัง[และอีกช่องก่อน]:

function foo {
   (cd $FOOBAR;
   <some command>
   if [ $? -ne 0 ]
   then
      echo "Nope!"
   else
      echo "OK!"
   fi
   )
}

[เป็น builtin เปลือกมันเป็นคำสั่งเช่นเดียวกับecho, read, expr... ]มันต้องการพื้นที่หลังจากที่มันและต้องจับคู่

เขียน[ $? -ne 0 ]เป็นจริงกล่าวอ้าง[และให้มัน 4 พารามิเตอร์: $?, -ne, และ0]

หมายเหตุ: ความจริงที่ว่าคุณจะได้รับข้อผิดพลาดว่า[1: command not foundหมายความว่าก็มีค่าของ$?1


1
ฉันเพิ่งตรวจสอบว่าคำตอบของคุณถูกต้องบน Linux VM ของฉัน
samiam

[เป็นลิงก์ไปยังtestเช่นกัน
Ricky Beam

2
@RickyBeam ในเชลล์ส่วนใหญ่[เป็น shell builtin และ/usr/bin/[ไม่ค่อยถูกใช้
แพทริค

20

หรือคุณสามารถข้าม $?ไปเลยก็ได้ หากคำสั่งของคุณคือcmdสิ่งต่อไปนี้ควรใช้งานได้:

function foo {
   (cd $FOOBAR;
   if cmd
   then
      echo "OK!"
   else
      echo "Nope!"
   fi
   )
}

6

เป็นวิธีปฏิบัติที่ดีในการกำหนดค่าตอบแทนให้กับตัวแปรก่อนใช้งาน

retval="$?"
if [ $retval -ne 0 ]

ช่วยให้คุณสามารถใช้ค่าที่ส่งคืน เช่นในคำสั่ง if ... elif ... else ...


-1: คุณลืมช่องว่างหลังจากนั้น[(หากไม่มีช่องว่างจะกลายเป็นข้อผิดพลาดทางไวยากรณ์ในbash) จะยกเลิกหากคุณแก้ไขและแก้ไขข้อผิดพลาด
samiam

ใช่คุณพูดถูก ฉันซ่อมมัน.
อับดุล

@samiam ที่ความคิดเห็นล่าสุดส่งตรงถึงคุณ
terdon

4
:) คุณช่วยขยายคำตอบหน่อยได้ไหม ทำไมจึงเป็นวิธีปฏิบัติที่ดี? ข้อผิดพลาดชนิดใดที่สามารถหลีกเลี่ยงได้
terdon

1
@terdon เป็นวิธีปฏิบัติที่ไม่ถูกต้องที่จะใช้$?โดยตรงเพราะมันจะแตกถ้าคุณเคยแก้ไขสคริปต์ในภายหลังให้วางบรรทัดระหว่างคำสั่งและการ$?ตรวจสอบ
samiam

3

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

until
  cmd
  [ "$?" -gt 1 ]
do
  something
done

ไวยากรณ์สำหรับทุกคนif, while, until... เป็นงบ

if cmd-list1
then cmd-list2
else cmd-list3
fi

ซึ่งทำงานcmd-list2หากcmd-list1ประสบความสำเร็จหรือcmd-list3อย่างอื่น

[ "$?" -eq 0 ]คำสั่งเป็น no-op มันตั้งค่า$?เป็น 0 ถ้า$?เป็น 0 และ$?ไม่ใช่ศูนย์ถ้ามันไม่ใช่ศูนย์

หากคุณต้องการเรียกใช้บางสิ่งหากcmdล้มเหลวนั่นคือ:

if ! cmd
then ...
fi

โดยทั่วไปแล้วคุณไม่จำเป็นต้องมีคนจรจัด$?นับประสาทราบว่าค่าวิธีการหรือtrue falseมีเพียงกรณีเดียวที่ฉันได้กล่าวไว้ข้างต้นหากคุณต้องการแยกแยะค่าเฉพาะหรือถ้าคุณต้องการบันทึกไว้ในภายหลัง (เช่นเพื่อส่งคืนเป็นค่าส่งคืนของฟังก์ชัน) เช่น:

f() {
  cmd; ret=$?
  some cleanup
  return "$ret"
}

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

[ "$?" -ne 0 ]

ไม่[ $? -ne 0 ]ปล่อยให้อยู่คนเดียว[$? -ne 0 ](ซึ่งจะเรียกใช้[คำสั่งหาก$IFSมีอักขระตัวแรกของ$?)

นอกจากนี้โปรดทราบว่าวิธี Bourne ในการกำหนดฟังก์ชั่นคือติดfunction-name()หน้าคำสั่ง เป็นกรณีที่ในทุกบอร์นเหมือนเปลือกยกเว้นbashและyash(และรุ่นล่าสุดของposh) ซึ่งเพียง แต่ช่วยให้คำสั่งผสม (คำสั่งผสมเป็น{...}หรือ(...)หรือสิ่งที่ต้องการfor...done, if...fi...

function foo { ... }เป็นkshไวยากรณ์นิยามฟังก์ชัน ไม่มีเหตุผลใดที่คุณต้องการใช้ที่นี่

รหัสของคุณสามารถเขียนได้แบบพกพา (POSIXly):

foo() (
  cd -P -- "$FOOBAR" || return # what if the cd failed!
  if
    <some command>
  then
    echo 'OK!'
  else
    echo 'Nope!'
  fi
)

นอกจากนี้โปรดทราบว่าcdหากไม่มี-Pความหมายพิเศษมาก (จัดการเส้นทางที่มี..ส่วนประกอบแตกต่างจากคำสั่งอื่น ๆ ) ดังนั้นควรรวมไว้ในสคริปต์เพื่อหลีกเลี่ยงความสับสน

(ฟังก์ชั่นนั้นคืนfalseถ้าcdล้มเหลว แต่ไม่ใช่ถ้า<some command>ล้มเหลว)


1

ฉันเชื่อว่าคำสั่งด้านล่างจะทำทุกอย่างที่คุณต้องการในหนึ่งบรรทัด

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