คู่มือ

คำสั่ง find ใน Linux: ค้นหาไฟล์ตามชื่อ ขนาด และวันที่ พร้อมตัวอย่าง

อัปเดต: · Skillaria.Top

คำสั่ง find ไล่ดูโครงสร้างไดเรกทอรีและเลือกไฟล์ตามเงื่อนไข: find /path -name '*.log' ค้นตามชื่อ -type f เฉพาะไฟล์ -size +100M ใหญ่กว่า 100 MB และ -mtime -7 ที่แก้ไขภายในหนึ่งสัปดาห์ เงื่อนไขรวมกันได้ และสามารถสั่งการกับผลลัพธ์ด้วย -exec, -delete หรือส่งรายการเข้า xargs

คำสั่ง find ไล่ดูโครงสร้างไดเรกทอรีและหาไฟล์ตามเงื่อนไข ได้แก่ ชื่อ ประเภท ขนาด วันที่แก้ไข เจ้าของ และสิทธิ์ รูปแบบทั่วไปคือ find [ค้นหาที่ไหน] [เงื่อนไข] [การกระทำ] ด้านล่างรวบรวมตัวอย่าง find linux สำหรับงานที่พบบ่อย เช่น หาไฟล์คอนฟิก ลบล็อกเก่า หรือค้นหาสิ่งที่กินพื้นที่ดิสก์

ไวยากรณ์ของคำสั่ง find

find /var/log -type f -name '*.log' -mtime +30 -print

แยกอธิบายทีละส่วน:

  • /var/log คือจุดเริ่มต้น ระบุหลายไดเรกทอรีต่อกันได้ หรือ . (ไดเรกทอรีปัจจุบัน) หากไม่ระบุพาธ GNU find จะค้นในไดเรกทอรีปัจจุบัน
  • -type f -name '*.log' -mtime +30 คือเงื่อนไข (เอกสารเรียกว่า test) ค่าเริ่มต้นระหว่างเงื่อนไขคือ "และ" (AND)
  • -print คือการกระทำ: พิมพ์พาธ ใส่ให้อัตโนมัติหากไม่มีการกระทำอื่น

find ทำงานแบบเรียกซ้ำ เข้าไปทุกไดเรกทอรีย่อย หากรันด้วยผู้ใช้ทั่วไปในพาธของระบบ ผลลัพธ์จะเต็มไปด้วยบรรทัด Permission denied ตัดออกได้โดยส่งข้อผิดพลาดไปยังอุปกรณ์ว่าง:

find / -name 'nginx.conf' 2>/dev/null

ค้นหาตามชื่อ: -name และ -iname

เงื่อนไข -name เทียบเฉพาะชื่อไฟล์ (ไม่รวมพาธ) กับแพตเทิร์น แพตเทิร์นรองรับ * (อักขระใดก็ได้), ? (อักขระหนึ่งตัว) และ [abc] (อักขระตัวใดตัวหนึ่งในวงเล็บ)

# ชื่อตรงตัว
find /etc -name 'hosts'

# ไฟล์ .conf ทั้งหมด
find /etc -name '*.conf'

# ไม่สนใจตัวพิมพ์: README.md, readme.MD, Readme.md
find ~/projects -iname 'readme.md'

# report_1.csv ... report_9.csv
find . -name 'report_?.csv'

ควรใส่แพตเทิร์นในเครื่องหมายคำพูดเสมอ ไม่เช่นนั้น shell จะขยาย *.conf ด้วยชื่อไฟล์ในไดเรกทอรีปัจจุบันก่อน find จะได้รายชื่อไฟล์แทนแพตเทิร์น ผลจึงคาดเดาไม่ได้ หรือคำสั่งล้มเหลวด้วย paths must precede expression

ค้นหาตามพาธ: -path และ -regex

หากสนใจไดเรกทอรีด้วย ไม่ใช่แค่ชื่อ ใช้ -path ซึ่งเทียบแพตเทิร์นกับพาธทั้งหมด:

# ไฟล์ .js เฉพาะในไดเรกทอรี src
find . -path '*/src/*' -name '*.js'

สำหรับแพตเทิร์นซับซ้อนมี -regex (regex ก็เทียบกับพาธเต็มเช่นกัน) และ -iregex แบบไม่สนใจตัวพิมพ์:

