คำสั่ง find ใน Linux: ค้นหาไฟล์ตามชื่อ ขนาด และวันที่ พร้อมตัวอย่าง
คำสั่ง 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 l | symbolic link |
-type s | ซ็อกเก็ต |
-type p | named 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 GB | find / -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: с нуля до уверенного администрирования”
ไปที่คอร์ส