22 คะแนน โดย GN⁺ 2026-05-11 | 1 ความคิดเห็น | แชร์ทาง WhatsApp
  • ตัวค้นหาแบบ fuzzy finder บนคอมมานด์ไลน์อย่าง fzf เป็นเครื่องมือที่ให้ผลตอบแทนต่อเวลาที่ลงทุนแบบเห็นผลทันทีและมีคุณค่าเฉพาะตัว แต่ผู้พัฒนาจำนวนมากมักติดตั้งแล้วก็เลิกใช้ไปเพราะไม่รู้จะใช้อย่างไร
  • สามารถแทนที่การค้นหาประวัติคำสั่งด้วย Ctrl+R ด้วย การจับคู่แบบฟัซซีและการแสดงตัวอย่างหลายรายการ เพื่อลดความไม่สะดวกของวิธีเดิมที่ต้องอาศัยการตรงกันของสตริงแบบเป๊ะ ๆ
  • ใช้ Alt+C เพื่อทำ fuzzy cd ได้ แม้จะจำชื่อไดเรกทอรีได้เพียงลาง ๆ และยังสร้างเวิร์กโฟลว์เปิดไฟล์ได้ทันทีด้วยชุดคำสั่ง vi $(fzf)
  • เมื่อต่อเข้ากับ ripgrep ผ่านไพป์ ก็สามารถ ค้นหาแบบฟัซซีทุกบรรทัดในทุกไฟล์ แล้วเปิดไฟล์นั้นในเอดิเตอร์ได้ทันที
  • เป็นเครื่องมือเพิ่มประสิทธิภาพที่ให้ผลทันทีมากจนแม้แต่แนวคิดแบบ 80/20 heuristic ที่แนะนำให้เรียนรู้เครื่องมือ Unix เดิม (cat, grep, find ฯลฯ) ก่อน ก็ยังใช้ไม่ได้ในกรณีนี้

คุณค่าที่ได้ทันทีหลังติดตั้ง fzf

  • วิศวกรซอฟต์แวร์สามารถสร้างเครื่องมือมาปรับปรุงงานของตัวเองได้ไม่ยาก แต่ถ้าสลับไปมาระหว่างหลายเครื่องมือและไม่เรียนรู้ให้ลึก ต้นทุนจะยิ่งสะสมเมื่อเวลาผ่านไป
  • 80/20 heuristic ที่ดีคือควรเรียนรู้เครื่องมือ Unix รุ่นเก่าอย่าง cat, ls, cd, grep, cut ก่อน และในงานดูแลระบบสมัยใหม่ก็ควรรวม sed กับ awk ด้วย
  • แต่ fzf ให้ผลตอบแทนต่อเวลาที่ลงทุนแบบทันทีและมีคุณค่าไม่เหมือนใคร จึงอาจถือเป็นข้อยกเว้นของ heuristic นี้ได้
  • ประเด็นสำคัญคือฟีเจอร์ที่ใช้ได้ทันทีหลังติดตั้งด้วย สคริปต์ติดตั้ง fzf`` บนสภาพแวดล้อม Ubuntu มาตรฐาน

ผลลัพธ์ทันทีจากคีย์ลัดพื้นฐาน

  • Ctrl+R: เปลี่ยนประวัติคำสั่งเป็นการค้นหาแบบฟัซซี

    • ในเทอร์มินัล Linux และ Windows ส่วนใหญ่ Ctrl+R ใช้สำหรับ ค้นหาย้อนกลับ ในประวัติคำสั่ง
    • Ctrl+R แบบเดิมต้องการ การตรงกันอย่างแม่นยำ เพื่อหาคำสั่งที่ต้องการ และแสดงได้เพียง ตัวอย่างครั้งละหนึ่งรายการ ทำให้ถ้าพิมพ์พลาดไปแม้ตัวเดียวก็หาเจอได้ยาก
    • เมื่อติดตั้ง fzf แล้ว คีย์ลัดหลายตัวจะถูกแทนด้วยพฤติกรรมที่ดีกว่า และ Ctrl+R ก็ได้รับการปรับปรุงอย่างมากจากวิธีเดิม
    • หากติดตั้งผ่านตัวจัดการแพ็กเกจอย่าง apt การผนวกคีย์ลัดนี้อาจไม่มีให้ จึงเป็นเหตุผลที่ควรใช้ สคริปต์ติดตั้ง fzf``
  • Alt+C: ย้ายไปยังไดเรกทอรีที่จำได้ไม่ชัดอย่างรวดเร็ว

    • fzf เปลี่ยน Alt+C ให้เป็นคีย์ลัด cd แบบฟัซซีที่ทรงพลังกว่าเดิม
    • ช่วยให้ย้ายไปยังไดเรกทอรีได้เร็วเมื่อจำพาธที่แน่นอนไม่ได้และนึกออกแค่ชื่อคร่าว ๆ
    • มีประโยชน์เมื่ออยู่ในเทอร์มินัลว่าง ๆ แล้วต้องหารีโพซิทอรีหรือไดเรกทอรีงานที่ไม่ได้เปิดมานาน