find . -regextype posix-extended -regex '.*\.(jpg|jpeg|png)$'

วิธีข้ามไดเรกทอรี

หากไม่ต้องการให้ find เข้าไปใน node_modules หรือ .git ใช้ -prune:

find . -path ./node_modules -prune -o -name '*.js' -print

อ่านได้ว่า "ถ้าพาธเป็น ./node_modules ไม่ต้องเข้าไปข้างใน มิฉะนั้น (-o) ให้พิมพ์ไฟล์ *.js" ต้องมี -print ปิดท้าย ไม่เช่นนั้นไดเรกทอรีที่ถูกข้ามจะถูกพิมพ์ออกมาด้วย วิธีที่ง่ายกว่าแต่ช้ากว่าคือ -not -path '*/node_modules/*' ซึ่ง find ยังคงเข้าไปในไดเรกทอรีนั้นแต่กรองผลลัพธ์ออกทีหลัง

ค้นหาตามประเภท: -type

ค่าสิ่งที่ค้นหา
-type fไฟล์ทั่วไป
-type dไดเรกทอรี
-type lsymbolic link
-type sซ็อกเก็ต
-type pnamed pipe (FIFO)
# เฉพาะไดเรกทอรีชื่อ logs
find / -type d -name 'logs' 2>/dev/null

# ไฟล์และไดเรกทอรีที่ว่างเปล่า
find . -type f -empty
find . -type d -empty

# symbolic link ที่เสีย (ชี้ไปยังที่ไม่มีอยู่จริง)
find . -xtype l

ค้นหาตามขนาด: -size

เงื่อนไข -size รับตัวเลขพร้อมหน่วย: c คือไบต์, k คือกิโลไบต์, M คือเมกะไบต์, G คือกิกะไบต์ เครื่องหมาย + หมายถึง "มากกว่า" - หมายถึง "น้อยกว่า" และไม่มีเครื่องหมายหมายถึง "เท่ากับพอดี"

# ไฟล์ที่ใหญ่กว่า 100 MB ทั้งระบบ
find / -type f -size +100M 2>/dev/null

# ตั้งแต่ 10 ถึง 50 MB
find . -type f -size +10M -size -50M

# เล็กกว่า 1 KB
find . -type f -size -1k

มีข้อควรระวัง: ขนาดจะถูกปัดขึ้นเป็นหน่วยที่เลือก ดังนั้น -size -1M จะพบเฉพาะไฟล์ว่าง เพราะไฟล์ที่ไม่ว่างจะถูกปัดเป็น "อย่างน้อย 1 เมกะไบต์" หากต้องการขอบเขตที่แม่นยำ ใช้หน่วยที่เล็กกว่า เช่น -size -1024k

อะไรกินพื้นที่ดิสก์

การรวม find กับ ls และ sort แสดงไฟล์ที่ใหญ่ที่สุด:

find /var -type f -size +50M -exec ls -lh {} + 2>/dev/null | sort -k5 -rh | head
-rw-r----- 1 syslog adm  1.2G Oct 14 09:12 /var/log/syslog.1
-rw-r--r-- 1 root   root 412M Oct 10 03:00 /var/backups/db.sql.gz
-rw-r----- 1 root   adm   96M Oct 14 09:15 /var/log/nginx/access.log

สำหรับประเมินขนาดของไดเรกทอรีทั้งก้อน du -sh เหมาะกว่า ส่วน find มีประโยชน์เมื่อมีไฟล์ขนาดใหญ่มากไฟล์เดียวซ่อนอยู่ลึกในโครงสร้าง

ค้นหาตามวันที่: -mtime, -mmin, -newer

ไฟล์แต่ละไฟล์มีเวลาบันทึกสามค่า และ find กรองได้ตามทุกค่า:

เงื่อนไขเวลาที่ใช้หน่วย
-mtime / -mminแก้ไขเนื้อหาวัน / นาที
-atime / -aminอ่านครั้งล่าสุดวัน / นาที
-ctime / -cminเปลี่ยนเมทาดาทา (สิทธิ์ เจ้าของ ชื่อ)วัน / นาที

เครื่องหมายทำงานเหมือนกับขนาด: -mtime -7 คือแก้ไขภายในไม่ถึง 7 วันที่ผ่านมา -mtime +30 คือแก้ไขเมื่อมากกว่า 30 วันก่อน

