Searching Commands

find, grep คำสั่งค้นหาข้อความและไฟล์ด้วยชุด Regular Expressions

find

การค้นหาไฟล์ในระบบปฏิบัติการลีนุกซ์สามารถทำได้หลายวิธี หนึ่งในคำสั่งที่ได้รับความนิยมคือคำสั่ง find เพราะมีความยืดหยุ่นสูงในการค้นหาไฟล์แต่ละชนิดดังตารางแสดงพารามิเตอร์ (parameter) เพื่อใช้ระบุชนิดไฟล์ที่ต้องการค้นหา

ตารางสัญลักษณ์บอกชนิดไฟล์

สัญลักษณ์ชนิดไฟล์

f

ไฟล์ทั่วไป

d

ไดเรกทอรี

b

block

c

character

p

pipe

l

Symbolic link

s

Socket

ในกรณีที่ต้องการระบุให้ค้นหาเฉพาะไฟล์ทั่วไป (f) หรือ ไดเรกทอรี (d) สามารถใช้ตัวเลือก -type เพื่อระบุประเภทได้ดังตัวอย่างข้างล่าง

$ ls -l
total 28
-rw-r--r-- 1 student student   53 2013-08-21 05:16 error.log
-rwxr-xr-x 1 student student 8497 2013-08-21 06:05 hello
-rw-r--r-- 1 student student   92 2013-08-21 06:05 hello.c
drwxr-xr-x 2 student student 4096 2013-09-17 18:03 out
-rw-r--r-- 1 student student   57 2013-08-21 05:16 result.txt


$ find . -type f
./error.log
./result.txt
./.my_hidden_file
./hello
./hello.c


$ find . -type d
.
./.my_hidden_directory
./out

ในกรณีที่ต้องการค้นหาไฟล์หรือไดเรกทอรีที่ถูกซ่อนอยู่

$ find . -type f -name ".*"
./.my_hidden_file

เนื่องจากระบบไฟล์ภายใต้ระบบปฏิบัติการลีนุกซ์จะเป็นแบบ case sensitive (สนใจตัวพิมพ์เล็ก-พิมพ์ใหญ่) ดังนั้นในการค้นหาไฟล์ที่ใกล้เคียงทั้งหมดโดยไม่สนใจกรณี case sensitive สามารถระบุโดยการใช้ -iname เข้าไปดังตัวอย่างข้างล่าง

$ find -iname "MyProgram.c"
./myprogram.c
./unix/myprogram.c
./programming/MyProgram.c
./MyProgram.c

การระบุระดับความลึกของชั้นไดเรกทอรีในการค้นหา สามารถทำได้โดยการใช้ -mindepth [level] และ -maxdepth [level] ตัวอย่างเช่น ต้องการค้นหาตั้งแต่ไดเรกทอรี root (level 1) และลึกลงไปอีก 2 ชั้น (level 2 - level 3) สามารถใช้คำสั่งดังนี้

$ find / -maxdepth 3 -name shadow
/etc/bash_completion.d/shadow
/etc/shadow

เมื่อต้องการระบุว่าให้ค้นหาไฟล์ที่อยู่เฉพาะระดับความลึกที่ 2 ถึง 4 (level 2 - level 4)

$ find / -mindepth 2 -maxdepth 4 -name shadow
/etc/bash_completion.d/shadow

การค้นหาด้วยคำสั่ง find แต่ละครั้ง สามารถตั้งชุดคำสั่งพิเศษหลังตัวเลือก -exec ในกรณีที่เจอไฟล์ตามที่ต้องการค้นหา ตัวอย่างเช่นให้ทำการเช็คค่า checksum ไฟล์ที่เจอด้วยคำสั่ง md5sum

$ find -iname "MyProgram.c" -exec md5sum {} \;
ed832d42670ee3af4041e4a50f851755 ./myprogram.c
ed832d42670ee3af4041e4a50f851755 ./unix/myprogram.c
7562d93e8b9a19dc80959d4eb7e2c7ca ./programming/MyProgram.c
ae96bf65a87976abba3fdc57f47a55a2 ./MyProgram.c

