1 คะแนน โดย GN⁺ 2 시간 전 | 1 ความคิดเห็น | แชร์ทาง WhatsApp
  • : ในเชลล์คือ คำสั่งว่าง (null command) ที่ไม่ทำงานใด ๆ นอกจากประเมินอาร์กิวเมนต์แล้วทิ้งไป และเมื่อใช้ร่วมกับการขยายพารามิเตอร์ จะช่วยจัดการการตรวจสอบอาร์กิวเมนต์ที่จำเป็นและการตั้งค่าเริ่มต้นได้อย่างกระชับ
  • : "${1:?missing argument, aborting!}" จะพิมพ์ข้อความวินิจฉัยไปยัง stderr และจบการทำงานด้วยสถานะที่ไม่ใช่ 0 หาก $1 ไม่มีหรือว่างเปล่า
  • เมื่อส่ง ${VAR:=default} เป็นอาร์กิวเมนต์ของ : การขยายจะถูกดำเนินการแต่สตริงผลลัพธ์จะถูกทิ้งไป จึงสามารถ ตั้งค่าเริ่มต้นเท่านั้น โดยไม่รันผลลัพธ์ของการขยายเป็นคำสั่ง
  • สามารถใช้ : ได้กับการล้างไฟล์ผ่าน redirection และการตรวจสอบว่าสามารถเข้าถึงได้หรือไม่, คำสั่งว่างใน trap, การตรวจสอบตัวแปรในสภาพแวดล้อม set -u และแขนงเงื่อนไขที่ว่างเปล่า
  • : "${VAR:=default}" ช่วยลดโอกาส พิมพ์ผิด เพราะเขียนชื่อตัวแปรเพียงครั้งเดียว และใน while : จะกลายเป็นเงื่อนไขที่สำเร็จเสมอ ใช้แทน ลูปไม่รู้จบ

คำสั่งว่างและการขยายพารามิเตอร์

  • : คือคำสั่ง built-in แบบ คำสั่งว่าง ที่ประเมินอาร์กิวเมนต์แล้วทิ้งผลลัพธ์ไป
    • ย้อนกลับไปได้ถึง Thompson shell ในปี 1971 และในเวลานั้นยังถูกใช้เป็น label รวมถึงเป็นเครื่องหมายคอมเมนต์แรกของ Unix ด้วย
  • แทนที่จะใช้เงื่อนไขสี่บรรทัด สามารถตรวจสอบอาร์กิวเมนต์ที่จำเป็นได้ด้วยบรรทัดเดียวต่อไปนี้
: "${1:?missing argument, aborting!}"
echo "Hello $1!"
  • ไวยากรณ์ การขยายพารามิเตอร์ ${name:?diagnostic} ใช้ตรวจสอบว่า $name ไม่ได้ถูกตั้งค่าหรือว่างเปล่าหรือไม่
    • หากไม่มีค่า จะพิมพ์ diagnostic ไปยัง stderr และทำให้เชลล์จบการทำงานด้วยสถานะที่ไม่ใช่ 0
    • หากมีค่า จะให้ผลลัพธ์เหมือน $name
  • หากรันแค่ ${HELLO:=123} โดยไม่มีคำสั่งว่าง ผลลัพธ์จากการขยายคือ 123 จะถูกมองเป็นคำสั่งและเกิด command not found
    • : ${HELLO:=123} จะประเมินการขยาย ตั้งค่า HELLO=123 แล้วทิ้งผลลัพธ์ไป
  • : "${DATA_DIR:=/var/data}" ต่างจาก DATA_DIR="${DATA_DIR:-/var/data}" ตรงที่เขียนชื่อตัวแปรเพียงครั้งเดียว จึงลด โอกาสพิมพ์ผิด เช่น DATA_DRI

วิธีใช้ :

  • ตั้งค่าเริ่มต้น

    • ตั้งค่าเริ่มต้นให้ตัวแปรพร้อมทิ้งผลลัพธ์จากการขยาย โดยไม่รันผลลัพธ์นั้น