ตัวคำสั่ง fzf เองและการใช้ร่วมกับเชลล์

  • fzf พื้นฐาน

    • ถ้ารันคำสั่ง fzf ตรง ๆ มันจะค้นหาแบบฟัซซีในพาธไฟล์แบบสัมพัทธ์โดยอิงจากไดเรกทอรีปัจจุบัน
    • ถ้าใช้เดี่ยว ๆ ก็มีประโยชน์แค่ประมาณเลือกตำแหน่งไฟล์ จึงยังไม่โดดเด่นมากนัก
  • vi $(fzf)

    • หากใช้ร่วมกับ command substitution แบบ vi $(fzf) ก็สามารถเปิดไฟล์ที่เลือกผ่านการค้นหาแบบฟัซซีในเอดิเตอร์ได้ทันที
    • วิธีนี้ไม่ได้ผูกกับ vi เป็นพิเศษ และใช้กับเอดิเตอร์ที่ต้องการอย่าง emacs, nano, code เป็นต้น ได้เช่นกัน
  • vi $(find . '/' | fzf)

    • เมื่อใช้ find . '/' | fzf ร่วมกับเอดิเตอร์ ก็สามารถค้นหาแบบฟัซซีจากรายการพาธเต็มเพื่อเปิดไฟล์คอนฟิกที่ไม่รู้ว่าอยู่ตรงไหนได้
    • เวลาหาไฟล์อย่าง nginx.conf ที่จำตำแหน่งไม่ได้ ก็ไม่จำเป็นต้องเดาตามความรู้เรื่อง FHS หรือท่องจำตำแหน่งไว้ แค่ไพป์ผลลัพธ์ของ find เข้า fzf ก็พอ
    • ถ้าค้นหาด้วย conf$ ก็สามารถกรองให้เหลือเฉพาะบรรทัดที่ลงท้ายด้วย conf ได้
    • หาก find เจอข้อผิดพลาด Permission denied จำนวนมาก fzf อาจกระตุกอยู่ชั่วครู่ แต่จะกลับมาทำงานได้เองในอีกไม่กี่วินาที
    • ความหน่วงไม่กี่วินาทีนี้คือสิ่งที่ต้องแลกกับความสะดวกในการหาไฟล์คอนฟิกด้วยวิธีที่เรียบง่ายมาก
  • vi **<TAB>

    • ฟีเจอร์นี้มาจากคอมเมนต์บน Hacker News ของ sigmonsays โดยอยู่กึ่งกลางระหว่างการแทนคีย์ลัดกับการรัน fzf โดยตรง นั่นคือ fuzzy tab completion ที่ใช้ดอกจันสองตัว
    • vi **<TAB> ใช้เลือกไฟล์ได้ในลักษณะคล้าย vi $(fzf)
    • แต่หลังจากเติมคำสั่งเสร็จแล้ว ยังต้องกด Enter อีกหนึ่งครั้ง
    • ทำงานได้ดีใน bash และ zsh แต่ใน fish อาจใช้ไม่ได้
    • ถ้าคุณจำวิธีเรียก $(fzf) แบบชัดเจนได้ง่ายกว่า ก็อาจไม่ได้ใช้ฟีเจอร์นี้บ่อยนัก