ถ้าต้องการระบุการค้นหาตามสิทธิ์ของไฟล์นั้น (file permission) สามารถใช้ -perm ได้ดังตัวอย่างข้างล่าง

$ find . -perm -g=r -type f -exec ls -l {} \;
-rw-r--r-- 1 student student 53 2013-08-21 05:16 ./error.log
----r----- 1 student student 57 2013-08-21 05:16 ./result.txt
-rw-r--r-- 1 student student 0 2013-09-17 18:04 ./.my_hidden_file
-rwxr-xr-x 1 student student 8497 2013-08-21 06:05 ./hello
-rw-r--r-- 1 student student 92 2013-08-21 06:05 ./hello.c


$ find . -perm g=r -type f -exec ls -l {} \;
----r----- 1 student student 57 2013-08-21 05:16 ./result.txt

หรือระบุเป็นเลขฐานแปด (Octal)

$ find . -perm 040 -type f -exec ls -l {} \;
----r----- 1 student student 57 2013-08-21 05:16 ./result.txt

งานด้านระบบสมองกลฝังตัวขนาดของไฟล์ข้อมูลค่อนข้างเป็นประเด็นที่ต้องให้ความสนใจ เนื่องจากพื้นที่เก็บข้อมูลมีขนาดจำกัด ดังนั้นการนำคำสั่ง find มาประยุกต์ใช้เพื่อค้นหาไฟล์ตามขนาดไฟล์ที่ต้องการจึงมีความสำคัญเช่นกัน ดังตัวอย่างต่อไปนี้

เมื่อต้องการค้นหาไฟล์ที่มีขนาดใหญ่ 5 อันดับแรก

$ find . -type f -exec ls -s {} \; | sort -n -r | head -5
80 ./testing/ktest/ktest.pl
64 ./perf/util/trace-event-parse.c
64 ./perf/util/symbol.c
60 ./lguest/lguest.c
56 ./perf/util/header.c

หรือขนาดเล็กสุด 5 อันดับแรก แต่ไม่ต้องการรวมไฟล์ที่มีขนาดศูนย์ไบต์ (Empty file)

$ find . -not -empty -type f -exec ls -s {} \; | sort -n  | head -5
4 ./firewire/list.h
4 ./firewire/Makefile
4 ./firewire/nosy-dump.h
4 ./include/tools/be_byteshift.h
4 ./include/tools/le_byteshift.h

ในกรณีที่ต้องการระบุขนาดไฟล์ (byte) อย่างชัดเจน สามารถใช้ -size [byte] ดังตัวอย่างข้างล่าง

$ find . -size +200M   <------ ไฟล์ที่มีขนาดมากกว่า 200 เมกะไบต์
$ find . -size -200M   <------ ไฟล์ที่มีขนาดน้อยกว่า 200 เมกะไบต์
$ find . -size 200M    <------ ไฟล์ที่มีขนาด 200 เมกะไบต์

นักพัฒนาสามารถสร้างคำสั่งเฉพาะด้วย alias เพื่อความสะดวกในการค้นหาไฟล์ขนาดที่ต้องการ เพื่อลบทิ้ง ดังตัวอย่างข้างล่าง

$ alias rm50m="find / -type f -name *.tar -size +50M -exec rm -i {} \;"
$ alias rm1g="find / -type f -name *.tar -size +1G -exec rm -i {} \;"
$ alias rm3g="find / -type f -name *.tar -size +3G -exec rm -i {} \;"
$ alias rm5g="find / -type f -name *.tar -size +5G -exec rm -i {} \;"