: "${DATA_DIR:=/var/data}"
: "${RETRIES:=3}"
  • ล้างไฟล์และตรวจสอบการเข้าถึง

    • เมื่อใช้ร่วมกับ redirection จะสามารถ ล้างไฟล์ หนึ่งไฟล์หรือมากกว่าได้
: > error.log
: > error.log > access.log
  • สามารถใช้ subshell และ redirection เพื่อตรวจสอบว่าไฟล์อ่านหรือเขียนได้หรือไม่
( : < dataset.json ) && echo YES
( : >> result.json ) && echo YES
  • ตำแหน่งที่ต้องการคำสั่งว่าง

    • ใช้ได้เมื่อไวยากรณ์ต้องมีคำสั่ง เช่น trap แต่ไม่ควรทำงานจริงใด ๆ
trap : INT
sleep 60
  • วางไว้ในแขนงของเงื่อนไขที่ต้องการปล่อยว่างได้เช่นกัน
if some-command; then
    :
else
    echo "command failed"
fi
  • ตรวจสอบหลายตัวแปร

    • ตรวจสอบพร้อมกันว่ามีการตั้งค่าหลายตัวแปรแล้วหรือไม่ ในสถานะที่เปิดใช้ set -u
set -u
: "$DEPLOY_ENV" "$HOST"
  • ลูปไม่รู้จบ

    • : เป็นเงื่อนไขที่สำเร็จเสมอ จึงใช้เขียน ลูปไม่รู้จบ ได้อย่างกระชับ
while :; do
  echo "I love colons"
  sleep 1
done

