ในคำตอบสำหรับคำถามนี้เกี่ยวกับความคิดเห็นในการเขียนสคริปต์เชลล์จะมีการระบุว่า:
คำสั่ง null เป็นคำสั่งที่ไม่ทำอะไรเลยอย่างชัดเจน (แต่ไม่ควรใช้สำหรับความคิดเห็น)
สิ่งที่เป็นประโยชน์ของคำสั่งที่ไม่ทำอะไรเลยอย่างแน่นอน?
ในคำตอบสำหรับคำถามนี้เกี่ยวกับความคิดเห็นในการเขียนสคริปต์เชลล์จะมีการระบุว่า:
คำสั่ง null เป็นคำสั่งที่ไม่ทำอะไรเลยอย่างชัดเจน (แต่ไม่ควรใช้สำหรับความคิดเห็น)
สิ่งที่เป็นประโยชน์ของคำสั่งที่ไม่ทำอะไรเลยอย่างแน่นอน?
คำตอบ:
ปกติฉันใช้เป็นtrue
ลูป ฉันคิดว่ามันชัดเจนกว่า:
while true; do
...
done
ที่เดียวที่ฉันพบว่า:
มีประโยชน์จริงๆคือในกรณีที่เป็นงบถ้าคุณต้องการจับคู่บางอย่าง แต่ไม่ต้องการทำอะไรจริง ๆ ตัวอย่างเช่น:
case $answer in
([Yy]*) : ok ;;
(*) echo "stop."; exit 1 ;;
esac
true
สำหรับเงื่อนไข:
สำหรับ NOP
case a in a ) ;; esac
ทุบตียอมรับ มีกระสุนบ้างไหมที่ไม่ยอมรับสิ่งนี้?
case ${var} in value);; *) do_something;; esac
เป็นที่ยอมรับ :
คำสั่งไม่จำเป็นสำหรับกรณีที่ว่างเปล่า
ในขั้นต้นมันถูกใช้เพื่อตรวจสอบว่ามันเป็นโปรแกรมเชลล์เป้าหมายเมื่อเทียบกับโปรแกรมที่คอมไพล์ด้วย C นี่คือก่อนที่ shebang และภาษาสคริปต์หลายภาษา (csh, perl) คุณยังสามารถเรียกใช้สคริปต์โดยเริ่มจาก:
:
$ echo : > /tmp/xyzzy
$ chmod +x /tmp/xyzzy
$ ./xyzzy
โดยทั่วไปจะเรียกใช้สคริปต์กับ $SHELL
(หรือ/bin/sh
)
ตั้งแต่นั้นมาการใช้หลักคือการประเมินข้อโต้แย้ง ฉันยังใช้:
: ${EDITOR:=vim}
เพื่อตั้งค่าเริ่มต้นในสคริปต์
:
มีประโยชน์สำหรับการเขียนลูปที่ต้องถูกยกเลิกจากภายใน
while :
do
...stuff...
done
นี้จะทำงานตลอดไปเว้นแต่break
หรือexit
ที่เรียกว่าหรือเปลือกได้รับสัญญาณยุติ
while true; do ...; done
สื่อสารความตั้งใจกับผู้อ่านดีกว่าwhile :; do ...; done
เมื่อคุณต้องการคำสั่ง "เว้นแต่" ในการเขียนสคริปต์เชลล์คุณอาจใช้เงื่อนไข "ไม่" ซึ่งสามารถดูโง่ ๆ สำหรับการทดสอบบางอย่างหรือคุณใช้ ':' ในประโยคจริงด้วยรหัสจริงในเท็จ - ประโยค
if [ some-exotic-condition ]
then
:
else
# Real code here
fi
"สภาพที่แปลกใหม่" อาจเป็นสิ่งที่คุณไม่ต้องการที่จะปฏิเสธหรือนั่นชัดเจนกว่าถ้าคุณไม่ใช้ "ตรรกะเชิงลบ"
autoconf
เพราะมันง่ายกว่ามากที่จะเพิ่มค่าเริ่มต้น:
สำหรับสาขาที่ว่างเปล่ากว่าที่จะคิดออกวิธีการย้อนกลับเงื่อนไข
!
ตรงหน้า[ some-exotic-condition ]
เป็นเรื่องโง่ แต่สิ่งที่ฟุ่มเฟือย: else
หลังจากนั้นไม่ใช่เรื่องไร้สาระ
!
โทเค็ขัดแย้งองค์ประกอบท่อคำสั่งทั้งหมด หรือwhile ! grep ... ; do ... done
if ! [ ... ] ; then ... fi
มันเป็นพื้นนอกtest/[]
ไวยากรณ์ ดู: pubs.opengroup.org/onlinepubs/9699919799/utilities/…
ฉันเคยใช้สิ่งนี้นอกเหนือจาก # อักขระสำหรับใส่เครื่องหมายบรรทัดชั่วคราวในสถานการณ์ที่การคอมเม้นต์บรรทัดทำให้เกิดข้อผิดพลาดทางไวยากรณ์เนื่องจากข้อบกพร่องในไวยากรณ์ไวยากรณ์ไม่อนุญาตให้มีลำดับของคำสั่งที่ว่างเปล่า :
if condition ; then
:# temporarily commented out command
fi
หากไม่มี: เรามีลำดับคำสั่งที่หายไปซึ่งเป็นข้อผิดพลาดทางไวยากรณ์
มีสองกรณีที่ฉันพบว่า:
มีประโยชน์:
#!/bin/sh
# set VAR to "default value" if not already set in the environment
: "${VAR=default value}"
# print the value of the VAR variable. Note that POSIX says the behavior
# of echo is implementation defined if the first argument is '-n' or if any
# argument contains a '\', so use printf instead of echo.
printf '%s\n' "VAR=${VAR}"
นี่เป็นวิธีที่สะดวกในการอนุญาตให้ผู้ใช้เชลล์สคริปต์ของคุณแทนที่การตั้งค่าโดยไม่ต้องแก้ไขสคริปต์ (อย่างไรก็ตามอาร์กิวเมนต์บรรทัดคำสั่งจะดีกว่าเพราะคุณไม่เสี่ยงต่อพฤติกรรมที่ไม่คาดคิดหากผู้ใช้มีตัวแปรที่คุณใช้ในสภาพแวดล้อมที่ส่งออกโดยบังเอิญ) นี่คือวิธีที่ผู้ใช้จะแทนที่การตั้งค่า:
VAR="other value" ./script
${VAR=value}
ไวยากรณ์พูดกับชุดVAR
ไปvalue
ถ้าVAR
ไม่ได้ถูกกำหนดไว้แล้วจากนั้นขยายไปเป็นค่าของตัวแปร เนื่องจากเราไม่สนใจเกี่ยวกับคุณค่าของตัวแปรเลยมันจึงถูกส่งผ่านเป็นอาร์กิวเมนต์ไปยังคำสั่ง no-op :
เพื่อละทิ้งมัน
แม้ว่าจะ:
เป็นคำสั่ง no-op แต่การขยายจะดำเนินการโดยเชลล์ (ไม่ใช่:
คำสั่ง!) ก่อนที่จะรัน:
คำสั่งเพื่อให้การกำหนดตัวแปรยังคงเกิดขึ้น (ถ้ามี)
มันก็จะเป็นที่ยอมรับได้ที่จะใช้true
หรือคำสั่งอื่น ๆ แทน:
แต่รหัสกลายเป็นยากต่อการอ่านเพราะความตั้งใจที่ชัดเจนน้อยลง
สคริปต์ต่อไปนี้ยังสามารถใช้งานได้:
#!/bin/sh
# print the value of the VAR variable. Note that POSIX says the behavior
# of echo is implementation defined if the first argument is '-n' or if any
# argument contains a '\', so use printf instead of echo.
printf '%s\n' "VAR=${VAR=default value}"
แต่ข้างต้นนั้นยากที่จะรักษา หากมีการ${VAR}
เพิ่มบรรทัดที่ใช้อยู่เหนือprintf
บรรทัดนั้นจะต้องย้ายส่วนขยายการมอบหมายเริ่มต้น หากผู้พัฒนาลืมที่จะย้ายการบ้านนั้นจะมีการแนะนำบั๊ก
โดยทั่วไปควรหลีกเลี่ยงบล็อกที่ไม่มีเงื่อนไข แต่บางครั้งก็มีประโยชน์:
if some_condition; then
# todo: implement this block of code; for now do nothing.
# the colon below is a no-op to prevent syntax errors
:
fi
บางคนยืนยันว่าการมีif
บล็อกว่างเปล่าจริง ๆสามารถทำให้อ่านรหัสได้ง่ายกว่าการปฏิเสธการทดสอบ ตัวอย่างเช่น:
if [ -f foo ] && bar || baz; then
:
else
do_something_here
fi
อ่านง่ายกว่า:
if ! [ -f foo ] || ! bar && ! baz; then
do_something_here
fi
อย่างไรก็ตามฉันเชื่อว่ามีวิธีการอื่น ๆ ที่ดีกว่าบล็อกจริงที่ว่างเปล่า:
ใส่เงื่อนไขในฟังก์ชั่น:
exotic_condition() { [ -f foo ] && bar || baz; }
if ! exotic_condition; then
do_something_here
fi
ใส่เงื่อนไขไว้ในเครื่องหมายปีกกา (หรือวงเล็บ แต่วงเล็บจะวางกระบวนการย่อยและการเปลี่ยนแปลงใด ๆ ที่เกิดขึ้นกับสภาพแวดล้อมภายใน subshell จะไม่ปรากฏภายนอก subshell) ก่อนที่จะปฏิเสธ:
if ! { [ -f foo ] && bar || baz; } then
do_something_here
fi
ใช้||
แทนif
:
[ -f foo ] && bar || baz || {
do_something_here
}
ฉันชอบวิธีนี้เมื่อปฏิกิริยาตอบสนองนั้นง่าย ๆ แบบหนึ่งซับเช่นเงื่อนไขในการยืนยัน:
log() { printf '%s\n' "$*"; }
error() { log "ERROR: $*" >&2; }
fatal() { error "$@"; exit 1; }
[ -f foo ] && bar || baz || fatal "condition not met"
ในเชลล์พรีเบิร์นเก่าในเวอร์ชันโบราณของ UNIX :
คำสั่งนี้มีจุดประสงค์เพื่อระบุเลเบลสำหรับgoto
(เป็นคำสั่งแยกต่างหากซึ่งทำให้อินพุตอยู่ในตำแหน่งที่พบเลเบลดังนั้นป้ายกำกับไม่สามารถเป็นไวยากรณ์แยกต่างหากที่ shell รู้เกี่ยวกับ. if
ยังเป็นคำสั่งที่แยกต่างหาก.) ในไม่ช้ามันก็ถูกใช้สำหรับความคิดเห็นก่อนที่จะมีไวยากรณ์ของความคิดเห็น ( #
ใช้สำหรับ backspace) และวันนี้ก็ใกล้เข้ากันได้มากเท่ากับอะไร
นอกเหนือจากการใช้มันเป็นคำสั่งที่ไม่ทำอะไรเลยคุณสามารถใช้มันเพื่อคอมเม้นท์คำสั่งเดียวโดยเปลี่ยนเป็นอาร์กิวเมนต์สำหรับ:
: echo write this line > myfile
จะยังคงสร้างไฟล์ว่างเปล่า
:
เป็นไม่กลไกการแสดงความคิดเห็นอย่างเพียงพอ