# แก้ไขภายในหนึ่งสัปดาห์ที่ผ่านมา
find ~/projects -type f -mtime -7

# ล็อกที่เก่ากว่า 30 วัน
find /var/log -type f -name '*.log' -mtime +30

# แก้ไขภายใน 15 นาทีที่ผ่านมา
find /etc -type f -mmin -15

วันนับเป็นช่วงละ 24 ชั่วโมงเต็ม ส่วนที่เกินจะถูกตัดทิ้ง จึงทำให้ -mtime +1 พบไฟล์ที่เก่ากว่า 48 ชั่วโมง ไม่ใช่ 24 ชั่วโมง ซึ่งเป็นกับดักที่พบบ่อย หากต้องการความแม่นยำ ให้ใช้นาที เช่น -mmin +1440

ไฟล์ที่ใหม่กว่าไฟล์อื่นหรือวันที่ที่กำหนด

# แก้ไขหลังจากที่ deploy.lock ถูกแก้ไข
find . -type f -newer deploy.lock

# แก้ไขหลังวันที่ที่กำหนด (GNU find)
find . -type f -newermt '2026-10-01'

# อยู่ในช่วงวันที่
find . -type f -newermt '2026-10-01' ! -newermt '2026-10-08'

ค้นหาตามเจ้าของและสิทธิ์

# ไฟล์ของผู้ใช้ alice
find /home -user alice

# ไฟล์ที่ไม่มีเจ้าของอยู่จริง (หลังลบผู้ใช้แล้ว)
find / -nouser 2>/dev/null

# ไฟล์ที่มีสิทธิ์ 777 พอดี
find /var/www -type f -perm 777

# ไฟล์ที่ทุกคนเขียนได้
find /var/www -perm -o=w

# ไฟล์ที่มีบิต SUID ใช้ในการตรวจสอบความปลอดภัย
find / -perm -4000 -type f 2>/dev/null

-perm มีสามรูปแบบ: ไม่มีเครื่องหมาย หมายถึงสิทธิ์ตรงกันพอดี เครื่องหมาย - หมายถึงต้องมีบิตที่ระบุทั้งหมดอย่างน้อย เครื่องหมาย / หมายถึงมีบิตที่ระบุอย่างน้อยหนึ่งบิต

ตรรกะของเงื่อนไข: และ หรือ ไม่

เงื่อนไขเชื่อมกันด้วย "และ" เป็นค่าเริ่มต้น ใช้ -o สำหรับ "หรือ" และใช้ ! หรือ -not สำหรับการปฏิเสธ การจัดกลุ่มทำด้วยวงเล็บ ซึ่งต้องใส่แบ็กสแลชเพื่อให้ shell ไม่ตีความ:

# รูปภาพ jpg หรือ png
find . -type f \( -name '*.jpg' -o -name '*.png' \)

# ทุกอย่างยกเว้นไฟล์ .tmp
find . -type f ! -name '*.tmp'

หากไม่มีวงเล็บ -type f จะใช้กับเงื่อนไขแรกของคู่ "หรือ" เท่านั้น และไดเรกทอรีชื่อ *.png ก็จะติดมาในผลลัพธ์ ต้องมีช่องว่างรอบ \( และ \)

ความลึกในการค้นหา: -maxdepth และ -mindepth

# เฉพาะไดเรกทอรีปัจจุบัน ไม่ลงไปชั้นย่อย
find . -maxdepth 1 -type f -name '*.sh'

# เริ่มจากระดับที่สองของการซ้อน
find . -mindepth 2 -name '*.md'

# ไม่ข้ามไปยังระบบไฟล์อื่น
find / -xdev -type f -size +1G

ใส่ -maxdepth ทันทีหลังพาธ ก่อนเงื่อนไขอื่น ไม่เช่นนั้น GNU find จะแสดงคำเตือน ตัวเลือก -xdev มีประโยชน์เมื่อค้นหาจาก / เพราะ find จะไม่เข้าไปใน /proc หรือดิสก์เครือข่ายและดิสก์ที่เมานต์อยู่

การกระทำกับผลลัพธ์: -exec, -delete, xargs

-exec: รันคำสั่งกับแต่ละไฟล์