1 ความคิดเห็น

 
GN⁺ 2 시간 전
ความคิดเห็นบน Lobste.rs
  • หากจัดพรอมป์ต์ไว้แบบต่อไปนี้ แม้จะ คัดลอกทั้งบรรทัดไปวาง ส่วนพรอมป์ต์ก็จะถูกละเลย และรันเฉพาะคำสั่งเท่านั้น
    : hayalci@tassadar ~/src/dool ; jj rebase -s dxw -d mrn
    • ได้แรงบันดาลใจจาก Plan 9 และใช้ตัวเลือก autocd ของเชลล์กับรูปแบบต่อไปนี้ด้วย
      ~/directoryname; <command>
      ทุกครั้งที่คัดลอกบรรทัดคำสั่งของเชลล์ ก็จะ cd กลับไปยังไดเรกทอรีที่เคยรันคำสั่งนั้นไว้
    • ใน zsh ตั้งค่าให้เมื่อนำ ช่องว่างแบบไม่ขึ้นบรรทัดใหม่ที่มองไม่เห็น มาวาง จะลบเนื้อหาทางซ้าย
      nbsp=$'\u00A0'  
      PS1="...$nbsp"  
      bindkey -s $nbsp '^u'  
      
  • มักใช้โคลอนใน Makefile เพื่อให้แสดงผลดูดี
    out/%.o: src/%.c  
        @echo CC $@  
        @$(CC) -c -o $@ $<  
    
    วิธีนี้ make อาจรันหลายโปรเซส echo พร้อมกันและเขียนออกสตรีมเดียวกันจนรบกวนกันได้ หากเปลี่ยนเป็นแบบต่อไปนี้ จะไม่ใช่โปรเซสลูก แต่เป็น โปรเซส make เองที่แสดงผล
    out/%.o: src/%.c  
        : CC $@  
        @$(CC) -c -o $@ $<  
    
  • เคยเห็นเทคนิคนี้ในสคริปต์เชลล์ แต่หาเอกสารที่มีประโยชน์ด้วย man : หรือ whatis : ได้ยาก
    คล้ายกับคำสั่ง true แต่ต่างกันตรงที่ไม่ตอบสนองเป็นพิเศษต่อ --help, --version ฯลฯ และจำนวนอักขระก็น้อยกว่า
    • คำสั่งในตัวของ Bash ต้องค้นด้วย help แทน man
      $ help :  
      :: :  
          Null command.
      
          No effect; the command does nothing.
      
          Exit Status:  
          Always succeeds.  
      
    • ใน Fish นั้น : คือ นามแฝงของ true ตามตัวอักษร
  • การขยายพารามิเตอร์เกิดขึ้นได้แม้ไม่มีโคลอน จึงสงสัยว่าทำไมต้องมี คำสั่งว่าง ด้วย
    • การขยายพารามิเตอร์ยังเกิดขึ้นเหมือนเดิม แต่ถ้าไม่มีไวยากรณ์ที่กินผลลัพธ์เหมือนคำสั่งว่าง เชลล์จะถือว่าสตริงที่ขยายแล้วเป็น คำสั่งที่จะรัน เรื่องนี้ถูกเพิ่มใน FAQ แล้วด้วย
      % ${HELLO:=123}  
      zsh: command not found: 123  
      
      % : ${HELLO:=123}  
      % echo $HELLO  
      123  
      
    • ผลลัพธ์ของสตริงที่ถูกแทรกค่าจะถูกตีความเป็นคำสั่งที่จะรัน
      #!/bin/sh  
      "${1:?missing argument, aborting!}"  
      
      $ sh foo.sh sh  
      sh-5.3$  
      
  • เวลาพิมพ์คำสั่งอยู่แล้วอยากกลับมารันทีหลัง จะใส่โคลอนไว้หน้าบรรทัดแล้วบันทึกลงประวัติการรัน จากนั้นค่อยหาบรรทัดนั้นในประวัติและลบอักขระตัวแรกออก ก็จะรันจริงได้
    แต่ไม่เคยคิดจะใช้กับ ผลข้างเคียง ที่เกิดจากการประเมินอาร์กิวเมนต์
    • ใช้ # แทน : เพื่อ บันทึกเป็นคอมเมนต์ ก็ได้ ข้อดีคือถ้าเป็นสิ่งที่จะรันภายหลัง นิพจน์ข้างในจะไม่ถูกประเมินล่วงหน้า
    • ใน zsh ใช้ Meta-q หรือ Alt-q เพื่อพักบรรทัดปัจจุบันไว้ชั่วคราว รันคำสั่งอื่น แล้วเมื่อเสร็จจะนำบรรทัดเดิมกลับมาในบัฟเฟอร์บรรทัดคำสั่งได้
      https://nathangrigg.com/2014/04/zsh-push-line-or-edit/
  • บน macOS ยังใช้ Bash 3 อยู่ และเกิดข้อผิดพลาดต่อไปนี้
    -bash: !}": event not found
    • สงสัยว่าถ้าลบการใช้ "!" ออกจะทำงานได้หรือไม่
  • โค้ดต่อไปนี้ใน Con-colon-sion มีแนวโน้มทำให้คนสับสนมากกว่า while true; do...
    while : colons are more than punctuation; do  
      echo "I love colons"  
      sleep 1  
    done  
    
    while true; do ยาวกว่า while :; do แค่สามตัวอักษร จึงสั้นพออยู่แล้ว และโค้ดนั้นดูไม่ใช่ตัวอย่างที่เหมาะกับประเด็นที่ผู้เขียนต้องการสื่อ
    • ไม่ใช่ตัวอย่างให้ทำตามตรง ๆ แต่เป็นโค้ดที่ใส่มาเป็น มุกเล่นคำ ถ้าเข้าใจโค้ดนี้ได้ ก็แปลว่ารู้จักคำสั่งว่าง และโคลอนก็มีความหมายมากกว่าเครื่องหมายวรรคตอนจริง ๆ
    • สิ่งที่ตั้งใจจะโชว์เดิมคือ ลูปไม่สิ้นสุด แบบต่อไปนี้ แต่ดูเหมือนพยายามทำให้เท่จนหลุดประเด็น
      while :; do  
          something  
      done