Fayl va matn qidirish: find, locate va grep
"Fayl qayerda?" va "bu xabar qaysi faylda yozilgan?" — ikki xil savol, garchi yangi boshlovchilar ikkalasiga ham ko'pincha bitta buyruq bilan javob izlasa ham. find va locate fayllarni yo'li, nomi va metama’lumotlari bo'yicha qidiradi. grep esa faylning ichidagi matnni qatorma-qator qidiradi. To'g'ri vositani tanlash vaqtni tejaydi va ruxsat xatosini "hech narsa topilmadi" deb noto'g'ri tushunib qolishning oldini oladi.
Misollar Ubuntu Server LTS’da, Bash muhitida, GNU Findutils va GNU Grep bilan ishlashga mo'ljallangan. Sizga Fayl va katalog buyruqlari maqolasidagi qo'shtirnoqlar va wildcard’lar, Matnli fayllarni ko'rish maqolasidagi standart chiqish (stdout) va standart xato (stderr) tushunchalari tanish bo'lishi kerak. Quyida find bilan nom, tur, hajm va vaqt bo'yicha qidirishni, grep natijasi va chiqish holatini to'g'ri o'qishni, shuningdek nomida bo'sh joy yoki yangi qator belgisi bor fayllarni natijani buzmasdan qayta ishlashni ko'rib chiqamiz.
Laboratoriyani tayyorlash
mkdir -p ~/lab/search/{config,logs,archive}
printf 'listen_port=8080\nenv=production\n' > ~/lab/search/config/app.conf
printf 'level=INFO order_id=ord-1001 message=checkout started\n' > ~/lab/search/logs/app.log
printf 'level=ERROR order_id=ord-1002 message=payment gateway timeout\n' >> ~/lab/search/logs/app.log
printf 'level=error order_id=ord-1003 message=invalid card\n' > ~/lab/search/logs/auth.log
printf 'quarterly report draft\n' > ~/lab/search/archive/report.txt
touch -d '10 days ago' ~/lab/search/archive/report.txt
find ~/lab/search -maxdepth 3 -printf '%y %p\n'
touch -d — GNU Coreutils’ning kengaytmasi. U faqat shu laboratoriya faylining vaqt tamg'asini o'zgartiradi, shunda keyingi -mtime va -newer misollarida solishtirishga arziydigan narsa bo'ladi.
find: ishlab turgan fayl tizimini aylanib chiqish
find buyrug'ining umumiy ko'rinishi:
Bu yerda:
~/lab/search— boshlang'ich nuqta, qidiruv shu yerdan boshlanadi.-type f— oddiy fayllarni tanlaydigan test.-name '*.log'— fayl nomini (basename) andoza bilan solishtiradigan test.-print— har bir mos kelgan yo'lni standart chiqishga yozadigan amal.
Ikki test orasida hech qanday operator bo'lmasa, find ularni mantiqiy VA (-a) bilan bog'langan deb hisoblaydi. '*.log' andozasi qo'shtirnoqqa olingan: shunda uni har bir nomzod fayl uchun find o'zi tekshiradi. Aks holda Bash uni find ishga tushishidan oldinroq joriy katalogdagi fayllar bilan almashtirib yuborgan bo'lardi.
Boshlang'ich nuqtani doim aniq yozing. U yozilmasa, GNU find . ni (joriy katalogni) oladi, lekin skript qaysi katalogdan ishga tushirilganiga qarab natija bilinmay o'zgarib qolishi mumkin.
Nom va yo'l bo'yicha qidirish
find ~/lab/search -type f -name '*.conf'
find ~/lab/search -type f -iname '*.LOG'
find ~/lab/search -path '*/archive/*'
-name fayl nomini katta-kichik harfni farqlagan holda solishtiradi, -iname harf registriga e’tibor bermaydi, -path esa faqat oxirgi qismni emas, butun yo'lni solishtiradi. -iname ning Unicode harflar bilan aniq qanday ishlashi locale va dastur versiyasiga bog'liq. Shu sabab avtomatlashtirishda registrni farqlamaydigan qidiruvga tayangandan ko'ra, fayllarni bir xil qoidada nomlash ishonchliroq.
Tur, chuqurlik, hajm va vaqt
find ~/lab/search -maxdepth 2 -type d -print
find ~/lab/search -type f -size +1k -print
find ~/lab/search -type f -mtime +7 -print
find ~/lab/search -type f -newer ~/lab/search/config/app.conf -print
-type foddiy fayllarni,-type dkataloglarni,-type lsymbolic link’larni tanlaydi.-maxdepth 2qidiruvni boshlang'ich nuqtadan pastga qarab ikki daraja bilan cheklaydi.-size +1kGNUfindda 1024 baytdan katta fayllarni tanlaydi.-mtime +7o'zgartirilgan vaqti oxirgi yettita to'liq 24 soatlik davrdan oldinroq bo'lgan fayllarni tanlaydi.-newer FILEhar bir faylning o'zgartirilgan vaqtini namuna faylning o'zgartirilgan vaqti bilan solishtiradi.
-mtime 1 ni kalendar ma’nosidagi "kecha" deb tushunmang. GNU find vaqtni mahalliy yarim tundan emas, buyruq ishga tushgan paytdan boshlab 24 soatlik davrlarga bo'lib hisoblaydi. Daqiqagacha aniqlik kerak bo'lsa, -mmin dan foydalaning. Aynan kalendar kuni chegarasi kerak bo'lsa, o'z tizimingizdagi man find dan -daystart opsiyasini o'qing.
Testlarni mantiqiy operatorlar bilan birlashtirish
Qavslar qochirilgan (\), chunki shell ularni maxsus belgi deb tushunadi. Qavslarsiz -a, -o va ! operatorlarining ustuvorligi siz kutmagan natija berishi mumkin. Inkor quyidagicha yoziladi:
Topilgan fayllar ustida amal bajarish
Faqat o'qiydigan misol:
{} o'rniga topilgan yo'llar qo'yiladi, + esa iloji boricha ko'p yo'lni file buyrug'ining bitta chaqiruviga jamlaydi. Boshqa shakl — -exec ... {} \; — odatda har bir topilgan fayl uchun alohida yangi jarayon ishga tushiradi, shuning uchun katta katalog daraxtida ancha sekin ishlaydi.
Danger
find ... -delete, -exec rm, -exec chmod va -exec chown bir vaqtda ko'p faylni o'zgartiradi va sukut bo'yicha hech qanday tasdiq so'ramaydi. Ulardan birortasini production ma’lumotlariga qarshi ishlatishdan oldin aynan shu ifodani avval -print bilan ishga tushiring, qidiruv boshqa mount nuqtalariga o'tishi yoki symlink’lar ortidan borishi kerakmi-yo'qligini tekshiring va zaxira nusxa yoki VM snapshot oling. Hatto laboratoriyada ham yalang'och -exec rm o'rniga -ok (har bir amaldan oldin so'raydi) yoki alohida, ko'rib chiqilgan qadamni afzal ko'ring.
Ishonchi pastroq foydalanuvchi yoza oladigan kataloglarda -execdir yo'l bilan bog'liq ba’zi poyga (race) xavflarini kamaytiradi. Lekin u xavfsiz PATH ning va chaqirilayotgan buyruqning o'z ehtiyot choralarining o'rnini bosmaydi. Root sifatida ishlayotganda cheklanmagan find / ni troubleshooting’dagi odatiy qadamingizga aylantirmang.
find xatolarini o'qish: Permission denied
Haqiqiy tizimda find sizning foydalanuvchingiz kira olmaydigan kataloglarni ham aylanib chiqadi. Ularning har biri uchun standart xato oqimiga bitta qator yoziladi va bu qatorlar standart chiqishdagi topilgan natijalar bilan aralashib chiqadi:
Topilganlar (stdout) va xatolar (stderr) — ikki alohida oqim, ular shunchaki bitta terminalda chiqadi. Natijani biror joyga yo'naltirishingiz bilan aynan shu farq hal qiluvchi bo'lib qoladi:
find / -name '*.conf' 2>/dev/nullbarcha xatolarni yashiradi, jumladan noto'g'ri yozilgan yo'lni yoki bilishingiz kerak bo'lgan, haqiqatan o'qib bo'lmaydigan joyni ham. Natijada chala natija to'liq natijadan farq qilmay qoladi.find / -name '*.conf' 2>find-errors.logekranda topilganlarni toza ko'rsatadi, xatolarni esa keyin ko'rib chiqish uchun faylga saqlaydi. Qidiruv natijasiga ishonish kerak bo'lganda shu yo'l xavfsizroq.
stderr ni ko'r-ko'rona tashlab yuborish — find asosidagi tekshiruv (audit) jimgina kam natija ko'rsatishining eng keng tarqalgan sababi. Agar sizga haqiqatan faqat o'qish mumkin bo'lgan joylar kerak bo'lsa, buni ochiq ko'rsating: qidiruvni o'zingizga tegishli katalog ichidan boshlang. Qidiruv doirasi chala bo'lganini ko'rsatadigan dalilni o'chirib qo'ymang.
locate: indeks bo'yicha tezkor qidirish
Ubuntu LTS’da locate odatda plocate paketi orqali keladi va minimal o'rnatilgan tizimda bo'lmasligi mumkin:
Agar mavjud bo'lsa:
locate oldindan updatedb tuzib qo'ygan indeks bo'yicha qidiradi. Shu sababli u katta fayl tizimida ham tez ishlaydi. Buning evaziga indeks eskirgan bo'lishi mumkin:
- indeks oxirgi marta yangilangandan keyin yaratilgan fayl hali ko'rinmaydi;
- o'chirilgan fayl nomi bir muddat indeksda qolib ketishi mumkin;
updatedb.confba’zi yo'llar yoki fayl tizimlarini butunlay chiqarib tashlagan bo'lishi mumkin;- siz ko'radigan natija ishlab turgan fayl tizimiga emas, indeksning o'z ko'rinish qoidalariga bog'liq.
Fayl tizimining hozirgi, real vaqtdagi holati va metama’lumot bo'yicha filtrlar kerak bo'lsa, find dan foydalaning. Indeksni qayta qurish disk (I/O) yukini oshiradi va tizim siyosatiga bo'ysunadi, shuning uchun production’da bitta faylni topish uchun sudo updatedb ni ishga tushirmang. Ubuntu’da plocate indeksini yangilashni odatda systemd timer allaqachon bajarib turadi.
grep: fayllar ichidan qidirish
Aniq (literal) satrni qidirishda -F eng to'g'ri tanlov:
-n qator raqamini qo'shadi. Sukut bo'yicha grep faqat mos kelgan bo'lakni emas, butun qatorni chiqaradi. Faqat mos kelgan qismni chiqarish uchun -o ishlatiladi.
Ko'pincha birga ishlatiladigan opsiyalar:
grep -niF 'level=error' ~/lab/search/logs/*.log
grep -cF 'level=ERROR' ~/lab/search/logs/app.log
grep -vF 'level=INFO' ~/lab/search/logs/app.log
grep -lF 'timeout' ~/lab/search/logs/*.log
grep -C 1 -F 'timeout' ~/lab/search/logs/app.log
-iharf registrini farqlamaydi.-cqator ichidagi mosliklar sonini emas, mos kelgan qatorlar sonini chiqaradi.-vmos kelmagan qatorlarni tanlaydi.-lkamida bitta moslik topilgan har bir faylning faqat nomini chiqaradi.-C 1har bir moslikdan oldingi va keyingi bittadan qatorni ham ko'rsatadi.
Aniq matn, asosiy regex va kengaytirilgan regex
-F bilan har bir belgi o'z ma’nosida, ya’ni oddiy belgi sifatida qidiriladi. Oddiy grep asosiy regular expression’lardan (BRE), grep -E esa kengaytirilgan regular expression’lardan (ERE) foydalanadi. Regex’da ^ qator boshini, $ qator oxirini bildiradi, . istalgan bitta belgiga mos keladi, * esa oldingi elementni nol yoki undan ko'p marta takrorlaydi. Bu * shell’dagi wildcard * bilan bog'liq emas: shell’dagi * fayl nomlarini grep ga yetib kelishidan oldinroq kengaytiradi.
Qidiriladigan so'z ishonchsiz manbadan kelsa, grep -F -- "$needle" dan foydalaning:
-- - bilan boshlanadigan qiymatni grep opsiya deb qabul qilishining oldini oladi, o'zgaruvchini qo'shtirnoqqa olish esa so'zlarga bo'linish va globbing’ni to'xtatadi.
Rekursiv qidirish
-R symbolic link’lar ortidan borishi mumkin, -r esa odatda bormaydi. Shu sabab katalog daraxtida nima borligini aniq bilmasangiz, -r xavfsizroq tanlov. Katta repozitoriy yoki / bo'ylab nazoratsiz rekursiv qidiruv diskka sezilarli yuk beradi. Qidiruv doirasini --include, --exclude va --exclude-dir bilan toraytiring.
Chiqish holatini to'g'ri o'qish
GNU grep uchta chiqish holatini qaytaradi:
0: kamida bitta qator mos keldi.1: birorta ham qator mos kelmadi.2: xatolik yuz berdi (noto'g'ri andoza, o'qib bo'lmaydigan fayl va hokazo).
if grep -qF 'level=ERROR' ~/lab/search/logs/app.log; then
echo "found an ERROR line"
else
status=$?
if ((status == 1)); then
echo "no ERROR line found"
else
printf 'grep failed, status=%s\n' "$status" >&2
fi
fi
-q odatdagi chiqishni o'chiradi va shart ichida ishlatish uchun qulay. Bunga qo'shimcha 2>/dev/null yozsangiz, "moslik topilmadi" va "grep xato bilan tugadi" holatlarining farqi yashirinib qolishi mumkin. Bu farq muhim bo'lgan joyda bunday qilmang.
Nomida bo'sh joy va yangi qator bor fayllar
Linux’da fayl nomida yangi qator belgisi bo'lishi ham qonuniy. Shu sababli find ... -print | while read ... har qanday nom uchun ishonchli emas. Buning o'rniga yozuvlarni NUL bayt bilan ajrating:
find ~/lab/search -type f -name '*.log' -print0 |
while IFS= read -r -d '' file; do
printf 'file: %q\n' "$file"
done
Bash’dagi read -d '' NUL baytgacha o'qiydi. Natijani tashqi vositalarga uzatishda find -print0 va xargs -0 juftligi ko'p ishlatiladi. Lekin vazifaga mos kelsa, find -exec ... {} + soddaroq va xavfsizroq.
Ishni parallel bajarish: xargs -0 -P
find -exec ... {} + bitta buyruqni ishga tushiradi va unga sig'adigan barcha argumentlarni beradi. xargs ham xuddi shunday NUL bilan xavfsiz jamlashni beradi, ustiga -exec o'zi qila olmaydigan bitta imkoniyat qo'shadi: buyruqning bir nechta nusxasini bir vaqtda ishga tushirish.
findtomonidagi-print0har bir yo'lni yangi qator emas, NUL bayt bilan tugatadi. Shunda nomida bo'sh joy, tab yoki hatto yangi qator belgisi bor fayl ham bo'linib ketmaydi va noto'g'ri o'qilmaydi.xargstomonidagi-0unga kirishdagi ma’lumot NUL bilan ajratilganini bildiradi va-print0ga mos keladi.-P4gzipni birin-ketin emas, bir vaqtda to'rttagacha nusxada ishga tushiradi. Ko'p yadroli mashinada bir-biriga bog'liq bo'lmagan ko'plab fayllarni siqish, checksum hisoblash yoki formatini o'zgartirishda bu foydali, chunki har bir chaqiruv o'zining disk (I/O) va CPU ishini kutib turadi.-I{}har bir yo'lni buyruq shablonidagi{}o'rniga qo'yadi, har bir chaqiruvga bittadan yo'l.
-print0/-0 bo'lmasa, xargs sukut bo'yicha kirishni bo'sh joy va yangi qatorlar bo'yicha bo'ladi va nomida bo'sh joy yoki yangi qator bor faylni jimgina buzib yuboradi: bitta yo'l ikki yoki undan ko'p alohida argument bo'lib qoladi. Bu yuqoridagi read siklidagi muammoning aynan o'zi. "Skript mening test fayllarimda ishlaydi, production’da esa buziladi" degan xatolarning keng tarqalgan sababi ham shu, chunki production’dagi kataloglarda ertami-kechmi hech kim kutmagan nomli fayl paydo bo'ladi.
Intervyuda
Nega -print0/-0 muhim, deb so'rashsa, "bu zamonaviy usul" deb javob berish yetarli emas. To'g'ri javob: Linux’da fayl nomi / va NUL dan boshqa istalgan baytni, jumladan bo'sh joy va yangi qator belgisini o'z ichiga olishi mumkin. Shu sababli sukut bo'yicha bo'sh joy yoki yangi qator bo'yicha bo'ladigan har qanday vosita (xargs, sodda for f in $(find ...) yoki -d '' siz read) shu taxminni buzadigan fayl nomiga duch kelguncha faqat tasodifan xavfsiz ishlaydi.
Amaliy vaziyat: timeout’ning izini topish
Muammo: ilova katalogi ichida qaysi log fayllarida va aynan qaysi qatorlarda timeout so'zi uchrashini aniqlash kerak.
-
Avval qidiruv doirasini tasdiqlang va undagi fayllarni ro'yxatga oling:
-
Faqat log fayllarida, aniq satr sifatida qidiring:
-
Kattaroq katalog daraxtida glob’ga tayanish o'rniga rekursiyani cheklang:
-
Moslik atrofida nima bo'lganini ko'rish kerak bo'lsa, kontekst qo'shing:
Natijada fayl yo'li, qator raqami va hodisaning o'zi ko'rinadi. Production log'ini boshqalarga yuborishdan oldin undagi tokenlar, cookie’lar, email manzillar va boshqa maxfiy ma’lumotlarni yashiring.
Keng tarqalgan xatolar
findvagrepni bir-birining o'rnini bosadi deb hisoblash. Aslida biri nom va metama’lumot bo'yicha, ikkinchisi esa mazmun bo'yicha qidiradi.-name '*.log'ni qo'shtirnoqsiz qoldirib, shell unifindishga tushishidan oldin kengaytirib yuborishiga yo'l qo'yish.-mtime +1ni o'zgaruvchan 24 soatlik davr emas, kalendar ma’nosidagi "kechadan oldin" deb tushunish.locatefayl tizimining hozirgi, real vaqtdagi holatini ko'rsatadi deb o'ylash.grep -cmos kelgan qatorlar sonini emas, matnning har bir uchrashini sanaydi deb o'ylash.- Foydalanuvchi kiritgan matnni avval aniq satr sifatida ko'rib chiqmasdan, to'g'ridan-to'g'ri regex’ga berish.
grepning1chiqish holatini ish xatosi,2ni esa "moslik topilmadi" deb tushunish.- Ruxsat xatolarini
/dev/nullga tashlab, qidiruv to'liq bajarildi degan xulosaga kelish. - Nomida yangi qator bo'lishi mumkin bo'lgan fayllarni qatorlarga asoslangan pipeline bilan qayta ishlash.
- Zarurat bo'lmasa ham, odat bo'yicha root sifatida keng
find /qidiruvini ishga tushirish.
Mashqlar
- Laboratoriya katalogida
findyordamida faqat oddiy.conffayllarni toping va yozgan ifodangizning har bir qismini tushuntiring. - Ikkita qo'shimcha laboratoriya fayli yarating: biri 1 KiB dan katta, ikkinchisi oxirgi besh daqiqada o'zgartirilgan bo'lsin. Har bir shartni alohida ajratib oladigan
findifodasini yozing. - Mos ravishda
grep -F, oddiygrepvagrep -Ega mos keladigan uchta andoza yozing va har bir andoza uchun nega aynan shu rejim to'g'ri tanlov ekanini qayd eting. - Laboratoriya katalogi ichida
grepning0,1va2chiqish holatlarini xavfsiz tarzda hosil qiling. - Nomida bo'sh joy va yangi qator belgisi bor ikkita fayl yarating, so'ng ikkalasini
find -print0sikli bilan to'g'ri ro'yxatlang.
Mashqni bajardim deyish uchun: "moslik topilmadi", "qidiruvning o'zi xato bilan tugadi" va "indeks hali yangilanmagan" holatlari orasidagi farqni dalillar bilan tushuntirib bera olishingiz kerak.
Manbalar
- GNU Findutils qo'llanmasi: https://www.gnu.org/software/findutils/manual/html_node/find_html/index.html
- GNU Findutils: bir nechta fayl ustida buyruq bajarish: https://www.gnu.org/software/findutils/manual/html_node/find_html/Multiple-Files.html
- GNU Grep qo'llanmasi: https://www.gnu.org/software/grep/manual/grep.html
- GNU Grep: Exit Status: https://www.gnu.org/software/grep/manual/html_node/Exit-Status.html
- Ubuntu qo'llanma sahifasi:
plocate(1): https://manpages.ubuntu.com/manpages/noble/man1/plocate.1.html - Ubuntu qo'llanma sahifasi:
updatedb(8): https://manpages.ubuntu.com/manpages/noble/man8/updatedb.plocate.8.html