นอกจากนั้นถ้าต้องการค้นหาไฟล์โดยดูจากเวลาของไฟล์ที่ถูกเข้าถึง (Access time) ถูกเปลี่ยนแปลงข้อมูลภายใน (Modification time) หรือ มีการเปลี่ยนแปลงไอโหนด/สถานะ (Change time) สามารถระบุตัวเลือกดังรายละเอียดในตารางข้างล่าง

ตารางตัวเลือกการเข้าถึงไฟล์ของคำสั่ง find

ตัวเลือกคำอธิบาย

--- Access Time ---

amin m

เวลา m นาทีที่ผ่านมา ที่ไฟล์ถูกเข้าถึง

atime d

เวลา d*24 ชั่วโมงที่ผ่านมา ที่ไฟล์ถูกเข้าถึง

--- Modification Time ---

mmin m

เวลา m นาทีที่ผ่านมา ที่ไฟล์ถูกเปลี่ยนแปลงข้อมูลภายใน

mtime d

เวลา d*24 ชั่วโมงที่ผ่านมา ที่ไฟล์ถูกเปลี่ยนแปลงข้อมูลภายใน

--- Change Time ---

cmin m

เวลา m นาทีที่ผ่านมา ที่ไฟล์ถูกเปลี่ยนสถานะหรือค่าไอโหนด

ctime d

เวลา d*24 ชั่วโมงที่ผ่านมา ที่ไฟล์ถูกสถานะหรือค่าไอโหนด

$ cd unix/
$ vim hello.c           <------ แก้ไขข้อมูลภายในไฟล์ hello.c
$ chmod 755 result.txt  <------ เปลี่ยนสิทธิ์ของไฟล์ result.txt

ค้นหาไฟล์ภายในไดเรกทอรี unix ที่มีการถูกแก้ไขข้อมูลภายในไฟล์ เมื่อ 10 นาทีที่ผ่านมา

$ find ~/unix/ -mmin -10
/home/student/unix/
/home/student/unix/hello.c

ค้นหาไฟล์ภายในไดเรกทอรี unix ที่มีการถูกเปลี่ยนแปลงสิทธิ์ไฟล์เมื่อ 10 นาทีที่ผ่านมา

$ find ~/unix/ -cmin -10
/home/student/unix/
/home/student/unix/result.txt
/home/student/unix/hello.c

ในกรณีที่ไม่ต้องการให้แสดงผลไฟล์ที่ถูกซ่อน (hidden file) ในผลลัพธ์ของการค้นหา สามารถใช้ -regex ดังตัวอย่างข้างล่าง

$ find ~/unix/ -amin -10 \( ! -regex ".*/\..*" \)
/home/student/unix/
/home/student/unix/hello.c

ในการค้นหาไฟล์ที่ต้องการบางครั้ง ถ้าผู้ใช้ต้องการตั้งเงื่อนไขแยกเป็น 2 ส่วนคือ ตรวจสอบสิทธิ์ และตรวจสอบขนาดไฟล์ สามารถเขียนให้อยู่ในรูปแบบดังตัวอย่างข้างล่าง

$ find / \( -perm -4000 -fprintf ~/unix/suid.txt '%#m %u %p\n' \) , \( -size +100M -fprintf ~/unix/big.txt '%-10s %p\n' \)

$ cat big.txt
510743705  /home/student/aosp/out/host/linux-x86/bin/clang
357304855  /home/student/aosp/out/host/linux-x86/bin/llvm-rs-cc
138665118  /home/student/aosp/out/host/linux-x86/obj/STATIC_LIBRARIES/libclangSema_intermediates/libclangSema.a
138104274  /home/student/aosp/out/host/linux-x86/obj/STATIC_LIBRARIES/libclangStaticAnalyzerCheckers_intermediates/libclangStaticAnalyzerCheckers.a
160314665  /home/student/aosp/out/host/linux-x86/obj/lib/libbcc.so
...
 
