نوشته شده به وسیلهی: Mohsen در 1 سال 6 ماه پیش تحت عنوان راهنمای-نرم-افزار find
یادداشت نویسنده
کدهای این پست را بر روی سیستم FreeBSD نوشته و تست کردهام ولی بر روی سیستمهای لینوکسی هم اجرا میشوند.
فهرست مطالب
- مقدمه
- طرح چند پرسش
- جستجوی کلیهی فایل ها
- جستجو بر مبنای نام فایل
- ارسال خروجی find به xargs
- حل مشکل space در xargs و find
- جستجو بر مبنای نوع (type) فایل
- علامت + و -
- جستجو بر مبنای بزرگی (size) فایل
- جستجو بر مبنای سطح دسترسی (permission) فایل
- جستجو بر مبنای زمان ویرایش ، زمان دسترسی و زمان تغییر i-node
- جستجو بر مبنای صاحب (owner) و گروه (group) فایل
- جستجو بر مبنای i-number
- جستجوی فایلهای خالی (empty)
- سوییچ exec- و ok-
- استفاده از AND و OR و NOT
- پاسخ پرسش های مطرح شده
- پایان مطلب و نتیجهگیری
مقدمه🔗
find
یکی از مهمترین دستورات یونیکس و سیستمهای شبهیونیکس مانند لینوکس است که دیر یا زود به آن نیاز مبرمی پیدا میکنید. با یادگیری دستور find
و به کار بردن عملی آن در کارهای روزانه، هر روز میتوانید کاربرد جدیدی برای آن پیدا کنید، مثلا با اتصال خروجی این دستور به ورودی دستوری دیگر از طریق pipe میتوانید عملیات گوناگونی را روی فایلهایی که پیدا کردهاید انجام دهید و یا اینکه مستقیما از سوییچ -exec
دستور find
استفاده کنید. -exec
بر روی تمام فایلهای یافت شده اجرا خواهد شد و میتواند شامل هر دستوری باشد. وقتی که در find
خبره شدید احتمالا به خود خواهید گفت: «بدون آن چگونه زندگی میکردم؟!»
طرح چند پرسش🔗
- دنبال ویدیویی به نام moammaye_hasti.mp4 از شجریان میگردم ولی پیداش نمیکنم.
- فیلمهای سینمایی من همه بالای ۶۰۰-۷۰۰ مگابایت هستن ولی متاسفانه توی فولدرهای مختلف گم شدن. از همه بدتر اینکه اسمشون رو هم چیزهای الکی گذاشتم مثلا ddd.mp4 یا london.mp4
- ماه گذشته دو تا سی دی کامل mp3 کپی کردم توی کامپیوتر ولی همهشون رو گم کردم. خدای من! شتر با بارش گم شد!
- میخوام عکسهای موجود در این دایرکتوری و زیر دایرکتورهاش رو پاک کنم ولی دایرکتوری خیلی بزرگ و پر از اطلاعاته. حتی اگه وقتش رو داشته باشم و به صورت دستی این کار رو انجام بدم، اون موقع همش ناراحت اینم که آیا همه عکسها رو پاک کردم یا خدایی ناکرده چند تاییشون از دستم در رفته!
- میخوام لیست کل فایلهای این دایرکتوری و کلیه زیر دایرکتوریهاش رو به دست بیارم. ls کمکی بهم نکرد.
- میخوام کلیهی فایلهایی که owner شون reza است رو به نام mohsen در بیارم. می دونم که باید از chown استفاده کنم ولی از کجا همهی فایلهای رضا رو شناسایی کنم و چه طوری اون همه chown بنویسم؟
جواب این چند پرسش و بسیاری پرسشهای دیگر دستور find
است.
جستجوی کلیهی فایل ها🔗
شکل کلی و ساده دستور find
به صورت زیر است:
$ find path experssion
path مسیر مورد جستجو است. جستجو در کلیهی دایرکتوریهای زیر مجموعه path به صورت تو در تو (recursive) و تا آخرین دایرکتوری انجام میشود مگر اینکه عمق جستجو را معلوم کرده باشیم که در این صورت، جستجو تا عمق انتخاب شده انجام خواهد شد. عمق جستجو با استفاده از سوییچ -d
(ابتدای کلمه depth) مشخص میشود.
$ find path -d 3 other-experssions
در دستور بالا find
تا سه زیر دایرکتوری را جستجو میکند.
لیست کلیهی فایلها و دایرکتوریهای خانه (و زیر دایرکتوریهای آن)
$ find ~
این دستور فاقد experssion است و به صورت اتوماتیک لیست فایلهای یافت شده را در خروجی استاندارد چاپ می کند. ~
(تیلده) نشان دهندهی دایرکتوری خانه کاربرِ جاری است.
جستجو بر مبنای نام فایل🔗
برای جستجو بر مبنای نام فایل از دو سوییچ -name
و -iname
استفاده میکنیم. حرف i در ابتدای سوییچ -iname
از کلمهی case-insensitive میآید به این معنا که کوچکی و بزرگی حروف اهمیتی ندارد. چنانچه در عبارتی که جلوی سوییچها نوشته میشود از wildcard استفاده نکرده باشیم، find
دقیقا عبارت مورد نظر را جستجو میکند. در صورت استفاده از wildcard دستور find
بر مبنای wildcard تصمیم گیری میکند. * به معنای هر تعداد کاراکتر و ? به معنای دقیقا یک کاراکتر است.
جستجو کردن فایل moammaye_hasti.mp3 در دایرکتوری خانگی (و زیر دایرکتوریهای آن)
$ find ~ -iname "moammaye_hasti.mp3"
برای اینکه جستجو، هم فایلهای با حروف کوچک و هم فایلهای با حروف بزرگ را شامل شود از سوییچ -iname
استفاده میکنیم. اگر از اسم فایل اطمینان دارید میتوانید نام را دقیقا مانند نام فایل بنویسید و از سوییچ -name
استفاده کنید.
جستجو کردن کلیهی فایلهای mp3 علی
$ find ~ali -iname "*.mp3"
جستجو کردن کلیهی فایلهای پنهان موجود در دایرکتوری جاری و زیر دایرکتوریهای آن
$ find . -name ".*"
میدانید که فایل پنهان فایلی است که با .
(دات) شروع شود.
کلیهی فایلها و دایرکتوریهای سه حرفی را نمایش بده. زیر دایرکتوریها را جستجو نکن.
$ find ~ -name "???" -d 1
فراموش نکنید چنانچه از * و یا ? استفاده میکنید حتما متن را با استفاده از ""
(double quote) و یا ′′
(single quote) quote کنید و یا اینکه قبل از کاراکتر ویژه * و یا ? علامت \
قرار دهید و یا به عبارت دیگر آن را escape کنید.
ارسال خروجی find به xargs🔗
تا به حال با پیغام arguments too long مواجه شده اید؟ علت این پیغام چیست؟ پوسته یا shell تا حد معینی میتواند آرگومانهای خط فرمان را به برنامه فراخوانده شده ارسال کند. وقتی این تعداد از حد معین شده توسط پوسته بیشتر میشود، پوسته پیغام arguments too long میدهد. برای حل این مشکل و البته برای کاربرد در وضعیتهای دیگر دستور xargs
به کمک میآید.
مثال زیر را ببینید:
$ ls | xargs echo
xargs
محتوای خوانده شده از ورودی استاندارد را به عنوان آرگومان به دستوری که در جلویش میآید میفرستد. در دستور فوق ورودی استاندارد به سمت pipe تغییر جهت یافته است و لذا xargs
محتوای ارسالی در pipe، که همان خروجی دستور ls
است را میخواند و آن را به عنوان آرگومانهای ورودی به دستور echo
ارسال میکند. xargs
محدودیت تعداد آرگومان پوسته را میداند و لذا دیگر شاهد پیغام arguments too long نخواهید بود.
برای حذف کلیهی فایلهای mp3 از دایرکتوری جاری به شیوه زیر نیز میتوان عمل کرد:
$ ls *.mp3 | xargs rm
دستور ls
کلیهی فایلهای خاتمه یافته به پسوند mp3 را لیست میکند و آن را به pipe می فرستد. xargs
از pipe میخواند و محتوای خوانده شده را به عنوان آرگومانهای دستور rm
منظور میکند و سپس rm
را اجرا میکند. اگر لیست فایلهای mp3 بسیار زیاد باشد در این صورت xargs
یکبار دستور rm
را با تعداد آرگومان کافی خوانده شده از pipe اجرا میکند و سپس دوباره اقدام به اجرای دستور rm
با آرگومانهای جدید میکند. این عمل تا زمانی که pipe خالی شود ادامه مییابد.
دستور بالا را میتوان با استفاده از find
نوشت. توجه کنید چون find
جستجو را به صورت تو در تو انجام میدهد برای پیاده سازی دقیق دستور بالا باید عمق جستجو را ۱ بگذاریم.
$ find . -d 1 -iname "*.mp3" | xargs rm
عمق جستجو با سوییچ -d
مشخص میشود.
نکته مهم
متاسفانه دستور xargs
در مورد فایلهایی که در نامشان space دارند درست عمل نمیکند. ولی راهحلهایی برای رفع این مشکل وجود دارد.
حل مشکل space در xargs و find🔗
دستور xargs
بر مبنای کاراکترهای space و \n
کار میکند، یعنی اگر میان نام یک فایل space باشد xargs
آن را به چند نام تقسیم میکند، چون کاراکتر جداکننده آن space است.
خوشبختانه find
دارای سوییچی به نام -print0
است که در آخر تمام موارد یافته شده کاراکتر NULL را قرار میدهد و همچنین دستور xargs
نیز دارای سوییچی به نام -0
است که کاراکتر جداکننده را به NULL تغییر میدهد.
دو دستور زیر و خروجیهای آنها را ملاحظه بفرمایید.
$ find . -name "Untitled 1.odt" | xargs ls -l
ls: ./Untitled: No such file or directory
ls: 1.odt: No such file or directory
$ find . -name "Untitled 1.odt" -print0 | xargs -0 ls -l
-rw-r--r-- 1 mohsen wheel 31308 Apr 1 17:33 ./Untitled 1.odt
به نظر مشکل بزرگی میآمد ولی با همکاری دو دستور با هم مسئله حل شد.
جستجو بر مبنای نوع (type) فایل🔗
گاهی اوقات نیاز به جستجو در میان نوع خاصی از فایلها داریم. برای این منظور از سوییچ -type
به همراه کاراکترهای تعریف شده زیر استفاده میکنیم.
b
: فایل ویژه از نوع block یا block special filec
: فایل ویژه از نوع character یا character special filed
: دایرکتوریf
: فایل معمولیl
: لینکs
: سوکت socket
لیست کلیهی فایلهای معمولی در دایرکتوری جاری و لیست کامل اطلاعات آن
$ find . -type f -d 1 | xargs ls -l
لیست کلیهی لینکها در دایرکتوری خانگی (و زیر دایرکتوریهای آن)
$ find ~ -type l
لینکهای موجود در دایرکتوری خانگی به کجا اشاره می کنند؟
$ find ~ -d 1 -type l | xargs ls -l | awk '{print $9 " " $10 " " $11}'
علامت + و -🔗
علامت + قبل از عدد به معنای «بزرگتر از» یا «بیشتر از» است. علامت - قبل از عدد به معنای «کوچکتر از» یا «کمتر از» است.
- عبارت
-size -20M
یعنی سایز فایل کمتر از ۲۰ مگابایت باشد و عبارت-mtime -2
یعنی تاریخ ویرایش فایل کمتر از ۲ روز گذشته باشد. - عبارت
-size +100K
یعنی فایلهایی که سایزشان بیشتر از ۱۰۰ کیلو بایت باشد و عبارت-atime +2
یعنی فایلهایی که تاریخ آخرین دسترسی به آنها بیشتر از ۲ روز گذشته باشد.
جستجو بر مبنای بزرگی (size) فایل🔗
برای جستجو بر مبنای سایز از سوییچ -size
استفاده میکنیم. به دنبال -size
یک عدد صحیح میآید. چنانچه این عدد بدون هیچ گونه کاراکتر بعدی باشد به معنای تعداد دقیق بلاکهای اشغال شده توسط برنامه است. متاسفانه فضای هر بلاک برای برنامههای مختلف متفاوت است. مثلا در سیستم FreeBSD که من استفاده میکنم دستور ls -s
که تعداد بلاک هر فایل را بر میگرداند هر بلاک را ۱۰۲۴ بایت حساب میکند در صورتیکه find
هر بلاک را ۵۱۲ بایت لحاظ میکند.
$ ls -ls 5.txt
4 -rw-r--r-- 1 mohsen wheel 1058 Apr 6 21:25 5.txt
دستور فوق نشان میدهد که فایل 5 دارای ۱۰۵۸ بایت است و ۴ بلاک اشغال کرده است. دستور ls
بلاکها را در واحدهای چهارتایی اختصاص داده است در حالیکه تعداد بلاک مصرف شده واقعی با حجم هر بلاک ۱۰۲۴ بایت دو بلاک است. ولی دستور find
بلاکها را ۵۱۲ بایت حساب میکند لذا عدد بلاک مصرف شده برای این فایل از نظر دستور find
تعداد ۳ بلاک است. این موضوع را با دستور زیر تست میکنیم.
$ find -size 3 | xargs ls -ls
4 -rw-r--r-- 1 mohsen wheel 1058 Apr 6 21:25 ./5.txt
موضوع پیجیده شد؟ خوشبختانه راههای فرار خوبی وجود دارد! میتوان بعد از عدد صحیح، از کاراکترهای زیر استفاده کرد:
c
: کاراکتر. مثلا 27c یعنی ۲۷ کاراکتر یا ۲۷ بایتk
: کیلو بایت. مثلا 27k یعنی ۲۷ کیلو بایت. (توجه کنید k با حرف کوچک نوشته شده است)M
: مگا بایت. مثلا 27M یعنی ۲۷ مگا بایتG
: گیگا بایت. مثلا 27G یعنی ۲۷ گیگا بایتT
: ترا بایت. مثلا 27T یعنی ۲۷ ترا بایتP
: پتا بایت. مثلا 27P یعنی ۲۷ پتا بایت
لیست فایلهای MP4 که سایز آنها بیشتر از ۶۰۰ مگا بایت است:
$ find ~ -type f -iname "*.mp4" -size +600M
لیست فایلهای jpg که بین ۴۰۰ کیلو بایت تا ۵ مگابایت هستند:
$ find ~ -type f -iname "*.jpg" -size +400k -size -5M
نکته مهم
دستور بالا نشان میدهد زمانی که دو یا چند شرط وجود داشته باشد تمامی شرطها میبایست true باشند یا به عبارت دیگر شرطها با هم AND میشوند.
جستجو بر مبنای سطح دسترسی (permission) فایل🔗
سوییچ -perm
برای یافتن فایل با سطوح دسترسی مشخص استفاده میشود. عدد قرار گرفته در جلو سوییچ میبایست عددی در مبنای ۸ باشد.
فایلهای دارای اجازه دسترسی ۷۷۷ را نمایش بده.
$ find ~ -perm 777
فایلهای دارای اجازه دسترسی ۷۵۵ را نمایش بده.
$ find ~ -perm 755
بعضی اوقات نیازی به دانستن اجازه دسترسی کامل فایل ندارید و فقط یک مجوز برای شما مهم است. مثلا میخواهید بدانید گروه در کدام فایلها اجازه نوشتن دارد. برای این موارد سریعا ترکیب rwx rwx rwx
را برای فایل مورد نظر تشکیل دهید. بدیهی است که rwx ها به ترتیب از چپ به راست مجوزهای صاحب فایل، گروه و دیگران هستند. زیرِ مجوزهایی که برای شما اهمیتی ندارند صفر بگذارید و مجوزهایی که لازم است داشته باشند را یک قرار دهید. عدد حاصله را سه رقم سه رقم در مبنای هشت بنویسید و با یک علامت -
پیش از آن، جلوی سوییچ -perm
قرار دهید.
نکته
علامت -
پیش از عدد permission میگوید که اجازه دسترسی واقعی فایل را با عدد جلوی permission به صورت بیتی AND کن و اگر حاصل درست بود فایل را نمایش بده (یعنی آن فایل مجوزی که برای شما مهم بوده است را دارد.)
کدام فایلها مجوز نوشتن توسط گروه را دارند؟
rwx rwx rwx
000 010 000
عدد هشت بیتی حاصل 020 است. از این عدد به صورت زیر استفاده میکنیم:
$ find ~ -perm -020
لیست کامل فایلهای اجرایی را نمایش بده.
rwx rwx rwx
001 000 000
عدد هشت بیتی حاصل 001 است.
$ find ~ -type f -perm -001
سوییچ -perm
همچنین قابلیت شناسایی بیتهای SUID و SGID و sticky bit را نیز دارد. برای این منظور فقط کافیست ترکیب SUID SGID sticky
را در سمت چپ rwx صاحب فایل تشکیل دهید و این بار عدد ۱۲ بیتی حاصل را سه رقم سه رقم در مبنای هشت بنویسید و با علامت -
بعد از سوییچ -perm
قرار دهید.
تمام فایلهایی که بیت SUID آن فعال است را پیدا کن.
SUID/SGID/sticky rwx rwx rwx
000 000 000 0 0 1
عدد ۱۲ بیتی حاصل 4000 است.
$ find /usr/bin -type f -perm -4000 -print0 | xargs -0 ls -lh | head -n 5
-r-sr-xr-x 4 root wheel 22k Dec 4 2012 /usr/bin/at
-r-sr-xr-x 4 root wheel 22k Dec 4 2012 /usr/bin/atq
-r-sr-xr-x 4 root wheel 22k Dec 4 2012 /usr/bin/atrm
-r-sr-xr-x 4 root wheel 22k Dec 4 2012 /usr/bin/batch
-r-sr-xr-x 6 root wheel 18k Dec 4 2012 /usr/bin/chfn
گاهی اوقات میخواهید فایلهایی را پیدا کنید که مجوز خاصی را نداشته باشند. برای اینگونه موقعیتها باید ابتدا شرط داشتن مجوز را بنویسید و سپس آن شرط را نقیض کنید. برای این منظور در بخشهای بعد عملگرهای منطقی را بررسی خواهیم کرد.
جستجو بر مبنای زمان ویرایش ، زمان دسترسی و زمان تغییر i-node🔗
به طور کلی جستجوی زمانی را بر مبنای دو پارامتر روز و دقیقه انجام میدهیم.
جستجو بر مبنای روز🔗
سوییجهای جستجو بر مبنای روز به صورت زیر تعریف میشوند:
-mtime
: برگرفته از عبارت modified time یا زمان آخرین ویرایش فایل. از آنجایی که یونیکس زمان ایجاد فایل را ذخیره نمیکند به عنوان زمان ایجاد فایل هم میتواند استفاده شود.-atime
: برگرفته از عبارت accessed time یا زمان آخرین دسترسی به فایل.-ctime
: برگرفته از عبارت i-node change time یا زمانِ آخرین تغییرِ اطلاعات i-node. چنانچه نام فایل، صاحب فایل، گروه و یا تعداد لینکهای داده شده به فایل و ... تغییر کند بدون اینکه محتوای فایل مورد ویرایش قرار گیرد این تاریخ، زمانی جلوتر از زمان آخرین ویرایش فایل خواهد داشت.
فایلهایی که ۷ روز پیش ویرایش شدهاند را نمایش بده.
$ find ~ -mtime 7
همین مثال میتواند به صورت زیر با استفاده از علامت های + و - نیز نوشته شود.
$ find ~ -mtime +6 -mtime -7
یعنی زمان ویرایش فایل بیشتر از ۶ روز و کمتر از ۷ روز پیش باشد. علامت + شامل همان عدد نمی شود ولی علامت - خود عدد را نیز شامل میشود.
فایلهایی که بیشتر از ۳۰ روز است که از آنها استفاده نکردهام را نمایش بده.
$ find ~ -atime +30 -type f
نمایش فایلهایی که بیشتر از یک روز پیش و کمتر از دو روز پیش به آنها دسترسی داشتهام.
$ (echo -e current date : `date` "\n";find . -type f -d 1 -atime -2 -atime +1 -print0 | xargs -0 ls -lut)
current date : Fri Apr 11 16:15:37 IRDT 2014
-rw-r--r-- 1 mohsen wheel 11710 Apr 9 23:20 ./b.result
-rw-r--r-- 1 mohsen wheel 155845071 Apr 9 23:13 ./download36.mp4
-rw-r--r-- 1 mohsen wheel 1292918 Apr 9 18:01 ./b.flv
-rw-r--r-- 1 mohsen wheel 2168490 Apr 9 18:01 ./recovered2.flv
-rw-r--r-- 1 mohsen wheel 3022870 Apr 9 18:00 ./recovered1.flv
همانطوری که مشاهده میکنید علامت + شامل خود عدد (در اینجا ۱ روز) نمیشود ولی علامت - شامل عدد (در اینجا ۲ روز) میشود.
جستجو بر مبنای دقیقه🔗
سه سوییچ زیر برای جستجو بر مبنای دقیقه مورد استفاده قرار میگیرند:
-mmin
: برگرفته از عبارت modified minute-amin
: برگرفته از عبارت accessed minute-cmin
: برگرفته از عبارت i-node change minute
کاربرد این سوییچها دقیقا مانند سوییچهای بخش قبل هستند با این تفاوت که همه چیز در اینجا معنای دقیقه میدهد.
فایلهایی که کمتر از ۶۰ دقیقه قبل ویرایش شدهاند را نمایش دهید.
$ find . -type f -mmin -60
فایلهایی که کمتر از ۴۰ دقیقه پیش آنها را مشاهده کردهام را نمایش دهید.
$ find . -type f -amin -40
جستجوی زمانی بر مبنای زمان ویرایش یک فایل🔗
اگر میخواهید متوجه شوید زمان آخرین ویرایش چه فایلهایی از فایل داده شده کمتر است از سوییچ -newer
استفاده کنید.
چه فایلهایی از فایل tmp.sh جدیدتر هستند؟
$ ls -l tmp.sh
-rwxr-xr-x 1 mohsen wheel 34 Mar 24 21:56 tmp.sh*
$ find . -d 1 -newer tmp.sh | xargs ls -lt | head -n 5
-rw-r--r-- 1 mohsen wheel 0 Apr 11 19:05 ./4
-rw-r--r-- 1 mohsen wheel 0 Apr 11 19:05 ./3
-rwxr-xr-x 2 mohsen wheel 2 Mar 30 22:40 ./1
-rwxr-xr-x 2 mohsen wheel 2 Mar 30 22:40 ./2
lrwxr-xr-x 1 mohsen wheel 21 Mar 30 17:08 ./.profile -> /home/mohsen/.profile
جستجو بر مبنای صاحب (owner) و گروه (group) فایل🔗
از سوییچ -user
برای جستجوی فایلها بر مبنای نام کاربری یا شمارهی یکتای صاحب فایل استفاده میشود. شماره یکتای هر کاربر را میتوانید در فایل etc/passwd/ مشاهده کنید.
$ cat /etc/passwd | grep ^mohsen
mohsen:*:1001:1001:Mohsen Safari:/home/mohsen:/usr/local/bin/bash
مثال بالا خط مربوط به کاربر mohsen در فایل etc/passwd/ را نشان میدهد که دارای شماره کاربری ۱۰۰۱ است.
از سوییچ -group
برای جستجوی فایلها بر مبنای نام گروه و یا شمارهی یکتای گروه استفاده میشود. شماره یکتای هر گروه را میتوانید در فایل etc/group/ مشاهده کنید.
$ cat /etc/group | grep ^mohsen
mohsen:*:1001:
در مثال بالا مشاهده میکنید که گروه mohsen دارای شماره یکتای ۱۰۰۱ است.
کلیهی فایلهایی که SGID آن ها به wheel ست شده است را پیدا کنید.
$ find ~ -group wheel -perm -2000
جستجو بر مبنای i-number🔗
تا به حال دستور ls -li
را اجرا کردهاید؟ نمونه خروجی این دستور را ببینید:
$ ls -li
total 64
11397272 drwxr-xr-x 6 mohsen wheel 512 Apr 5 20:23 ./
11318506 drwxr-xr-x 3 mohsen wheel 512 Mar 21 21:34 ../
11396871 lrwxr-xr-x 1 mohsen wheel 21 Mar 30 17:08 .profile@ -> /home/mohsen/.profile
11396876 -rw-r--r-- 2 mohsen wheel 2 Mar 30 22:40 1
11396876 -rw-r--r-- 2 mohsen wheel 2 Mar 30 22:40 2
11396865 -rwxr-xr-x 1 mohsen wheel 34 Mar 24 21:56 2.2.sh*
11879926 drwxr-xr-x 3 mohsen wheel 512 Mar 30 18:12 DIR/
11396862 -rw-r--r-- 1 mohsen wheel 252 Mar 24 20:51 args-no.sh
11396866 -rwxr-xr-x 1 mohsen wheel 2054 Mar 23 16:02 cleanup*
12039467 drwxrwxr-x 2 mohsen wheel 512 Apr 5 20:23 d1/
12039468 dr-xr-xr-x 2 mohsen wheel 512 Apr 5 20:23 d2/
12039469 drwxr-xr-x 2 mohsen wheel 512 Apr 5 20:23 d3/
11396867 -rw-r--r-- 1 mohsen wheel 352 Mar 24 21:49 log
11396875 -rwxr-xr-x 1 mohsen wheel 8780 Mar 24 20:59 readme*
11396878 -rwxr-xr-x 1 mohsen wheel 403 Mar 21 22:11 swap.sh*
عددهای قرار گرفته در سمت چپ هر سطر i-number نامیده میشوند و شماره درایه مربوط به آن فایل در داخل جدول i-table یا inode-table است.
دستور find
قابلیت جستجو بر مبنای i-number را دارد. برای این منظور میتوانید از سوییچ -inum
استفاده کنید. میبایست بعد از -inum
شماره i-number فایل مورد نظر را قرار دهید.
فایل دارای i-number به شماره ۱۱۳۹۶۸۶۶ را از طریق دستور find
بیابید.
$ find . -inum 11396866 | xargs ls -li
11396866 -rwxr-xr-x 1 mohsen wheel 2054 Mar 23 16:02 ./cleanup
برای مشاهده صحت عملکرد find
خروجی آن را از طریق pipe به دستور xargs ls -li
ارسال میکنیم. سوییچ -i
در دستور ls
همانگونه که میدانید شماره i-number هر فایل را بر میگرداند.
جستجوی فایلهای خالی (empty)🔗
از سوییچ -empty
برای یافتن فایلهای خالی استفاده میشود.
$ >1 ; >2 ; >3
$ echo "salam" >4
$ find . -empty | xargs ls -l
-rw-r--r-- 1 mohsen wheel 0 Apr 7 15:32 ./1
-rw-r--r-- 1 mohsen wheel 0 Apr 7 15:32 ./2
-rw-r--r-- 1 mohsen wheel 0 Apr 7 15:32 ./3
همانطور که در ریزِ لیست فایلها میبینید حجم تمام این فایلها صفر بایت است و در واقع خالی هستند.
از سوییچ -empty
برای یافتن دایرکتوریهای خالی هم میتوان استفاده کرد.
$ mkdir newdir
$ echo "salam" >newdir/1.txt
$ mkdir emptydir
$ find . -type d -empty
./emptydir
سوییچ exec- و ok-🔗
تاکنون برای ارسال خروجی دستور find
به برنامههای دیگر از pipe و xargs
استفاده کردهایم ولی این شیوه تنها راهحل نیست بلکه میتوانیم از سوییچ -exec
خود دستور find
هم استفاده کنیم. بعد از -exec
هر دستوری میتواند بیایید.
-
سوییچ
-ok
دقیقا مانند سوییچ-exec
است با این تفاوت که قبل از اجرای دستور از شما میپرسد که آیا دستور را اجرا کند یا خیر. -
متغیر
{}
در سوییچ-exec
به معنای نام فایل یافته شده است. با یافتن نتیجه جدید مقدار{}
رونویسی میشود. -
-exec
یکبار به ازای هر فایل یافته شده اجرا میشود به عنوان مثال اگر جستجویی ۴۰ نتیجه داشته باشد و در این جستجو از سوییج-exec
استفاده کرده باشیم،-exec
چهل بار اجرا خواهد شد، در صورتیکه با استفاده از pipe وxargs
، دستورxargs
چهل نتیجه یافته شده را به عنوان آرگومان دستور بعدی منظور کرده و به احتمال بسیار زیاد فقط یکبار دستور مورد نظر را اجرا می کند. از طرف دیگرxargs
در مورد فایلهایی که در داخل نامشان space دارند به صورت پیش فرض درست عمل نمی کند (مشاهده راه حل) و در این مواقع بهتر است از سوییچ-exec
استفاده کنید. تصمیم گیری در مورد استفاده ازxargs
یا سوییچ-exec
با توجه به شرایط و تجربه با شما خواهد بود . -
بعد از سوییج
-exec
دستوری میآید که در صورت پیدا شدن یک فایل اجرا خواهد شد. از آنجا که این دستور باید مستقیما و به طور کامل به دستورfind
ارسال شود تا در موقع لزوم اجرا شود، میبایست کلیهی کاراکترهایی که shell آنها را تفسیر می کند را escape کنیم. از جملهی این کاراکترها;
و*
و?
هستند. برای escape کردن این کاراکترها قبل از آنها یک\
قرار دهید. از طرفیfind
میبایست نقطه پایان دستور-exec
را شناسایی کند. برای نشان دادن نقطه پایان دستور-exec
از;
استفاده میکنیم.;
در پوسته به معنای جداکننده دستورها است لذا;
نیز میبایست escape شود.
فایلهای mp3 دایرکتوری جاری و زیردایرکتوریهای آن را حذف کنید. لطفا قبل از حذف از من سوال کنید.
$ find . -iname "*.mp3" -ok rm {} \;
دستور فوق فایلهای mp3 را یافته و بعد از پرسیدن اینکه آیا دستور اجرا شود یا خیر، در صورت موافقت، دستور rm
را روی فایل مورد نظر ({}
) اجرا میکند. -ok
به ازای هر نتیجه یکبار از شما میپرسد که آیا دستور را اجرا کند یا خیر. بنابر این شما میتوانید دستور را روی بعضی از فایلها اجرا کنید و روی بعضی فایلها اجرا نکنید.
از کلیهی فایلهای txt در دایرکتوری فعلی backup بگیرید.
$ find . -d 1 -iname "*.txt" -exec mv {} {}.bak \;
متاسفانه در اثر بیدقتی فایلی به صورت زیر ایجاد شده است که نام آن حاوی تعداد زیادی space است. چه طور میتوانم آنرا حذف کنم.
$ ls -li
12039479 -rw-r--r-- 1 mohsen wheel 0 Apr 7 16:02 o o
سادهترین راه استفاده از دستور find
به همراه سوییچهای -inum
و -exec
است.
$ find . -inum 1203979 -exec rm {} \;
شیوه بالا برای انجام هرگونه عملیات روی فایلهایی که دارای کاراکترهای ویژه هستند و یا اینکه نامشان در ترمینال به درستی نمایش داده نمیشود مناسب است.
مجوز کلیهی فایلهای دایرکتوری جاری که نامشان با عدد شروع میشود را به ۷۵۵ تغییر دهید.
$ find . -d 1 -name "[0-9]*" -type f -exec chmod 755 {} \;
استفاده از AND و OR و NOT🔗
به صورت پیش فرض کلیهی شرطهای موجود در دستور find
با هم AND میشوند ولی ما میتوانیم با استفاده از چند سوییچ و عملگرِ !
روند پیش فرض find
را تغییر دهیم.
توجه
عملگرِ !
قبل از شرط، به معنای نقیض شرط مشخص شده است.
فایلهایی که بزرگتر از ۳۴ کاراکتر نیستند را نمایش بدهید.
$ find . -d 1 -size -34c
$ find . -d 1 ! -size +34c
دو دستور فوق تاحدودی معادل یکدیگرند. دستور اول میگوید سایز فایل کمتر از ۳۴ کاراکتر باشد و دستور دوم میگوید سایز فایل بیشتر از ۳۴ کاراکتر نباشد ولی دستور اول فایلهای ۳۴ کاراکتری را نشان نمیدهد ولی دستور دوم نشان میدهد.
سوییچ -a
به معنای AND و سوییچ -o
به معنای OR است . شرطها را میتوانیم با پرانتز گروهبندی کنیم. فراموش نکنید به علت اینکه پرانتز برای پوسته معنا دارد آنرا حتما با \
(بک اسلش) escape کنید.
فایلهایی که در اسمشان حسن یا حسین است را پیدا کنید.
$ find . \( -iname "*hassan*" -o -iname "*hossein*" \)
دستور فوق میتواند به صورت زیر نیز نوشته شود.
$ find . -iname "*hassan*" -print -o -iname "*hossein*" -print
فایلهایی که دیگران اجازه هیچ گونه دسترسی به آنها را ندارند پیدا کنید.
$ find . -d 1 ! \( -perm -001 -o -perm -002 -o -perm -004 \) -print0 | xargs -0 ls -ld
-rwxr-x--- 1 mohsen wheel 0 Apr 12 16:10 ./1
-rwxr-x--- 1 mohsen wheel 0 Apr 12 16:10 ./2
-rwxr-x--- 1 mohsen wheel 0 Apr 12 16:10 ./3
-rwxr-x--- 1 mohsen wheel 0 Apr 12 16:10 ./4
دستور فوق میتواند به صورت زیر نیز نوشته شود:
$ find . -d 1 ! -perm 001 ! -perm 002 ! -perm -004 -print0 | xargs -0 ls -ld
-rwxr-x--- 1 mohsen wheel 0 Apr 12 16:10 ./1
-rwxr-x--- 1 mohsen wheel 0 Apr 12 16:10 ./2
-rwxr-x--- 1 mohsen wheel 0 Apr 12 16:10 ./3
-rwxr-x--- 1 mohsen wheel 0 Apr 12 16:10 ./4
پاسخ پرسش های مطرح شده🔗
پیدا کردن ویدیوی moammaye_hasti.mp4
$ find ~ -type f -iname "moammaye_hasti.mp4"
یافتن ویدیوهای حجیم با حجم بالای ۶۰۰ مگا بایت
$ find ~ -type f -size +600M
پیدا کردن mp3 هایی که ماه گذشته ریخته بودم توی کامپیوتر. فکر میکنم بین ۳۰ تا ۳۵ روز گذشته بود؟!
$ find ~ -type f -iname "*.mp3" -ctime +29 -ctime -35
حذف کردن عکسها. عکسهام همه پسوند jpg دارند. اگر هم نداشته باشند راحتترم که چند بار دستور find
رو برای حذف پسوندهای مختلف صدا بزنم.
$ find ~/doc/BBAABB -type f -iname "*.jpg" -exec rm {} \;
لیست کل فایلهای دایرکتوری خانه و زیر دایرکتوریهای آن. جایی که ls
به راحتی کمک نمیکند!
$ find ~ -type f
فایلهای رضا را به محسن تغییر مالکیت بده.
$ find ~ -user reza -ok chown mohsen {} \;
دستور بالا به شرطی اجرا خواهد شد که مجوزهای لازم را داشته باشید.
پایان مطلب و نتیجهگیری🔗
نوشتن این مطلب سخت بود ولی خوشحالم که آن را نیمه کاره رها نکردم. حجم بالای اطلاعات که میبایست به مخاطب منتقل کرد و «خوب» و «صحیح» منتقل کرد کار نوشتن و بازنگری متن را زمانبر و طولانی کرد. حالا شاید بتوانم ادعا کنم که برای ۹۰ درصد کاربران روزمرهی سیستمهای شبه یونیکس این راهنما میتواند آخرین راهنمای دستور find
باشد. ولی امیدوارم که به این مطلب بسنده نکنید و متوقف نشوید. نوشتههای دیگر را بخوانید و از مستندات find
که در خط فرمان به صورت زیر قابل دسترسی است غافل نباشید:
$ man find
چنانچه در کدها و یا توضیحات خطایی میبینید سپاسگزار میشوم کامنت بگذارید و یا به هر طریق دیگری اطلاع دهید تا آن را اصلاح کنم.
شاد باشید.
من محسن هستم؛ برنامهنویس سابق PHP و Laravel و Zend Framework و پایتون و فلسک. تمرکزم بیشتر روی لاراول بود! الان از صفر مشغول مطالعات اقتصادی هستم.
برای ارتباط با من یا در همین سایت کامنت بگذارید و یا به dokaj.ir(at)gmail.com ایمیل بزنید.
در مورد این مطلب یادداشتی بنویسید.