stdout (استاندارد)
در حال حاضر، ما با بسیاری از دستورات و خروجی آنها آشنا شده ایم و این ما را به جریان های (ورودی/خروجی) سوژه بعدی خود می رساند. بیایید دستور زیر را اجرا کنیم و در مورد نحوه عملکرد آن بحث خواهیم کرد.
$ echo Hello World > peanuts.txt
دایرکتوری را که در آن دستور اجرا کردید بررسی کنید و ببینید که باید فایلی به نام peanuts.txt را ببینید، داخل آن فایل را نگاه کنید و متن Hello World را ببینید. بسیاری از چیزها فقط در یک دستور اتفاق افتاده است، بنابراین بیایید آن را تجزیه کنیم.
ابتدا بیایید قسمت اول را تجزیه کنیم:
$ echo Hello World
می دانیم که Hello World را روی صفحه نمایش می دهد، اما چگونه؟ فرآیندها از جریان های ورودی/خروجی برای دریافت ورودی و خروجی برگشتی استفاده می کنند. به طور پیش فرض دستور echo ورودی (ورودی استاندارد یا stdin) را از صفحه کلید می گیرد و خروجی (خروجی استاندارد یا stdout) را به صفحه باز می گرداند. بنابراین به همین دلیل است که وقتی شما echo Hello World را در پوسته خود تایپ می کنید، Hello World را روی صفحه نمایش می دهید. با این حال، تغییر مسیر ورودی/خروجی به ما اجازه میدهد تا این رفتار پیشفرض را تغییر دهیم و انعطافپذیری بیشتری در فایل به ما میدهد.
بیایید به قسمت بعدی دستور ادامه دهیم:
>
> یک عملگر تغییر مسیر است که به ما اجازه می دهد تا جایی که خروجی استاندارد تغییر می کند. این به ما امکان می دهد خروجی echo Hello World را به جای صفحه نمایش به یک فایل ارسال کنیم. اگر فایل از قبل وجود نداشته باشد، آن را برای ما ایجاد می کند. با این حال، اگر وجود داشته باشد، آن را بازنویسی می کند (برای جلوگیری از این امر بسته به پوسته ای که استفاده می کنید، می توانید یک پرچم پوسته اضافه کنید).
و اساساً تغییر مسیر stdout اینگونه است!
خوب فرض کنید من نمی خواستم peanuts.txt خود را بازنویسی کنم، خوشبختانه یک عملگر تغییر مسیر برای آن نیز وجود دارد، >>:
$ echo Hello World >> peanuts.txt
با این کار Hello World به انتهای فایل peanuts.txt اضافه میشود، اگر فایل از قبل وجود نداشته باشد، آن را برای ما ایجاد میکند، همانطور که با > redirector انجام داد.
stdin (در استاندارد)
در درس قبلی یاد گرفتیم که جریانهای stdout مختلفی داریم که میتوانیم از آنها استفاده کنیم، مانند یک فایل یا صفحه. خوب جریان های ورودی استاندارد (stdin) مختلفی نیز وجود دارد که می توانیم از آنها نیز استفاده کنیم. ما میدانیم که stdin را از دستگاههایی مانند صفحه کلید داریم، اما میتوانیم از فایلها، خروجیهای سایر فرآیندها و ترمینال نیز استفاده کنیم، بیایید یک مثال را ببینیم.
بیایید از فایل peanuts.txt در درس قبلی برای این مثال استفاده کنیم، به یاد داشته باشید که متن Hello World در آن وجود دارد.
$ cat < peanuts.txt > banana.txt
همانطور که برای تغییر مسیر stdout > داشتیم، میتوانیم از < برای تغییر مسیر stdin استفاده کنیم.
به طور معمول در دستور cat، یک فایل برای آن ارسال می کنید و آن فایل تبدیل به stdin می شود، در این حالت peanuts.txt را تغییر مسیر دادیم تا stdin ما باشد. سپس خروجی cat peanuts.txt که Hello World است به فایل دیگری به نام banana.txt هدایت می شود.
stderr (خطای استاندارد)
بیایید اکنون کمی متفاوت را امتحان کنیم، بیایید سعی کنیم محتویات دایرکتوری را که در سیستم شما وجود ندارد فهرست کنیم و خروجی را دوباره به فایل peanuts.txt هدایت کنیم.
$ ls /fake/directory > peanuts.txt
برای مثال:
ls: cannot access /fake/directory: No such file or directory
حالا احتمالاً به این فکر می کنید که آیا نباید آن پیام به فایل ارسال می شد؟ در واقع یک جریان ورودی/خروجی دیگری در اینجا وجود دارد به نام خطای استاندارد (stderr). به طور پیش فرض، stderr خروجی خود را به صفحه نمایش می فرستد، این جریان کاملاً متفاوت از stdout است. بنابراین باید خروجی آن را به روش دیگری تغییر مسیر دهید.
متأسفانه redirector به خوبی استفاده از < یا > نیست اما بسیار نزدیک است. ما باید از توصیف کننده های فایل استفاده کنیم. توصیفگر فایل یک عدد غیر منفی است که برای دسترسی به یک فایل یا جریان استفاده می شود. ما بعداً در مورد این موضوع عمیق خواهیم کرد، اما در حال حاضر بدانید که توصیف کننده فایل برای stdin، stdout و stderr به ترتیب 0، 1 و 2 است.
بنابراین اکنون اگر بخواهیم std
err خود را به فایل تغییر مسیر دهیم، می توانیم این کار را انجام دهیم:
$ ls /fake/directory 2> peanuts.txt
شما باید فقط پیام های stderr را در peanuts.txt ببینید.
حالا اگر بخواهم هم stderr و هم stdout را در فایل peanuts.txt ببینم چه می شود؟ انجام این کار با توصیفگرهای فایل نیز امکان پذیر است:
$ ls /fake/directory > peanuts.txt 2>&1
این کار نتایج ls /fake/directory را به فایل peanuts.txt می فرستد و سپس stderr را از طریق 2>&1 به stdout هدایت می کند. ترتیب عملیات در اینجا مهم است، 2>&1 stderr را به هر چیزی که stdout به آن اشاره می کند ارسال می کند. در این مورد stdout به یک فایل اشاره می کند، بنابراین 2>&1 نیز stderr را به یک فایل می فرستد. بنابراین اگر فایل peanuts.txt را باز کنید، باید هم stderr و هم stdout را ببینید. در مورد ما، دستور بالا فقط stderr را خروجی می دهد.
یک راه کوتاهتر برای تغییر مسیر stdout و stderr به یک فایل وجود دارد:
$ ls /fake/directory &> peanuts.txt
حالا اگر من هیچ یک از آن cruft را نخواهم و بخواهم از شر پیام های stderr به طور کامل خلاص شوم چه؟ خوب شما همچنین می توانید خروجی را به یک فراخوانی فایل خاص /dev/null هدایت کنید و هر ورودی را حذف می کند.
$ ls /fake/directory 2> /dev/null
pipe and tee
حالا بیایید وارد pipe شویم، نه واقعاً اما کمی. بیایید یک دستور را امتحان کنیم:
$ ls -la /etc
شما باید یک لیست بسیار طولانی از موارد را ببینید، در واقع خواندن آن کمی سخت است. به جای اینکه این خروجی را به یک فایل هدایت کنیم، خوب نیست اگر بتوانیم خروجی را در دستور دیگری مانند less ببینیم؟
برای مثال:
$ ls -la /etc | less
عملگر لوله |، که با یک نوار عمودی نشان داده می شود، به ما اجازه می دهد که stdout یک دستور را دریافت کرده و آن را به فرآیند دیگری تبدیل کنیم. در این مورد، stdout ls -la /etc را گرفتیم و سپس آن را به دستور less لوله کردیم. دستور pipe بسیار مفید است و ما تا ابد به استفاده از آن ادامه خواهیم داد.
خوب اگر بخواهم خروجی دستورم را در دو جریان مختلف بنویسم چه می شود؟ این با دستور tee امکان پذیر است:
$ ls | tee peanuts.txt
شما باید خروجی ls را روی صفحه نمایش خود ببینید و اگر فایل peanuts.txt را باز کنید باید همان اطلاعات را ببینید.
env (محیط زیست)
دستور زیر را اجرا کنید:
$ echo $HOME
شما باید مسیر دایرکتوری خانه خود را ببینید، مسیر من مانند home/pete است.
بیایید با دستوراتی در مورد اطلاعات کاربر اشنا شویم:
$ echo $USER
$ env
این خروجی اطلاعات زیادی را در مورد متغیرهای محیطی که در حال حاضر تنظیم کرده اید، به دست می دهد. این متغیرها حاوی اطلاعات مفیدی هستند که پوسته و سایر فرآیندها می توانند از آنها استفاده کنند.
برای مثال:
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/bin
PWD=/home/user
USER=pete
یکی از متغیرهای مهم، متغیر PATH است. با چسباندن یک $ در جلوی نام متغیر می توانید به این متغیرها دسترسی پیدا کنید:
$ echo $PATH
/usr/local/sbin:/usr/local/bin:/usr/sbin:/bin
این لیستی از مسیرهای جدا شده توسط یک دونقطه را برمی گرداند که سیستم شما هنگام اجرای یک فرمان جستجو می کند. فرض کنید یک بسته را به صورت دستی از اینترنت دانلود و نصب کرده اید و آن را در یک دایرکتوری غیر استاندارد قرار می دهید و می خواهید آن دستور را اجرا کنید، دستور خنک $ را تایپ می کنید و اعلان می گوید command not found. خوب این احمقانه است که به باینری در یک پوشه نگاه می کنید و می دانید که وجود دارد. چیزی که اتفاق می افتد این است که متغیر $PATH آن دایرکتوری را برای این باینری بررسی نمی کند، بنابراین یک خطا ایجاد می کند.
فرض کنید تعداد زیادی فایل باینری داشتید که میخواستید از آن دایرکتوری تمام شود، فقط میتوانید متغیر PATH را تغییر دهید تا آن دایرکتوری را در متغیر محیطی PATH خود قرار دهید.
(cut) بریدن
ما چند دستور مفید را یاد می گیریم که می توانید از آنها برای پردازش متن استفاده کنید. قبل از شروع، بیایید یک فایل ایجاد کنیم که با آن کار خواهیم کرد. دستور زیر را کپی و پیست کنید، پس از انجام این کار، یک TAB بین lazy و dog اضافه کنید (Ctrl-v + TAB را نگه دارید).
$ echo 'The quick brown; fox jumps over the lazy dog' > sample.txt
اولین دستوری که در مورد آن یاد خواهیم گرفت دستور cut است که بخش هایی از متن را از یک فایل استخراج می کند.
برای استخراج محتویات توسط لیستی از کاراکترها از دستور زیر استفاده کنید:
$ cut -c 5 sample.txt
این کاراکتر 5 را در هر خط از فایل خروجی می دهد. در این مورد "q" است، توجه داشته باشید که فاصله نیز به عنوان یک کاراکتر به حساب می آید.
برای استخراج محتویات توسط یک فیلد، باید تغییرات کوچکی انجام دهیم:
$ cut -f 2 sample.txt
پرچم -f یا فیلد متن را بر اساس فیلدها قطع می کند، به طور پیش فرض از TAB ها به عنوان جداکننده استفاده می کند، بنابراین هر چیزی که توسط یک TAB از هم جدا می شود یک فیلد در نظر گرفته می شود. شما باید "سگ" را به عنوان خروجی خود ببینید.
میتوانید پرچم فیلد را با پرچم جداکننده ترکیب کنید تا محتویات را توسط یک جداکننده سفارشی استخراج کنید:
$ cut -f 1 -d ";" sample.txt
این جداکننده TAB را به ";" تغییر می دهد. جداکننده و از آنجایی که در حال برش میدان اول هستیم، نتیجه باید "قهوه ای سریع" باشد.
(paste) چسباندن
دستور paste شبیه دستور cat است که خطوط را در یک فایل با هم ادغام می کند. بیایید یک فایل جدید با محتویات زیر ایجاد کنیم:
sample2.txt
The
quick
brown
fox
بیایید همه این خطوط را در یک خط ترکیب کنیم:
$ paste -s sample2.txt
جداکننده پیشفرض برای چسباندن، TAB است، بنابراین اکنون یک خط با TAB وجود دارد که هر کلمه را از هم جدا میکند.
بیایید این جداکننده (-d) را به چیزی کمی خواناتر تغییر دهیم:
$ paste -d ' ' -s sample2.txt
اکنون همه چیز باید در یک خط باشد که با فاصله ها مشخص شده است.
head
فرض کنید یک فایل بسیار طولانی داریم، در واقع ما تعداد زیادی برای انتخاب داریم، ادامه دهید و cat /var/log/syslog را انتخاب کنید. شما باید صفحات به صفحات متن را ببینید. اگر من فقط بخواهم دو خط اول این فایل متنی را ببینم چه می شود؟ خوب ما می توانیم با دستور head این کار را انجام دهیم، به طور پیش فرض دستور head 10 خط اول یک فایل را به شما نشان می دهد.
$ head /var/log/syslog
شما همچنین می توانید تعداد خطوط را به هر آنچه که انتخاب می کنید تغییر دهید، فرض کنید من می خواستم به جای آن 15 خط اول را ببینم.
$ head -n 15 /var/log/syslog
پرچم -n مخفف تعداد خطوط است.
(tail) دنباله
مشابه دستور head، دستور tail به شما امکان می دهد 10 خط آخر یک فایل را به طور پیش فرض مشاهده کنید.
$ tail /var/log/syslog
همراه با head می توانید تعداد خطوطی را که می خواهید ببینید تغییر دهید.
$ tail -n 10 /var/log/syslog
یکی دیگر از گزینههای عالی که میتوانید استفاده کنید، پرچم -f (دنبال کردن) است، این پرچم پس از بزرگ شدن فایل دنبال میشود. آن را امتحان کنید و ببینید چه اتفاقی می افتد.
$ tail -f /var/log/syslog
فایل syslog شما به طور مداوم در حال تغییر است در حالی که شما با سیستم خود تعامل دارید و با استفاده از tail -f می توانید هر چیزی که به آن فایل اضافه می شود را مشاهده کنید.
expand and unexpand
در درس دستور cut، فایل sample.txt خود را داشتیم که حاوی یک برگه بود. معمولاً TAB ها تفاوت قابل توجهی را نشان می دهند، اما برخی از فایل های متنی به اندازه کافی خوب نشان نمی دهند. وجود TAB ها در یک فایل متنی ممکن است فاصله دلخواه شما نباشد. برای تغییر TAB های خود به فاصله، از دستور Expand استفاده کنید.
$ expand sample.txt
دستور بالا خروجی را با تبدیل هر TAB به گروهی از فضاها چاپ می کند. برای ذخیره این خروجی در یک فایل، از تغییر مسیر خروجی مانند زیر استفاده کنید.
$ expand sample.txt > result.txt
در مقابل گسترش، میتوانیم هر گروه از فضاها را با دستور unexpand به یک TAB برگردانیم:
$ unexpand -a result.txt
(join&split) پیوستن و تقسیم
دستور join به شما این امکان را می دهد که چندین فایل را با یک فیلد مشترک به یکدیگر متصل کنید:
فرض کنید من دو فایل داشتم که می خواستم به هم بپیوندم:
file1.txt
1 John
2 Jane
3 Mary
file2.txt
1 Doe
2 Doe
3 Sue
$ join file1.txt file2.txt
1 John Doe
2 Jane Doe
3 Mary Sue
ببینید چگونه فایل های من را به هم متصل کرد؟ آنها به طور پیش فرض توسط فیلد اول به یکدیگر متصل می شوند و فیلدها باید یکسان باشند، در غیر این صورت می توانید آنها را مرتب کنید، بنابراین در این حالت فایل ها از طریق 1، 2، 3 به هم متصل می شوند.
چگونه به فایل های زیر بپیوندیم؟
file1.txt
John 1
Jane 2
Mary 3
file2.txt
1 Doe
2 Doe
3 Sue
برای پیوستن به این فایل باید مشخص کنید که به کدام فیلدها میپیوندید، در این مورد ما فیلد 2 را در file1.txt و فیلد 1 را در file2.txt میخواهیم، بنابراین دستور به شکل زیر است:
$ join -1 2 -2 1 file1.txt file2.txt
1 John Doe
2 Jane Doe
3 Mary Sue
-1 به file1.txt و -2 به file2.txt اشاره دارد. خیلی مرتب همچنین می توانید با دستور split یک فایل را به فایل های مختلف تقسیم کنید:
$ split somefile
با این کار آن را به فایلهای مختلف تقسیم میکند، بهطور پیشفرض پس از رسیدن به حد 1000 خط، آنها را تقسیم میکند. فایل ها به صورت پیش فرض x** نام دارند.
مرتب کردن
دستور sort برای مرتب سازی خطوط مفید است.
file1.txt
dog
cow
cat
elephant
bird
$ sort file1.txt
bird
cat
cow
dog
elephant
همچنین می توانید مرتب سازی معکوس انجام دهید:
$ sort -r file1.txt
elephant
dog
cow
cat
bird
و همچنین از طریق مقدار عددی مرتب کنید:
$ sort -n file1.txt
bird
cat
cow
elephant
dog
tr (ترجمه)
دستور tr (translate) به شما امکان می دهد مجموعه ای از کاراکترها را به مجموعه دیگری از کاراکترها ترجمه کنید. بیایید نمونه ای از ترجمه همه کاراکترهای کوچک به حروف بزرگ را امتحان کنیم.
$ tr a-z A-Z
hello
HELLO
همانطور که می بینید ما محدوده های a-z را به A-Z تبدیل کردیم و تمام متن هایی که تایپ می کنیم که با حروف کوچک هستند بزرگ می شوند.
یونیک (بی نظیر)
دستور uniq (unique) ابزار مفید دیگری برای تجزیه متن است.
فرض کنید یک فایل با تعداد زیادی تکراری داشتید:
reading.txt
book
book
paper
paper
article
article
magazine
و شما می خواهید موارد تکراری را حذف کنید، خوب می توانید از دستور uniq استفاده کنید:
$ uniq reading.txt
book
paper
article
magazine
بیایید تعداد دفعات یک خط را محاسبه کنیم:
$ uniq -c reading.txt
2 book
2 paper
2 article
1 magazine
بیایید فقط مقادیر منحصر به فرد را بدست آوریم:
$ uniq -u reading.txt
magazine
بیایید فقط مقادیر تکراری دریافت کنیم:
$ uniq -d reading.txt
book
paper
article
نکته: uniq خطوط تکراری را شناسایی نمی کند مگر اینکه مجاور باشند.
reading.txt
book
paper
book
paper
article
magazine
article
$ uniq reading.txt
reading.txt
book
paper
book
paper
article
magazine
article
نتیجه ای که توسط uniq برگردانده می شود، بر خلاف مورد اول شامل تمام ورودی ها خواهد بود
برای مثال:
برای غلبه بر این محدودیت uniq میتوان از مرتبسازی در ترکیب با uniq استفاده کرد:
$ sort reading.txt | uniq
article
book
magazine
paper
wc و nl
دستور wc (شمارش کلمات) تعداد کل کلمات یک فایل را نشان می دهد.
$ wc /etc/passwd
96 265 5925 /etc/passwd
به ترتیب تعداد خطوط، تعداد کلمات و تعداد بایت ها را نمایش می دهد.
برای مشاهده فقط تعداد یک فیلد خاص، به ترتیب از -l، -w یا -c استفاده کنید.
$ wc -l /etc/passwd
96
دستور دیگری که می توانید برای بررسی تعداد خطوط روی یک فایل استفاده کنید، دستور nl (خطوط اعداد) است.
file1.txt
i
like
turtles
$ nl file1.txt
1. i
2. like
3. turtles
grep
دستور grep احتمالاً رایج ترین دستور پردازش متنی است که استفاده می کنید. این به شما امکان می دهد فایل ها را برای کاراکترهایی جستجو کنید که با یک الگوی خاص مطابقت دارند. اگر بخواهید بدانید که آیا فایلی در یک دایرکتوری خاص وجود دارد یا اینکه بخواهید ببینید آیا رشته ای در یک فایل یافت شده است، شما مطمئناً تمام خط متن را بررسی نمی کنید، از grep استفاده می کنید.
بیایید از فایل sample.txt خود به عنوان مثال استفاده کنیم:
$ grep fox sample.txt
باید ببینید که grep فاکس را در فایل sample.txt پیدا کرده است.
همچنین می توانید الگوهایی را که به بزرگی و کوچکی حروف حساس هستند با پرچم -i grep کنید:
$ grep -i somepattern somefile
برای انعطاف پذیری بیشتر با grep می توانید آن را با دستورات دیگر با | ترکیب کنید.
$ env | grep -i User
همانطور که می بینید grep بسیار متنوع است. حتی می توانید از عبارات منظم در الگوی خود استفاده کنید:
$ ls /somedir | grep '.txt$'
باید تمام فایل هایی که با txt. در Somedir ختم می شوند را برگرداند.