ใช้ fzf กับการย้ายไฟล์ได้ด้วย

  • mv $(fzf) $(fzf)

    • mv $(fzf) $(fzf) เหมาะเมื่อคุณจำไม่ได้แน่ชัดว่าต้องย้ายอะไรและย้ายไปที่ไหน แต่ยังพอมีเบาะแสที่เฉพาะเจาะจงสำหรับทั้งสองอย่าง
    • วิธีนี้คือเลือกทั้งไฟล์ต้นทางและปลายทางผ่าน fzf สองครั้ง
    • จึงอาจกลายเป็นคำสั่งที่หยิบมาใช้บ่อยเวลาจัดวางไฟล์ เช่น ตอนใส่ GIF ลงใน GitHub README
    • มีตัวอย่างที่เกี่ยวข้องคือ finstem interactive mode README

ใช้ร่วมกับ rg เพื่อค้นหาแบบฟัซซีถึงเนื้อหาในไฟล์

  • rg: grep ที่เร็วและค้นหาแบบ recursive เป็นค่าเริ่มต้น

    • ชุดคำสั่งด้านล่างทำกับ grep ก็ได้ แต่ rg หรือ ripgrep เหนือกว่าในงานลักษณะนี้เพราะค้นหาแบบ recursive เป็นค่าเริ่มต้น
    • ถ้าจะทำตามตัวอย่าง แนะนำให้ติดตั้งและใช้ rg
  • rg . | fzf

    • rg . จะส่งออกแต่ละบรรทัดจากไฟล์ต่าง ๆ เป็นผลการค้นหา และเมื่อส่งต่อเข้า fzf ก็จะค้นหาแบบฟัซซีได้ในทุกบรรทัดของทุกไฟล์
    • จึงเป็นการค้นหาโดยอาศัยเนื้อหาภายในบรรทัด แทนที่จะอาศัยชื่อไฟล์
  • rg . | fzf | cut -d ":" -f 1

    • ถ้านำผลที่เลือกจาก rg . | fzf ไปต่อด้วย cut -d ":" -f 1 ก็จะคืนค่าฟิลด์แรกตามตัวคั่นโคลอน หรือก็คือตำแหน่งไฟล์
    • เป็นชุดคำสั่งสำหรับค้นหาแบบฟัซซีจากเนื้อหาบรรทัด แล้วดึงออกมาเฉพาะพาธของไฟล์ที่มีบรรทัดนั้น
  • vim $(rg . | fzf | cut -d ":" -f 1)

    • vim $(rg . | fzf | cut -d ":" -f 1) คือการค้นหาแบบฟัซซีในทุกบรรทัดของทุกไฟล์ แล้วเปิดไฟล์ที่มีบรรทัดที่เลือกด้วย vim
    • ช่วยให้เปิดเอดิเตอร์ต่อได้ทันทีเมื่อจำชื่อไฟล์ไม่ได้ แต่จำเนื้อหาบางส่วนได้

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

 
GN⁺ 2026-05-11
ความคิดเห็นจาก Lobste.rs
  • ดูเหมือนว่ากลุ่มผู้อ่านเป้าหมายของบทความนี้จะเป็นผมพอดี ติดตั้ง fzf แล้วคิดว่า “อัจฉริยะมาก” แต่สุดท้ายก็ลืมใช้มันอยู่เรื่อย ๆ ตอนนี้อาจจะได้เริ่มใช้จริงแล้วก็ได้

    • ประเด็นสำคัญคือการผนวกมันเข้ากับการตั้งค่าเชลล์เดิม สคริปต์ส่วนตัว และ alias ต่าง ๆ ผมใช้ fzf ตลอด แต่แทบไม่เคยรันมันตรง ๆ เลย
  • อาจจะเป็นบทความที่ดี แต่ถ้าเป้าหมายคือจะตอบคำถามว่า “แล้วจะทำอะไรต่อดี?” การเริ่มจากการผสานรวมกับเชลล์ของ fzfกลับให้ความรู้สึกว่ากำลังคุยกับผู้อ่านกลุ่มที่แคบลงไปอีก
    ผมคุ้นกับการใช้ ctrl-r ใน bash อยู่แล้ว จะให้เปลี่ยนเลยก็ดูเรียกร้องมากเกินไป น่าจะเริ่มจากสอนวิธีฝึกใช้พฤติกรรมแบบเดิมโดยไม่ต้องแทนที่ค่าเริ่มต้นก่อน

    • ที่จริงแล้วมันใกล้เคียงกับค่าเริ่มต้นแบบอัปเกรดมากกว่า ปล่อยให้มันมาแทน ctrl-r นั่นแหละถูกแล้ว และเสน่ห์หลักครึ่งหนึ่งก็คือการคงพฤติกรรมที่คุ้นมือไว้ ขณะที่ได้ประสบการณ์ที่สมบูรณ์ขึ้นในโฟลว์ที่แทบเหมือนเดิม
      ctrl-r น่าจะเป็นคำสั่งที่ผมใช้บ่อยที่สุด และ fzf ก็เป็นการปรับปรุงที่เข้าที่ทันทีโดยแทบไม่มีช่วงเรียนรู้ พอมันรันผ่าน ctrl-r ก็เลยไม่ลืมใช้ fzf ด้วย แต่ต่อมาผมย้ายไปใช้ Fish shell ซึ่งที่นั่นมีพฤติกรรมแบบเดียวกันมาให้เป็นค่าเริ่มต้นอยู่แล้ว
  • โอเค เชื่อแล้ว อีกไม่นานจะเพิ่มการผสานรวมกับเชลล์ของ fzf และวันนี้ก็ได้เรียนรู้อะไรใหม่หนึ่งอย่าง

  • เวลาอยากหาไฟล์มาใส่ในคำสั่ง ก็ใช้**คีย์ลัด ctrl-t**ได้เหมือนกัน ผมใช้กับ git บ่อยเวลาจะเลือกไฟล์ที่จะรวมในบางการเปลี่ยนแปลง และเคยใช้กรองผลลัพธ์จาก grep เพื่อให้ขอบเขตการค้นหาแคบลงด้วย

  • นอกจากการค้นหาประวัติในเชลล์ที่ดีขึ้นแล้ว ผมยังใช้ fzf ร่วมกับaliasสองตัวนี้มาตลอด
    alias gbd='git -c color.ui=never branch | fzf | xargs -I {} git branch -D {}'
    ส่วนใหญ่ใช้เลือกชุด local branch ที่จะลบทิ้งหลัง merge pull request เสร็จ อาจมีวิธีที่ดีกว่านี้ แต่จนถึงตอนนี้ก็ยังไม่เคยพลาด
    alias awp='export AWS_PROFILE="$(grep -e "\[\(.*\)\]" ~/.aws/config | sed -e "s/\[//g" | sed -e "s/\]//g" | cut -d " " -f 2 | sort -u | fzf)"'
    มันช่วยให้สลับAWS_PROFILEได้อย่างรวดเร็วตามค่าที่อยู่ใน ~/.aws/config ตอนนี้กำลังคิดว่าจะทำ alias คล้าย ๆ กันไว้สลับ Kubernetes namespace ด้วย

  • ถ้าใช้ปลั๊กอิน fzf.vim ก็จะใช้ fzf ภายใน vim ได้ ไม่ใช่แค่เปิดไฟล์ แต่ยัง fuzzy search กับบัฟเฟอร์ ประวัติคำสั่ง และเนื้อหาไฟล์ได้ด้วย

  • การใช้งานหลักของ fzf สำหรับผมคือไล่ดูและค้นหาประวัติ commit ของ Gitแบบเชิงเส้น เพื่อดูว่าเมื่อไม่นานมานี้มีอะไรเปลี่ยนไปบ้าง
    ในการตั้งค่า Git ปกติของผม ผมกำหนด git fzf ไว้แบบนี้

    [alias]  
      # Browse commit history with fzf  
      # Inspired by: https://chrismanbrown.gitlab.io/67.html  
      fzf = "!git log --oneline --color=always --decorate=short $@ | \  
          fzf --ansi --reverse --no-sort \  
            --preview 'git show --color=always {1}' \  
            --preview-window '<50(down)' \  
            --bind 'enter:become(git show {1})' #"  
    
  • เหมือนผมจะพลาดอะไรบางอย่างไป สงสัยว่าถ้ายังไม่รู้ว่าจะเอาไปทำอะไร ทำไมถึงติดตั้ง fzfตั้งแต่แรก

  • มีโพสต์ที่เกี่ยวข้องล่าสุดเหมือนกัน มีผู้ใช้คนหนึ่งใช้ fzf เป็นตัวเลือกไฟล์สำหรับ jj
    https://lobste.rs/s/exlogg/jjj