find จะแทนที่ {} ด้วยพาธของไฟล์ คำสั่งต้องจบด้วย \; หรือ +:

# รันทีละไฟล์
find . -name '*.sh' -exec chmod +x {} \;

# ทุกไฟล์ในรายการเดียว เร็วกว่า
find . -name '*.log' -exec gzip {} +

# ถามยืนยันทีละไฟล์
find . -name '*.bak' -ok rm {} \;

รูปแบบ + รวมพาธเป็นกลุ่มและรันคำสั่งน้อยครั้งกว่ามาก จึงเร็วกว่าหลายเท่าเมื่อมีไฟล์หลายพันไฟล์ รูปแบบ \; ใช้เมื่อคำสั่งรับไฟล์ทีละไฟล์เท่านั้น หรือวาง {} ไว้ที่อื่นที่ไม่ใช่ท้ายคำสั่ง

-delete: ลบสิ่งที่พบ

# ดูก่อนว่าอะไรจะถูกลบ
find /tmp/build -type f -name '*.o' -mtime +7

# จากนั้นจึงลบ
find /tmp/build -type f -name '*.o' -mtime +7 -delete

รันโดยไม่ใส่ -delete และตรวจรายการเสมอ และวาง -delete ไว้ท้ายสุด เพราะ find ประเมินนิพจน์จากซ้ายไปขวา หาก find . -delete -name '*.o' จะลบทุกอย่างในไดเรกทอรีก่อน แล้วจึงตรวจชื่อ

find และ xargs

การต่อแบบคลาสสิกคือส่งรายการไฟล์ให้โปรแกรมอื่นผ่าน xargs เพื่อไม่ให้พังกับชื่อไฟล์ที่มีช่องว่าง ให้ใช้ตัวคั่นเป็นไบต์ว่าง:

find . -type f -name '*.txt' -print0 | xargs -0 wc -l

แฟล็ก -P ของ xargs ทำงานแบบขนาน:

find ./images -name '*.png' -print0 | xargs -0 -P 4 -n 10 optipng

find และ grep: ค้นหาข้อความภายในไฟล์

find ค้นหาไฟล์ ไม่ได้ค้นเนื้อหา เพื่อหาบรรทัดภายในไฟล์ที่เลือกไว้ ส่งไฟล์เหล่านั้นให้ grep:

# listen 8080 อยู่ที่ไหนบ้างในคอนฟิก
find /etc/nginx -type f -name '*.conf' -exec grep -Hn 'listen 8080' {} +
/etc/nginx/sites-enabled/app.conf:4:    listen 8080;

แฟล็ก -H พิมพ์ชื่อไฟล์ -n พิมพ์หมายเลขบรรทัด และ grep -l พิมพ์เฉพาะชื่อไฟล์ที่พบ หากกรองแค่ตามนามสกุล grep เพียงอย่างเดียวก็พอ: grep -rn --include='*.conf' 'listen 8080' /etc/nginx

รูปแบบผลลัพธ์เอง: -printf

GNU find พิมพ์ได้มากกว่าพาธ เช่น ขนาด วันที่ และชื่อ:

find . -maxdepth 1 -type f -printf '%s\t%TY-%Tm-%Td\t%p\n' | sort -n

โดย %s คือขนาดเป็นไบต์ %T... คือวันที่แก้ไขแยกเป็นส่วน และ %p คือพาธ เหมาะกับสคริปต์ เพราะไม่ต้องแยกวิเคราะห์ผลลัพธ์ของ ls

ตารางคำสั่ง find ที่ใช้ทุกวัน

งานคำสั่ง
ค้นหาไฟล์ตามชื่อfind / -name 'file.txt' 2>/dev/null
ไม่สนใจตัวพิมพ์find . -iname '*.jpg'
เฉพาะไดเรกทอรีfind . -type d -name 'cache'
ไฟล์ที่ใหญ่กว่า 1 GBfind / -xdev -type f -size +1G
แก้ไขภายใน 1 วันfind . -type f -mtime -1
แก้ไขภายใน 1 ชั่วโมงfind . -type f -mmin -60
ลบล็อกที่เก่ากว่า 30 วันfind /var/log/app -name '*.log' -mtime +30 -delete
ไดเรกทอรีว่างfind . -type d -empty
เปลี่ยนสิทธิ์ของทุกไดเรกทอรีfind . -type d -exec chmod 755 {} +
ข้อความภายในไฟล์find . -name '*.py' -exec grep -l 'TODO' {} +
นับจำนวนไฟล์find . -type f | wc -l

