جستجو فایلها در لینوکس – بخش دوم
از آنجایی که مبحث جستجو فایلها مبحثی طولانی بود؛ ادامه آن را در این بخش شرح میدهیم.
اکشنها (Actions)
داشتن لیستی از نتایج فرمان find مفید است ولی کاری که ما واقعا میخواهیم انجام دهیم این است که بر روی آیتمهای لیست حرکتی انجام دهیم. خوشبختانه فرمان find به اکشنها این اجازه را میدهد تا بر روی نتایج جستجو اعمال شوند.
اکشنهای از قبل تعریف شده (Predefined Actions)
دستهای از اکشنهای از قبل تعریف شده وجود دارند و راههای مختلفی هم برای اعمال این اکشنهای تعریف شده توسط کاربر وجود دارد. اول نگاهی به لیستی از اکشنهای از قبل تعریف شده در جدول زیر بیندازیم:
| اکشن | توضیحات |
|---|---|
| -delete | حذف فایل منطبق فعلی |
| -ls | انجام معادل فرمان -ls dils بر روی فایل منطبق. خروجی به خروجی استاندارد ارسال میگردد. |
| خروجی نام مسیر کامل از فایل منطبق به خروجی استاندارد. این اکشن پیشفرض است در صورتی که هیچ اکشن دیگری تعیین نشده باشد. | |
| -quit | خروج زمانی که یک مطابقت صورت پذیرد. |
علاوه بر جدول، اکشنهای تعریف شده زیاد دیگری وجود دارد که برای مطالعه بیشتر به صفحه manual فرمان find مراجعه کنید. در مثال اول ما این فرمان را انجام دادیم:
find ~
این فرمان لیستی از هر فایل و زیردایرکتوری که درون دایرکتوری home وجود دارد را ایجاد میکند. این فرمان پس از ایجاد لیست، آن را چاپ میکند. چرا؟ چون در صورتی که هیچ اکشنی اعمال نشود، اکشن –print به صورت پیشفرض اعمال میشود. در نتیجه فرمان بالا را به این صورت هم میتوانیم بنویسیم:
find ~ -print
ما میتوانیم از فرمان find به منظور حذف فایلهایی که در برخی موقعیتها قرار دارند استفاده کنیم. برای مثال، برای حذف فایلهایی که دارای پسوند .BAK هستند (که اغلب برای فایلهای بکاپ در نظر گرفته شدهاند) میتوانیم از فرمان زیر استفاده کنیم:
find ~ -type f -name '*.BAK' -delete
در این مثال هر فایل که در پوشه home قرار دارد (و همه زیرشاخههایش) به منظور جستجو پسوند *.BAK در نظر گرفته میشوند. وقتی که پیدا شدند حذف خواهند شد (نه اینکه در صفحه نمایش نتایجی به ما نشان داده شود). البته همیشه در استفاده از اکشن –delete دقت کنید.
قبل از اینکه بیشتر توضیح دهیم بگذارید ببینیم که عملگرهای منطقی چگونه بر روی اکشنها اثر میگذارند. این فرمان را در نظر بگیرید:
find ~ -type f -name '*.BAK' -print
همانطور که دیدیم این فرمان به دنبال هر فایل ساده که دارای الگوی *.BAK میگردد و خروجی را در صفحهنمایش نشان میدهد. هر چند دلیل اینگونه عملکرد رابطه منطقی بین هر تست و اکشن است. به یاد بیاورید که به صورت پیشفرض –and این رابط را ایجاد میکند (هر چند نیازی به قرار دادن –and نیست چون به صورت پیشفرض اعمال میشود). در نتیجه فرمان را به این صورت میتوانیم بنویسیم:
find ~ -type f -and -name '*.BAK' -and -print
به جدول زیر نگاه کنید و ببینید که عملگرهای منطقی چگونه بر اجرای این فرمان تاثیر میگذارند.
| تست یا اکشن | زمانی انجام میشود که |
|---|---|
| -type f و -name '*BAK' صحیح هستند. | |
| -name '*.BAK' | -type f درست است |
| -type f | همیشه انجام میشود از آنجایی که اولین تست یا اکشن در یک ارتباط -and میباشد. |
از آنجایی که رابطه منطقی بین تستها و اکشنها تشخیص میدهد که کدام یک اجرا شوند، ما میتوانیم ببینیم که ترتیب تستها و اکشنها مهم هستند. برای مثال اگر ترتیب تستها و اکشنها را تغییر دهیم و در نتیجه اکشن –print اول بیاید، عملکرد فرمان نیز کاملا متفاوت خواهد بود:
find ~ -print -and -type f -and -name '*.BAK'
این نسخه از فرمان هر فایلی را نمایش میدهد (اکشن –print همیشه مقدار true را بازمیگرداند) و سپس نوع فایل و پسوند تست میشود (که آن چیزی نیست که ما میخواهیم، پس ترتیب مهم است).
اکشنهای تعریف شده توسط کاربر (User Defined Actions)
علاوه بر اکشنهای از پیش تعریف شده میتوانیم فرمانهای اختیاری را به کار بگیریم. راه سنتی انجام این کار استفاده از –exec میباشد:
-exec command {} ;
در این حالت عبارت command نام یک فرمان است، آکولاد یک ارایه سمبولیک از نام مسیر فعلی است و علامت سمیکالن (;) یک نشانگر جداکننده در آخر خط فرمان است. این هم یک مثال استفاده از اکشن –exec است:
-exec rm '{}' ';'
باز هم دقت کنید چون علامت آکولادو سمیکالن معنی خاصی در شل (Shell) دارند، بایستی با استفاده از کوتیشن آنها را در خط فرمان نادیده بگیریم.
علاوه بر –exec میتوانیم از اکشن –ok برای اجرای اکشنهای تعریف شده توسط کاربر استفاده کنیم. با استفاده –ok قبل از اجرای هر فرمان از کاربر پاسخی خواسته میشود. به صورت زیر:
find ~ -type f -name 'foo*' -ok ls -l '{}' ';'
< ls ... /home/me/bin/foo > ? y
-rwxr-xr-x 1 me me 224 2011-10-29 18:44 /home/me/bin/foo
< ls ... /home/me/foo.txt > ? y
-rw-r--r-- 1 me me 0 2012-09-19 12:53 /home/me/foo.txt
در این مثال، فایلهایی که با رشته foo شروع میشوند را جستجو کرده و هر وقت موردی که پیدا شد از ما سوال میکند و در صورتی که پاسخ yes بدهیم فرمان ls –l اجرا خواهد شد.
بهبود بهرهوری (Improving Efficiency)
وقتی که اکشن –exec استفاده میشود، هر بار که مطابقتی یافت میگردد، نمونهای از فرمان اختصاص یافته نیز اجرا میشود. برخی مواقع ما ترجیح میدهیم که همه نتایج بدست آمده را ترکیب کنیم و یک نمونه از فرمان را اجرا نماییم. برای مثال به جای اجرای فرمانهای زیر:
ls -l file1 ls -l file2
ترجیح میدهیم که فرمان را به این صورت اجرا کنیم:
ls -l file1 file2
اینجاست که فرمان را به جای چندین بار، فقط یکبار اجرا میکنیم. دو شیوه برای انجام این کار وجود دارد. شیوه سنتی این است که از فرمان خارجی xargs استفاده کنیم و راه جایگزین استفاده از یک ویژگی جدید در خود فرمان find هست. ابتدا شیوه جدید را توضیح میدهیم.
با تغییر علامت (;) به علامت (+) در واقع فرمان find توانایی لازم برای ترکیب نتایج جستجو به یک لیست آرگومان برای اجرای یک فرمان نهایی را پیدا میکند. به مثال زیر توجه کنید:
find ~ -type f -name 'foo*' -exec ls -l '{}' ';'
-rwxr-xr-x 1 me me 224 2011-10-29 18:44 /home/me/bin/foo
-rw-r--r-- 1 me me 0 2012-09-19 12:53 /home/me/foo.txt
مثال بالا را میتوانیم به صورت زیر هم بنویسیم:
find ~ -type f -name 'foo*' -exec ls -l '{}' +
-rwxr-xr-x 1 me me 224 2011-10-29 18:44 /home/me/bin/foo
-rw-r--r-- 1 me me 0 2012-09-19 12:53 /home/me/foo.txt
نتیجه حاصله همان است فقط سیستم فرمان ls را به جای دوبار، یکبار اجرا میکند.
همچنین میتوانیم به شیوه سنتی و از فرمان xargs برای دریافت همان نتایج استفاده کنیم. xargs ورودی را از استاندارد ورودی دریافت میکند و آن را به یک لیست آرگومان برای فرمان تعیین شده تبدیل میکند. برای فرمان بالا به صورا زیر عمل میکنیم:
find ~ -type f -name 'foo*' -print | xargs ls -l -rwxr-xr-x 1 me me 224 2011-10-29 18:44 /home/me/bin/foo -rw-r--r-- 1 me me 0 2012-09-19 12:53 /home/me/foo.txt
همانطور که میبینید خروجی فرمان find را در داخل xargs پایپ میکنیم که در مقابل، یک لیست آرگومان برای فرمان ls ایجاد کرده و سپس آن را اجرا میکند. نتیجه حاصله تفاوتی نمیکند.
تمرین فرمان find و گزینههای ممکن آن
اکنون زمان آن رسیده که فرمان find را به صورت عملی به کار بگیریم. در ابتدا یک محیط آزمایشی با زیرشاخهها و فایلهای زیاد ایجاد میکنیم:
[me@linuxbox ~]$ mkdir -p playground/dir-{00{1..9},0{10..99},100}
[me@linuxbox ~]$ touch playground/dir-{00{1..9},0{10..99},100}/file-{A..Z}
با این دو خط کد پوشهای با نام playground ایجاد کردیم که حاوی ۱۰۰ زیرپوشه و هر زیرپوشه حاوی ۲۶ فایل خالی است. این کار را با استفاده از رابط گرافیکی انجام دهید و ببینید که چقدر زمانبر خواهد بود!
متدی که برای ایجاد پوشهها به کار گرفته مستلزم آشنایی با گزینههای فرمان mkdir نحوه استفاده از بسط بریسها و فرمان touch است. با ترکیب فرمان mkdir با گزینه –p (که موجب ایجاد زیرشاخهها در مسیرهای اختصاصی میشود) با بسط بریسها قادر به ایجاد ۱۰۰ شاخه هستیم.
فرمان touch معمولا به منظور بروزرسانی یا تغییر فایلها به کار میرود. هر چند در اینجا برای ایجاد فایل خالی به کار رفته است. در داخل محیط کاری ما ۱۰۰ نمونه از یک فایل ایجاد کردیم که file-A نام دارد. اکنون با استفاده از فرمان find آنها را جستجو میکنیم.
[me@linuxbox ~]$ find playground -type f -name 'file-A'
قابل ذکر است که بر خلاف ls فرمان find نتایج را مرتب نمیکند. ترتیب آن بر اساس ترتیب دیوایس ذخیرهسازی نمایش داده میشود. ما میتوانیم داشتن ۱۰۰ نمونه از فایل را با استفاده از فرمان زیر تایید کنیم:
[me@linuxbox ~]$ find playground -type f -name 'file-A' | wc -l 100
اکنون میخواهیم فایلها را بر اساس زمان ویرایش، پیدا کنیم. این کار زمانی مفید است که بخواهیم فایلهای بکاپ ایجاد کنیم و یا فایلها را بر اساس زمانبندی مرتب کنیم. به این منظور ابتدا بایستی یک فایل مرجع ایجاد کنیم که زمان تغییر را بر اساس آن مقایسه کنیم.
[me@linuxbox ~]$ touch playground/timestamp
این فرمان یک فایل خالی با نام timestamp ایجاد میکند و زمان تغییر آن را بر اساس زمان حال قرار میدهد. میتوانیم این را با استفاده از یک فرمان دیگر با نام stat انجام دهیم، که یک نسخه ارتقایافته از فرمان ls است. فرمان stat نشان میدهد که سیستم فایل و مشخصههای آن را درک میکند:
[me@linuxbox ~]$ stat playground/timestamp File: `playground/timestamp' Size: 0 Blocks: 0 IO Block: 4096 regular empty file Device: 803h/2051d Inode: 14265061 Links: 1 Access: (0644/-rw-r--r--) Uid: ( 1001/ me) Gid: ( 1001/ me) Access: 2012-10-08 15:15:39.000000000 -0400 Modify: 2012-10-08 15:15:39.000000000 -0400 Change: 2012-10-08 15:15:39.000000000 -0400
اگر فایل را دوباره تغییر دهیم و دوباره فرمان stat را بر روی آن اجرا کنیم، خواهیم دید که زمان تغییر میکند:
[me@linuxbox ~]$ touch playground/timestamp [me@linuxbox ~]$ stat playground/timestamp File: `playground/timestamp' Size: 0 Blocks: 0 IO Block: 4096 regular empty file Device: 803h/2051d Inode: 14265061 Links: 1 Access: (0644/-rw-r--r--) Uid: ( 1001/ me) Gid: ( 1001/ me) Access: 2012-10-08 15:23:33.000000000 -0400 Modify: 2012-10-08 15:23:33.000000000 -0400 Change: 2012-10-08 15:23:33.000000000 -0400
سپس با استفاده از فرمان find برخی از فایلهای محیط خود را بروزرسانی میکنیم:
[me@linuxbox ~]$ find playground -type f -name 'file-B' -exec touch '{}' ';'
این فرمان تمامی فایلهای playground که file-B نام دارند را بروز میکند. سپس از فرمان find استفاده میکنیم تا فایلهای بروز شده شناسایی شوند (با مقایسه کردن همه فایلها با فایل مرجع timestamp).
[me@linuxbox ~]$ find playground -type f -newer playground/timestamp
نتیجه شامل ۱۰۰ نمونه از فایلهای file-B است. از آنجایی که یک touch بر روی همه فایلهای موجود در playground که دارای نام file-B هستند انجام دادیم و این کار پس از آنکه فایل timestamp را بروز کردیم صورت پذیرفته، اکنون آنها نسبت به فایل timestamp جدیدتر هستند، در نتیجه در تست –newer قابل شناساییاند.
[me@linuxbox ~]$ find playground \( -type f -not -perm 0600 \) -or \( -type d -not -perm 0700 \)
این فرمان لیست تمام ۱۰۰ پوشه و ۲۶۰۰ فایل موجود در playground (به اضافه خود پوشه playground و فایل timestamp که در مجموع میشود ۲۷۰۲) رابرمیگرداند چرا که هیچ کدام از اینها تعریف ما از یک مجوز درست را ندارند. با داشتن دانش کافی درباره عملگرها و اکشنها، میتوانیم اکشنها را به این فرمان اضافه کنیم تا مجوزهای جدید اعمال کنیم:
[me@linuxbox ~]$ find playground \( -type f -not -perm 0600 -exec chmod 0600
'{}' ';' \) -or \( -type d -not -perm 0700 -exec chmod 0700 '{}' ';' \)
گزینهها
در نهایت همه گزینهها را داریم. گزینههایی که به منظور کنترل گستره یک جستجو با find استفاده میشوند. آنها ممکن است در دیگر تستها و اکشنها ترکیب شوند. جدول زیر رایجترین آنها را به شما نشان میدهد:
| گزینه | توضیحات |
|---|---|
| -depth | جستجو مستقیم به منظور پردازش فایلهای یک پوشه قبل خود پوشه. این گزینه وقتی که اکشن -delete تعیین میشود بهصورت خودکار اعمال میگردد. |
| -maxdepth levels | تعیین بیشینه تعداد سطوحی که فرمان find هنگام ایجاد تستها و اکشنها بر روی یک ساختار درختی سرازیر میشود |
| -mindepth levels | تعیین کمینه تعداد سطوحی که فرمان find هنگام ایجاد تستها و اکشنها بر روی یک ساختار درختی سرازیر میشود |
| -mount | جستجو مستقیم نه برای عبور از پوشههایی که بر روی سیستمهای فایل سوار شدهاند. |
| -noleaf | جستجو مستقیم نه به منظور بهینهسازی جستجو فایل سیستم لینوکسی است. این زمانی مورد نیاز است که میخواهیم یک سیستم فایل ویندوزی را اسکن کنیم. |
درباره فرشید نوتاش حقیقت
همیشه نیازمند یک منبع آموزشی فارسی در حوزه نرمافزارهای آزاد/ متنباز و سیستمعامل گنو/لینوکس بودم. از این رو این رسالت رو برای خودم تعریف کردم تا رسانه «محتوای باز» رو بوجود بیارم.
نوشتههای بیشتر از فرشید نوتاش حقیقتاین سایت از اکیسمت برای کاهش جفنگ استفاده میکند. درباره چگونگی پردازش دادههای دیدگاه خود بیشتر بدانید.
دیدگاهتان را بنویسید