$ cat suid.txt
04755 root /bin/ping6
04755 root /bin/su
04755 root /bin/fusermount
04755 root /bin/umount
04755 root /bin/mount
04755 root /bin/ping
04755 root /usr/bin/chfn
06755 daemon /usr/bin/at
04755 root /usr/bin/lppasswd
04755 root /usr/bin/sudoedit
04755 root /usr/bin/arping
04755 root /usr/bin/gpasswd
...

grep

คำสั่ง grep (Generalized Regular Expression Parser) เป็นคำสั่งที่มีการใช้งานบ่อยครั้งตั้งแต่ระดับคอมพิวเตอร์ตั้งโต๊ะจนไปถึงบอร์ดสมองกลฝังตัวที่มีระบบปฏิบัติการลีนุกซ์อยู่ภายในโดยหน้าที่ของคำสั่งนี้คือการค้นหาข้อความที่อยู่ภายในไฟล์ที่ต้องการตามเงื่อนไขที่ตั้งไว้ ตัวอย่างเช่น

$ grep ".*passwd" suid.txt 
04755 root /usr/bin/lppasswd
04755 root /usr/bin/gpasswd
04755 root /usr/bin/passwd
04755 student /home/student/Downloads/poky-dylan-9.0.0/build/tmp/work/i586-poky-linux/shadow/4.1.4.3-r13/package/usr/bin/passwd.shadow
...

ตารางตัวดำเนินการสำหรับคำสั่ง grep

ตัวดำเนินการคำอธิบาย

?

เจออย่างน้อย 1 ตัวอักขระ

*

เจออย่างน้อย 0 หรือ มากกว่าหลายตัวอักขระ

+

เจออย่างน้อย 1 หรือ มากกว่าหลายตัวอักขระ

^

ค้นหาเฉพาะขึ้นต้นบรรทัด

$

ค้นหาเฉพาะท้ายบรรทัด

[ ]

ค้นหาตัวอัขระใดตัวอักขระหนึ่งที่อยู่ใน [ ]

{n}

เจอซ้ำเป็นจำนวน n ครั้ง

{n,}

เจอซ้ำเป็นจำนวนตั้งแต่ n ครั้ง หรือมากกว่า

{n,m}

เจอซ้ำเป็นจำนวนตั้งแต่ n ครั้งจนถึง m ครั้้ง

\char

ค้นหาตัวอักขระ char

-E ‘pattern1 .* pattern2

ค้นหา pattern1 และ pattern2

-E ‘pattern1 | pattern2

ค้นหา pattern1 หรือ pattern2

ตัวอย่างการใช้คำสั่ง grep เพื่อค้นหาคำจากผลลัพธ์ของคำสั่ง ls -al

$ ls -al
total 61
drwxr-xr-x  4 student student  4096 2013-09-20 05:09 .
drwxr-xr-x 37 student student  4096 2013-09-11 20:53 ..
-rw-r--r--  1 student student  5160 2013-09-18 00:04 big.txt
-rw-r--r--  1 student student    53 2013-08-21 05:16 error.log
-rwxr-xr-x  1 student student  8497 2013-08-21 06:05 hello
-rw-r--r--  1 student student    93 2013-09-17 19:16 hello.c
drwxr-xr-x  2 student student  4096 2013-09-17 18:04 .my_hidden_directory
-rw-r--r--  1 student student     0 2013-09-17 18:04 .my_hidden_file
-rw-r--r--  1 student student     0 2013-09-20 05:09 mytest.txt
-rw-r--r--  1 student student    72 2013-09-20 05:09 number
-rw-r--r--  1 student student     0 2013-09-20 04:48 test1.txt
-rw-r--r--  1 student student     0 2013-09-20 04:48 test.txt
$ ls -al | grep test?.txt
-rw-r--r--  1 student student     0 2013-09-20 04:48 test1.txt

ในกรณีที่จะใช้ตัวดำเนินการ “+” จำเป็นต้องใช้โปรแกรมรุ่นใหม่ของโปรแกรม grep คือโปรแกรม egrep (Extended Grep) ดังตัวอย่างข้างล่าง