ข้อผิดพลาดที่พบบ่อย

  • แพตเทิร์นที่ไม่ใส่เครื่องหมายคำพูด. find . -name *.log จะพังเมื่อมีไฟล์ .log อย่างน้อยหนึ่งไฟล์ในไดเรกทอรีปัจจุบัน ให้เขียน '*.log'
  • ข้อความ Permission denied จำนวนมาก. เพิ่ม 2>/dev/null หรือรันด้วย sudo หากต้องการค้นทั้งดิสก์จริง ๆ
  • -delete อยู่ผิดตำแหน่ง. ต้องอยู่ท้ายสุดเสมอ และก่อนหน้านั้นควรมีการรันทดสอบโดยไม่ลบ
  • ชื่อที่มีช่องว่างในท่อ. find ... | xargs rm จะแยก "My File.txt" เป็นสองอาร์กิวเมนต์ ใช้ -print0 กับ xargs -0 หรือ -exec
  • คาดหวังจำนวนวันที่แม่นยำจาก -mtime. หากต้องการช่วงเวลาที่แน่นอน ใช้ -mmin หรือ -newermt

สรุป

find เป็นเครื่องมือค้นหาในระบบไฟล์ที่ใช้ได้กับทุกงาน: กำหนดพาธ ตั้งเงื่อนไขตามชื่อ ประเภท ขนาด วันที่ และสิทธิ์ แล้วจึงกำหนดการกระทำ เรียนรู้เสาหลักห้าอย่าง ได้แก่ -name, -type, -size, -mtime และ -exec ... + แล้วงานส่วนใหญ่จะแก้ได้ในบรรทัดเดียว ตัวอย่าง find linux เหล่านี้ควรลองรันในเทอร์มินัลของคุณเอง และการต่อ find กับ grep, sed และ awk เราฝึกกันจริงในบทเรียนหลักสูตร Linux เรื่องการประมวลผลข้อความ

คำถามที่พบบ่อย

find ต่างจาก locate อย่างไร?

locate ค้นจากฐานข้อมูลชื่อไฟล์ที่สร้างไว้ล่วงหน้า จึงเร็วมาก แต่ไม่เห็นไฟล์ที่สร้างหลังจากอัปเดตฐานข้อมูลล่าสุดด้วย updatedb ส่วน find สแกนดิสก์แบบเรียลไทม์ และกรองตามขนาด วันที่ และสิทธิ์ได้

จะค้นหาไฟล์จากเนื้อหาแทนชื่อได้อย่างไร?

find เองไม่อ่านเนื้อหา ใช้ grep -rn 'ข้อความ' /path หรือรวมกันเป็น find . -name '*.conf' -exec grep -l 'ข้อความ' {} +

ทำไม find ช้ามากเมื่อค้นจากรากของดิสก์?

เพราะมันสแกนทุกไดเรกทอรี รวมถึง /proc, /sys และดิสก์ที่เมานต์อยู่ จำกัดการค้นหาให้อยู่ในไดเรกทอรีที่ต้องการ เพิ่ม -xdev และ -maxdepth หรือยกเว้นส่วนที่ไม่จำเป็นด้วย -prune

เรียงผลลัพธ์ของ find ตามวันที่ได้หรือไม่?

ได้ find . -type f -printf '%T@ %p\n' | sort -n จะแสดงไฟล์จากเก่าไปใหม่ โดย %T@ คือเวลาแก้ไขเป็นวินาทีนับจากยุค Unix

จะค้นหาและลบไดเรกทอรีว่างอย่างไร?

คำสั่ง find . -type d -empty -delete จะลบไดเรกทอรีว่างทั้งหมด รวมถึงที่เพิ่งว่างหลังลบไดเรกทอรีย่อย ควรรันโดยไม่ใส่ -delete ก่อนเพื่อตรวจรายการ

เรียนหัวข้อนี้ผ่านวิดีโอ

หัวข้อนี้สอนอย่างละเอียดพร้อมฝึกปฏิบัติในคอร์ส “Linux: с нуля до уверенного администрирования”

ไปที่คอร์ส