فرمت خروجی

در این درس و درسهای پیش رو نگاهی به برخی از ابزارهای فرمتبندی خواهیم انداخت.
اکثر این ابزارها، تکمنظوره بوده و از نظر عملکرد، ساده میباشند؛ بهطوریکه میتوان آنها را برای وظایف کوچکی که بخشی از Pipelineها و اسکریپتها محسوب میشوند، استفاده نمود.
فرمان nl (شمارهگذاری خطوط)
این فرمان، ابزاری ویژه برای انجام وظیفه سادهای در نظر گرفته میشود. فرمان nl میتواند خطوط را شمارهگذاری کند:
1 2 3 4 5 6 7 8 9 10 11 |
[me@linuxbox ~]$ nl distros.txt | head 1 SUSE 10.2 12/07/2006 2 Fedora 10 11/25/2008 3 SUSE 11.0 06/19/2008 4 Ubuntu 8.04 04/24/2008 5 Fedora 8 11/08/2007 6 SUSE 10.3 10/04/2007 7 Ubuntu 6.10 10/26/2006 8 Fedora 7 05/31/2007 9 Ubuntu 7.10 10/18/2007 10 Ubuntu 7.04 04/19/2007 |
فرمان nl نیز همانند فرمان cat، نام فایل را بهعنوان آرگومانهای خط فرمان یا ورودی استاندارد قبول میکند. هرچند که فرمان nl دارای گزینههایی است و از شکل اولیه نشانهگذاری پشتیبانی میکند که اجازه میدهد تا شمارهگذاریهای پیچیدهتری انجام شود.
فرمان nl از مفهومی با نام Logical Pages (صفحات منطقی) در حین شمارهگذاری پشتیبانی میکند. این ویژگی به فرمان nl این اجازه را میدهد تا در حین شمارهگذاری، توالی شمارهگذاری از ابتدا آغاز گردد. با استفاده از گزینهها این قابلیت ایجاد میگردد. درواقع صفحات منطقی به هدر، بدنه و فوتر تقسیم میشوند. در هر کدام از این بخشها امکان دارد که شمارهگذاری ریست شده و از ابتدا آغاز گردد و یا یک استایل متفاوت اختصاص یابد.
اگر به فرمان nl چندین فایل داده شود، با آنها بهگونهای رفتار میشود که گویی یک جریان متن جداگانه هستند. بخشها در جریان متن، بهوسیله حضور برخی نشانهگذاریهای عجیب اضافه میگردد که در جدول زیر نمایش داده شدهاند:
نشانهگذاری | مفهوم |
---|---|
\:\:\: | شروع عنوان logical-page |
\:\: | شروع بدنه logical-page |
\: | شروع فوتر logical-page |
هر کدام از این عناصر نشانهگذاری در جدول بالا بایستی در خط خود نمایان شوند. پس از پردازش عنصر نشانهگذاری، فرمان nl آن را از جریان متن حذف میکند. جدول زیر، لیست گزینههای رایج مورد استفاده توسط فرمان nl را نشان میدهد:
گزینه | معنا |
---|---|
-b style | تعیین شمارهگذاری بدنه به استایل در حالیکه style یکی از موارد زیر است: a شماره همه خطوط t شماره فقط خطوط خالی. این گزینه پیشفرض است pregexp شماره فقط خطوط منطبق با عبارت منظم regexp |
-f style | تعیین شمارهگذاری فوتر به style. پیشفرض n هست (هیچکدام). |
-h style | تعیین شمارهگذاری هدر به style. پیشفرض n هست (هیچکدام). |
-i number | تعیین شمارهگذاری صفحه افزایشی به شماره. پیشفرض 1 هست (هیچکدام). |
-n format | تعیین شمارهگذاری فرمت به format در حالیکه format یکی از موارد زیر است: ln چپ بدون صفر پیشین rn راست بدون صفر پیشین. این مقدار پیشفرض است. rz راست به همراه صفر پیشین |
-p | شمارهگذاری صفحه را در ابتدای هر صفحه منطقی از ابتدا آغاز نکن. |
-s string | اضافه کردن string به آخر هر شماره خط برای ایجاد جداکننده. پیشفرض یک کاراکتر تب میباشد. |
-v number | تنظیم شماره خط اول از هر صفحه منطقی به number. پیشفرض 1 است. |
-w width | تعیین طول فیلد شماره خط به width. پیشفرض 6 است. |
مسلما خیلی خطوط را شمارهگذاری نخواهیم کرد ولی میتوانیم از فرمان nl استفاده کنیم تا ببینیم چگونه قادر به ترکیب ابزارهای مختلف برای اجرای وظایف پیچیدهتر هستیم. در دروس قبلی اسکریپتی برای گزارش توزیعهای لینوکس ایجاد کردیم.
از آنجایی که میخواهیم از فرمان nl بیشتر استفاده کنیم، مفید است که هدر، بدنه و فوتر را نشانهگذاری کنیم.
بدین منظور، این ویژگی را به اسکریپت sed که در دروس قبلی اجاد کرده بودیم، اضافه خواهیم کرد. با استفاده از ویرایشگر متنی، فایل مربوطه را تغییر داده و بهصورت distros-nl.sed ذخیره میکنیم:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
# sed script to produce Linux distributions report 1 i\ \\:\\:\\:\ \ Linux Distributions Report\ \ Name Ver. Released\ ---- ---- --------\ \\:\\: s/\([0-9]\{2\}\)\/\([0-9]\{2\}\)\/\([0-9]\{4\}\)$/\3-\1-\2/ $ a\ \\:\ \ End Of Report |
اکنون این اسکریپت نشانهگذاری صفحات مطقی را درج کرده و یک فوتر به انتهای گزارش اضافه میکند. به یاد داشته باشید که بایستی بکاسلشها را دوباره چک کنید. چون sed بهصورت عادی، آنها را بهعنوان کاراکتر Escape در نظر میگیرد.
سپس گزارش خود را با ترکیب فرمانهای sort، sed و nl ایجاد میکنیم:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
[me@linuxbox ~]$ sort -k 1,1 -k 2n distros.txt | sed -f distros-nl.sed | nl Linux Distributions Report Name Ver. Released ---- ---- -------- 1 Fedora 5 2006-03-20 2 Fedora 6 2006-10-24 3 Fedora 7 2007-05-31 4 Fedora 8 2007-11-08 5 Fedora 9 2008-05-13 6 Fedora 10 2008-11-25 7 SUSE 10.1 2006-05-11 8 SUSE 10.2 2006-12-07 9 SUSE 10.3 2007-10-04 10 SUSE 11.0 2008-06-19 11 Ubuntu 6.06 2006-06-01 12 Ubuntu 6.10 2006-10-26 13 Ubuntu 7.04 2007-04-19 14 Ubuntu 7.10 2007-10-18 15 Ubuntu 8.04 2008-04-24 16 Ubuntu 8.10 2008-10-30 End Of Report |
در این گزارش، عنوان مشخص شده، هر ستون دارای نام مشخصی است و در پایان هم بخش فوتر گزارش نشان داده شده است.
فرمان fold (قرار دادن هر خط به اندازه تعیین شده)
فرمان fold (برگرفته از واژه folding بهمعنای تا کردن)، مربوط به پروسه شکستن خطوط متن با اندازه تعیین شده میباشد. فرمان fold نیز همانند سایر فرمانها، یک یا چند فایل را بهعنوان ورودی استاندارد قبول میکند. اگر fold را به جریان ساده متن ارسال کنیم، مشاهده خواهیم کرد که چگونه کار میکند:
1 2 3 4 5 6 |
[me@linuxbox ~]$ echo "The quick brown fox jumped over the lazy dog." | fold -w 12 The quick br own fox jump ed over the lazy dog. |
در اینجا فرمان fold را بهصورت عملی میبینیم. جریان متنی که توسط echo ارسال شده به بخشهایی که با استفاده از گزینه –w کاراکتر ۱۲ را اختصاص داده شکسته شده است. اگر که هیچ طولی برای آن در نظر گرفته نشود، بهصورت پیشفرض تعداد کاراکتر ۸۰ در نظر گرفته میشود. به یاد داشته باشید که خطوط، بدون در نظر گرفتن آن کلمات واحد شکسته میشوند؛ پس ممکن است، کلمات نیز شکسته شوند. گزینه –s موجب میشود تا فرمان fold خطوط را در آخرین فضای موجود ممکن بشکند.
پس با افزودن این گزینه، از شکستن کلمات جلوگیری میکنیم:
1 2 3 4 5 6 7 |
[me@linuxbox ~]$ echo "The quick brown fox jumped over the lazy dog." | fold -w 12 -s The quick brown fox jumped over the lazy dog. |
فرمان fmt (یک فرمتدهنده ساده متن)
فرمان fmt علاوه بر اینکه متن را میشکند، عملیات بیشتری بر روی متن انجام میدهد. برنامه fmt ورودی استاندارد یا فایلها را قبول کرده و فرمتدهی پاراگراف را بر روی جریان متن انجام میدهد. بهطور کلی، این فرمان، خطوط را پر کرده و به هم متصل میکند. در عین حال از خطوط خالی و فرورفتگیهای متن محافظت میکند.
بهمنظور شرح موضوع، به کمی متن نیاز داریم. متن زیر را از صفحه اطلاعات فرمان fmt کپی میکنیم. این متن، متنی توضیحی است و هیچ چیز خاصی ندارد. پرواضح است که هر متن دیگری را میتوانید استفاده کنید:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
`fmt' reads from the specified FILE arguments (or standard input if none are given), and writes to standard output. By default, blank lines, spaces between words, and indentation are preserved in the output; successive input lines with different indentation are not joined; tabs are expanded on input and introduced on output. `fmt' prefers breaking lines at the end of a sentence, and tries to avoid line breaks after the first word of a sentence or before the last word of a sentence. A "sentence break" is defined as either the end of a paragraph or a word ending in any of `.?!', followed by two spaces or end of line, ignoring any intervening parentheses or quotes. Like TeX, `fmt' reads entire "paragraphs" before choosing line breaks; the algorithm is a variant of that given by Donald E. Knuth and Michael F. Plass in "Breaking Paragraphs Into Lines", `Software--Practice & Experience' 11, 11 (November 1981), 1119-1184. |
سپس این متن را به درون فایل جدیدی با نام fmt-info.txt ایجاد میکنیم، کپی خواهیم کرد. در ادامه، فرض خواهیم کرد که قصد داریم طول هر ستون در متن، ۵۰ کاراکتر باشد. این کار را به کمک فرمان fmt و گزینه –w بهصورت زیر انجام داده و خروجی را درون head پایپ میکنیم:
1 2 3 4 5 6 7 8 9 |
me@linuxbox ~]$ fmt -w 50 fmt-info.txt | head `fmt' reads from the specified FILE arguments (or standard input if none are given), and writes to standard output. By default, blank lines, spaces between words, and indentation are preserved in the output; successive input lines with different indentation are not joined; tabs are expanded on input and introduced on output. |
جدول زیر گزینههای موجود برای استفاده در فرمان fmt را نشان میدهد:
گزینه | توضیحات |
---|---|
-c | پردازش در crown margin mode. این گزینه فرورفتگی دو خط اول پاراگراف را حفظ میکند. خطوط بعدی با فرورفتگی خط دوم تراز میشوند. |
-p string | فرمتدهی فقط خطوطی که با string پیشوند شدهاند. پس از فرمتدهی، محتویات string با هر خط از قبل فرمتدهی شده پیشوند میشوند. این گزینه را میتوان برای فرمتدهی متن در ککامنتهای کد منبع استفاده کرد. برای مثال هر زبان برنامهنویسی یا فایل پیکربندی که از کاراکتر # برای معین کردن یک کامنت استفاده میکند میتواند با تعیین -p '#' فرمتدهی تا کامنتها فرمتدهی شوند. |
-s | Split-only mode. در این مود، فقط به منظور تناسب با طول ستون تقسیم میشوند. خطوط برای پر کردن فضا متصل نخواهند شد. این مود برای فرمتدهی متنهای مثل code زمانی که اتصال رضایتبخش نیست مفید خواهد بود. |
-u | انجام uniform spacing. این گزینه فرمتدهی سنتی را به متن اعمال میکند. به این معنی که یک فاصله بین کلمات و دو فاصله بین جملات اضافه میکند. |
-w width | فرمتدهی متن به منظور تناسب به طول کاراکترهای یک ستون. مقدار پیشفرض 75 کاراکتر میباشد. |
گزینه –p بسیار جالب است. با استفاده از آن میتوانیم بخشهای انتخاب شده فایل را فرمتدهی کنیم که این خطوط و بخشها با کاراکتر خاصی مشخص شدهاند. مثلا فرض کنید بسیاری از زبانهای برنامهنویسی برای شروع کامنت، از کاراکتر # استفاده میکنند. در نتیجه میتوان این بخش را با گزینه –p فرمتدهی کرد. بدین منظور فایلی را ایجاد میکنیم تا این قابلیت را نشان دهیم:
1 2 3 4 5 6 7 8 |
[me@linuxbox ~]$ cat > fmt-code.txt # This file contains code with comments. # This line is a comment. # Followed by another comment line. # And another. This, on the other hand, is a line of code. And another line of code. And another. |
در ابتدای فایلی که ایجاد کردیم، کامنتهایی است که با # شروع میشوند و بهدنبال آن برخی خطوط کد وجود دارد. اکنون میتوانیم با استفاده از فرمان fmt فقط کامنتها را فرمتدهی کنیم و کدها را به حال خود باقی بگذاریم:
1 2 3 4 5 6 7 |
[me@linuxbox ~]$ fmt -w 50 -p '# ' fmt-code.txt # This file contains code with comments. # This line is a comment. Followed by another # comment line. And another. This, on the other hand, is a line of code. And another line of code. And another. |
توجه داشته باشید که خطوط مجاور کامنتهای سوم و چهارم بههم متصل شدند، در حالی که خطوط خالی و خطوطی که با کاراکتر مورد نظر # آغاز نمیشوند، تغییری پیدا نمیکنند.
فرمان pr (فرمت متن برای چاپ)
فرمان pr بهمنظور صفحهبندی متن بهکار میرود. اگر صفحات متن با چند خط فضای خالی برای فاصله بین گوشهها و پایین و بالای متن ایجاد شود، چاپ متن، قابل قبولتر است. همچنین میتوان به منظور ایجاد هدر و فوتر بر روی هر صفحه از این فاصلهها استفاده کرد.
فرمان pr را با فرمتدهی فایل distros.txt (که در دروس قبلی ایجاد کردیم) به چند صفحه بسیار کوتاه، شرح میدهیم (در زیر، فقط دو صفحه اول نمایش داده شده است):
1 2 3 4 5 6 7 8 9 10 11 12 13 |
[me@linuxbox ~]$ pr -l 15 -w 65 distros.txt 2012-12-11 18:27 distros.txt Page 1 SUSE 10.2 12/07/2006 Fedora 10 11/25/2008 SUSE 11.0 06/19/2008 Ubuntu 8.04 04/24/2008 Fedora 8 11/08/2007 2012-12-11 18:27 distros.txt Page 2 SUSE 10.3 10/04/2007 Ubuntu 6.10 10/26/2006 Fedora 7 05/31/2007 Ubuntu 7.10 10/18/2007 Ubuntu 7.04 04/19/2007 |
در این مثال، گزینه –l (برای اندازه خط) و گزینه –w (برای اندازه صفحه) را بهکار گرفتیم. در ادامه، طول خطوط ۱۶ کاراکتر و طول صفحات ۶۵ کاراکتر تعیین شد. در نتیجه فرمان pr فایل distros.txt را به سه دسته تقسیم کرده و بالا و پایین صفحات را با فاصله خالی از هم جدا میکند.
فرمان printf (فرمت و چاپ داده)
برخلاف سایر فرمانهایی که بدان اشاره شد، فرمان printf را نمیتوان بههمراه Pipelineها استفاده کرد (چرا که ورودی استاندارد را قبول نمیکند). به همین خاطر کمتر (بهصورت مستقیم) در خط فرمان بهکار گرفته میشود و آن را بیشتر در فایلهای اسکریپت استفاده میکنند.
درواقع فرمان printf (برگرفته از عبارت Print Formatted بهمعنای چاپ قالببندی شده)، برای برنامهنویسان زبان C و Shell توسعه یافت و به تبع آن در بسیاری از زبانهای برنامهنویسی پیادهسازی شد. این فرمان با این ساختار کار میکند:
1 |
printf "format" arguments |
به فرمان، یک رشته داده میشود که حاوی توضیح فرمت است و سپس آرگومانهای مختلف میآید. نتیجه فرمتدهی شده به ورودی استاندارد، ارسال میگردد.
یک مثال ساده:
1 2 |
[me@linuxbox ~]$ printf "I formatted the string: %s\n" foo I formatted the string: foo |
ممکن است رشته فرمت، حاوی متن لیترال (مثل I formatted the string)، توالیهای Escape (مانند \n و خط جدید) و همچنین کاراکتر شروع خط % نیز باشد. در مثال بالا %s استفاده شده تا رشته foo فرمتدهی شود و آن را در خط فرمان، نمایش دهیم. مثالی دیگر:
1 2 |
[me@linuxbox ~]$ printf "I formatted '%s' as a string.\n" foo I formatted 'foo' as a string. |
همانگونه که مشاهده میشود، %s توسط foo در خروجی خط فرمان، جایگزین شد. تبدیل s بهمنظور فرمتدهی داده رشتهای بهکار گرفته میشود. مشخصکنندههای دیگری برای انواع مختلف داده وجود دارد که در جدول زیر، قابل مشاهده هستند:
مشخصکننده | توضیحات |
---|---|
d | فرمت یک شماره به عنوان یک شماره دسیمال صحیح |
f | فرمتدهی و خروجی یک شماره اعشاری |
o | فرمت یک عدد صحیح به عنوان یک عدد اوکتال |
s | فرمت یک رشته |
x | فرمت یک عدد صحیح به عنوان یک شماره هگزادسیمال با استفاده از حروف کوچک a-f |
X | همان x ولی استفاده از حروف بزرگ |
% | چاپ سمبول لیترال % |
تاثیر هر کدام از این مشخصکنندههای تبدیل را بر روی رشته ۳۸۰ در مثال زیر نشان میدهیم:
1 2 |
[me@linuxbox ~]$ printf "%d, %f, %o, %s, %x, %X\n" 380 380 380 380 380 380 380, 380.000000, 574, 380, 17c, 17C |
از آنجایی که شش مشخصکننده تبدیل قرار دادیم، بایستی ۶ آرگومان برای تبدیل نیز قرار دهیم. نتیج بهدست آمده توسط هر مشخصکننده تاثیر آن را نشان میدهد. برخی اجزای اختیاری را میتوان به مشخصکنندهها اضافه کرد.
یک مشخصه تبدیل کامل ممکن است شامل اجزای زیر باشد:
1 |
%[flags][width][.precision]conversion_specification |
جدول زیر این اجزا را توضیح میدهد:
جزء | توضیحات |
---|---|
flags | پنج نوع فلگ یا همان پرچم مختلف وجود دارد: # - استفاده از فرمت جایگزین برای خروجی. این بر اساس نوع داده متفاوت است. صفر - لایهگذاری خروجی با صفر. به این معنا که فیلد با صفرهای اولیه پر میشود. - (dash) - تراز به چپ خروجی. بصورت پیشفرض printf خروجی را تراز به راست میکند. space - ایجاد یک فاصله پیشین برای شمارههای مثبت + - نشانهگذاری شمارههای مثبت. بصورت پیشفرض printf فقط شمارههای منفی را نشانهگذاری میکند. |
width | یک شماره که طول حداقلی فیلد را تعیین میکند. |
.precision | برای شمارههای اعشاری، شماره رقم اعشار را در خروجی بعد از نقطه دسیمال مشخص میکند. |
جدول زیر، شامل مثالهایی از فرمتهای مختلف است:
آرگومان | فرمت | نتیجه | توضیح |
---|---|---|---|
380 | "%d" | 380 | فرمت ساده یک عدد صحیح |
380 | "%#x" | 0x17c | عدد صحیح فرمتدهی شده به عنوان یک عدد هگزادسیمال با استفاده از فلگ جایگزین فرمت |
380 | "%05d" | 00380 | عدد صحیح فرمتدهی شده با صفر پیشین و یک طول حداقلی پنج کاراکتری |
380 | "%05.5f" | 380.00000 | عدد فرمتدهی شده به عنوان یک شماره اعشاری به همراه پنج رقم اعشاری |
380 | "%010.5f" | 0380.00000 | افزایش طول کمینه فیلد به 10 که لایهگذاری را نمایان میکند |
380 | "%+d" | +380 | فلگ + یک عدد مثبت را نشانهگذاری میکند |
380 | "%-d" | 380 | فلگ - فرمتدهی را به چپ تراز میکند. |
abcdefghijk | "%5s" | abcedfghijk | یک رشته که با طول کمینه فیلد فرمتدهی شده است |
abcdefghijk | "%.5s" | abcde | با اعمال اعشار به یک رشته باعث حذف آن میگردد |
با اینکه فرمان printf بهجای آنکه بهصورت مستقیم در خط فرمان بهکار گرفته شود، بیشتر در اسکریپتها (غالبا برای فرمتدهی دادههای جدولی) کاربرد دارد؛ ولی هنوز هم قادریم که نشان دهیم چگونه میتوان از آن برای مشکلات مختلف فرمتددهی استفاده کنیم.
در ابتدا برخی از فیلدها را بهوسیله کاراکترهای Tab در خروجی نشان میدهیم:
1 2 |
[me@linuxbox ~]$ printf "%s\t%s\t%s\n" str1 str2 str3 str1 str2 str3 |
با درج \t (توالی عبور برای کاراکتر Tab)، نتیجه دلخواه را دریافت میکنیم. حالا برخی شمارهها را با فرمتی واضح نمایش میدهیم:
1 2 3 |
[me@linuxbox ~]$ printf "Line: %05d %15.3f Result: %+15d\n" 1071 3.14156295 32589 Line: 01071 3.142 Result: +32589 |
این فرمان، تاثیر حداقل طول فیلد بر روی فضای فیلدها را یا اینکه چگونه صفحه وب کوچکی را فرمتدهی کنیم را نشان میدهد:
1 2 3 4 5 6 7 8 9 10 |
[me@linuxbox ~]$ printf "<html>\n\t<head>\n\t\t<title>%s</title>\n\t</head> \n\t<body>\n\t\t<p>%s</p>\n\t</body>\n</html>\n" "Page Title" "Page Content" <html> <head> <title>Page Title</title> </head> <body> <p>Page Content</p> </body> </html> |