$ ls -al | egrep test+.txt
-rw-r--r--  1 student student     0 2013-09-20 05:09 mytest.txt
-rw-r--r--  1 student student     0 2013-09-20 04:48 test.txt

ในกรณีที่ต้องการค้นหาตัวเลขตามจำนวนหลักที่ต้องการ สามารถใช้ตัวดำเนินการ [ ] และ {n} ดังตัวอย่างข้างล่าง

$ cat numbers
ID 3710166
Telephone No. 0891234122
City Code 20131
Phone No. 038191772


$ grep  "[0-9]\{5\}$" numbers
City Code 20131

ถ้าต้องการค้นหาที่มีตัวเลขตั้งแต่ 7 หลักขึ้นไปจะใช้ตัวดำเนินการ {m, } ดังตัวอย่างข้างล่าง

$ grep  "[0-9]\{7,\}$" numbers
ID 3710166
Telephone No. 0891234122
Phone No. 038191772

การค้นหาข้อมูลภายในไฟล์ log นักพัฒนาสามารถทำการวิเคราะห์เบื้องต้นได้ด้วยตัวดำเนินการ -E ‘pattern1 | pattern2’ ดังตัวอย่างของข้อมูล log ข้างล่างนี้

$ cat data.log 
1  Station01 Temp_Sensor 35.4
2  Station02 Flow_Sensor 12.4
3  Station03 Light_Sensor 55
4  Station04 Motion_Sensor ON
5  Station05 Current_Sensor 1.42

สามารถใช้คำสั่ง grep เพื่อค้นหาข้อมูลภายในได้ 4 รูปแบบ ได้แก่

(แบบที่ 1) $ grep -i 'station01\|station03' data.log 
1  Station01 Temp_Sensor 35.4
3  Station03 Light_Sensor 55


(แบบที่ 2) $ grep -i -E 'station01|station03' data.log 
1  Station01 Temp_Sensor 35.4
3  Station03 Light_Sensor 55


(แบบที่ 3) $ grep -i -e station01 -e station03 data.log 
1  Station01 Temp_Sensor 35.4
3  Station03 Light_Sensor 55
(แบบที่ 4) $ egrep -i 'station01|station03' data.log 
1  Station01 Temp_Sensor 35.4
3  Station03 Light_Sensor 55

เมื่อต้องการค้นหาคำที่อยู่ตำแหน่งต้นบรรทัด จะใช้ “^” นำหน้าคำที่ต้องการค้นหา หรือคำที่อยู่ตำแหน่งปลายบรรทัด จะใช้ “$” ต่อท้ายคำที่ต้องการค้นหา ดังตัวอย่างข้างล่าง

