ในคำตอบสำหรับคำถามนี้เกี่ยวกับความคิดเห็นในการเขียนสคริปต์เชลล์จะมีการระบุว่า:คำสั่ง 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จะยังคงสร้างไฟล์ว่างเปล่า
:เป็นไม่กลไกการแสดงความคิดเห็นอย่างเพียงพอ