این در واقع سه پرسش مختلف است، بنابراین ما پاسخ را به سه قسمت تفکیک کردهایم.
آسانترین روش برای مطابقت با سطرهایی که شامل هر دو رشته foo و bar هستند استفاده از دو فرمان grep میباشد:
grep foo | grep bar grep foo "$myfile" | grep bar # برای آنهایی که نیاز به نگهداری دستی دارند
این کار همچنین میتواند با یک egrep انجام بشود، هر چند(به طوریکه احتمالاً میتوانید حدس بزنید) این فرمان نمیتواند به طور واقعی برای سنجش بیش از دو الگو به کار برود:
egrep 'foo.*bar|bar.*foo'
اگر ترجیح میدهید، میتوانید با یک جمله sed یا awk به این مقصود نائل شوید:
sed -n '/foo/{/bar/p}' awk '/foo/ && /bar/'
اگر نیاز به راه حل سنجش awk برای تعداد اختیاری الگوها دارید، میتوانید یک سطر فرمان awk ممتد طرحریزی نمایید:
# bashو ksh93 درپوستههای # را ایجاد میکند awk "/$1/&&/$2/&&...." # دادههایی که میخواهند مطابقت شوند باید در ورودی استاندارد باشند # سطرهای انطباق یافته را در خروجی استاندارد مینویسد multimatch() { (($# < 2)) && { echo "usage: multimatch pat1 pat2 [...]" >&2; return 1; } awk "/$1/$(printf "&&/%s/" "${@:2}")" }
یا، نگارش POSIX:
# POSIX multimatch() { [ $# -lt 2 ] && { echo "usage: multimatch pat1 pat2 [...]" >&2; return 1; } __p1=$1 shift awk "/$__p1/$(printf "&&/%s/" "$@")" }
افسوس، توابع POSIX متغیرهای محلی ندارند. همچنین، در صورتیکه هر یک از الگوها شامل کاراکترهای
یک نگارش POSIX که عبارتهای منظم را در اسکریپت awk تعبیه نمیکند.
# POSIX multimatch() { awk 'BEGIN{for(i=1;i<ARGC;i++) a[i]=ARGV[i]; ARGC=1} {for (i in a) if ($0 !~ a[i]) next; print}' "$@" }
روشهای بسیار زیادی برای مطابقت سطرهای شامل foo یا bar وجود دارد. با گزینه -e میتوان الگوهای چندتایی را با grep به کار برد:
grep -e 'foo' -e 'bar'
یا میتوانید یک الگو با egrep (یا grep -E) بسازید:
egrep 'foo|bar' grep -E 'foo|bar'
(نمیتوانید ازعملگر اتصال | با grep ساده استفاده کنید. این عملگر | فقط در عبارتهای منظم توسعهیافته معتبر میباشد.)
این کار همچنین میتواند با sed، awk، و غیره انجام بشود.
awk '/foo|bar/'
رویکرد awk برتری آن را دارد که به شما اجازه استفاده از سایر ویژگیهای awk روی سطرهای انطباق یافته را میدهد.
مطابقت سطرهایی که شامل هیچ یک از رشتههای foo و bar نیستند:
grep -E -v 'foo|bar' # را ترجیح میدهند egrep -v 'foo|bar' بعضی اشخاص
اگر میخواهید مطابقت کنید که فایلها (به جای سطرها) شامل هر دو رشته foo و bar هستند، چندین رویکرد عملی وجود دارد. سادهترین(اگر چه ضرورتاً کارآمدترین نیست) دوبار خواندن فایل است:
grep -q foo "$myfile" && grep -q bar "$myfile" && echo "Found both"
راه حل استفاده دوگانه grep -q این مزیت را دارد که در هر نوبت خواندن، در جایی که مورد انطباقی پیدا شود توقف میکند، بنابراین اگر یک فایل حجیم داشته باشید، اما کلمات در ابتدای آن باشند، فقط قسمت اول فایل خوانده میشود. متأسفانه، اگر انطباقها در انتهای فایل باشند(وضعیت وخیم: در انتهاییترین سطرهای فایل) شما کل فایل را دوبار میخوانید.
رویکرد دیگری یکبار خواندن فایل، و حفظ نمودن اثر آنچه دیدهاید، در ضمن پیشروی در فایل میباشد. در awk:
awk '/foo/{a=1} /bar/{b=1} a&&b{print "both found";exit} END{if (a&&b){ exit 0} else{exit 1}}'
این کد فایل را یک بار میخواند، موقعی که هر دو الگو منطبق گردیدند توقف میکند. مهم نیست چه اتفاقی رخ میدهد، پس از آن بلوک END اجرا میشود، و مطابق آن وضعیت خروج تنظیم میگردد.
اگر میخواهید بررسیهای اضافی در محتویات فایل انجام بدهید، این راهکار awk میتواند کاملاً به آسانی وفق داده شود.
پرسش و پاسخ 79 (آخرین ویرایش 2011-04-15 12:16:35 توسط GreyCat)