$ grep "^Sep 11" messages.1 
Sep 11 21:16:58 EE-Burapha rsyslogd: [origin software="rsyslogd" swVersion="4.2.0" x-pid="691" x-info="
http://www.rsyslog.com
"] rsyslogd was HUPed, type 'lightweight'.
Sep 11 21:44:29 EE-Burapha kernel: [ 3077.192891] e1000: eth0 NIC Link is Down
Sep 11 21:45:17 EE-Burapha kernel: [ 3125.462088] e1000: eth0 NIC Link is Up 1000 Mbps Full Duplex, Flow Control: None
Sep 11 21:46:58 EE-Burapha kernel: [ 3222.009399] e1000: eth0 NIC Link is Down
Sep 11 21:47:04 EE-Burapha kernel: [ 3227.275574] e1000: eth0 NIC Link is Up 1000 Mbps Full Duplex, Flow Control: None
...


$ grep "Link is Down$" messages.1 
Sep 11 21:44:29 EE-Burapha kernel: [ 3077.192891] e1000: eth0 NIC Link is Down
Sep 11 21:46:58 EE-Burapha kernel: [ 3222.009399] e1000: eth0 NIC Link is Down
Sep 11 21:47:07 EE-Burapha kernel: [ 3230.682704] e1000: eth0 NIC Link is Down
Sep 11 21:53:34 EE-Burapha kernel: [ 3310.165309] e1000: eth0 NIC Link is Down
Sep 11 21:54:02 EE-Burapha kernel: [ 3338.102673] e1000: eth0 NIC Link is Down
...

การค้นหาคำที่มีอักขระพิเศษอยู่ด้วยนั้น จะต้องใช้ตัวดำเนินการ \ นำหน้าตัวอักขระพิเศษเสมอ ดังตัวอย่างข้างล่าง

$ grep "255\.255\.255\.255" syslog.1 
Sep 18 11:36:12 EE-Burapha dhclient: DHCPDISCOVER on eth0 to 255.255.255.255 port 67 interval 3
Sep 18 11:36:13 EE-Burapha dhclient: DHCPREQUEST of 172.16.56.134 on eth0 to 255.255.255.255 port 67
Sep 18 19:54:11 EE-Burapha dhclient: DHCPDISCOVER on eth0 to 255.255.255.255 port 67 interval 3
Sep 18 19:54:12 EE-Burapha dhclient: DHCPREQUEST of 172.16.56.134 on eth0 to 255.255.255.255 port 67
Sep 20 04:50:05 EE-Burapha dhclient: DHCPDISCOVER on eth0 to 255.255.255.255 port 67 interval 5
Sep 20 04:50:06 EE-Burapha dhclient: DHCPREQUEST of 172.16.56.134 on eth0 to 255.255.255.255 port 67

ตารางตัวดำเนินการเพิ่มเติมสำหรับคำสั่ง grep

OperatorDescription

[:digit:]

เฉพาะตัวเลขตั้งแต่ 0 ถึง 9

[:alnum:]

ทั้งตัวอักษร A ถึง Z หรือ a ถึง z และตัวเลขตั้งแต่ 0 ถึง 9

[:alpha:]

ตัวอักษร A ถึง Z หรือ a ถึง z

[:blank:]

เฉพาะช่องว่าง (Space) และแท๊ป (TAB) เท่านั้น

จากตารางข้างต้น เป็นการระบุตัวอักขระในแต่ละประเภทเพื่อให้การค้นหามีประสิทธิภาพมากขึ้น ดังตัวอย่างการใช้งานดังนี้

$ grep "anacron\[[[:digit:]]\+\]" /var/log/syslog.1
Sep 18 08:50:17 EE-Burapha anacron[27155]: Job `cron.daily' terminated
Sep 18 08:50:17 EE-Burapha anacron[27155]: Job `cron.weekly' started
Sep 18 08:50:17 EE-Burapha anacron[27530]: Updated timestamp for job `cron.weekly' to 2013-09-18
Sep 18 08:50:18 EE-Burapha anacron[27155]: Job `cron.weekly' terminated
...

การรวมคำสั่งเข้าด้วยกัน ด้วยสัญญลักษณ์ที่เรียกว่า Pipe (|) โดยเอาท์พุตของคำสั่งแรกจะเป็นอินพุตของคำสั่งถัดไป จนกระทั่งถึงคำสั่งสุดท้ายที่จะแสดงผลลัพธ์สู่หน้าจอ ดังตัวอย่างการใช้ดังนี้

$ ls <ไดเรกทอรี> | grep <คำค้นหา>

$ ls -al | grep "^d"
drwxr-xr-x  4 student student  4096 2013-09-21 02:21 .
drwxr-xr-x 37 student student  4096 2013-09-11 20:53 ..
drwxr-xr-x  2 student student  4096 2013-09-17 18:04 .hidden_directory
drwxr-xr-x  2 student student  4096 2013-09-17 18:03 out

Last updated

Assoc. Prof. Wiroon Sriborrirux, Founder of Advance Innovation Center (AIC) and Bangsaen Design House (BDH), Electrical Engineering Department, Faculty of Engineering, Burapha University