جستجو برای مثالهای چگونگی افزودن محلیسازی ساده به اسکریپتهای bash خودتان، و چگونگی انجام آزمایش؟ احتمالاً آنچه شما میخواهید این است....
فهرست
قبل از اینکه حتی بتوانیم شروع کنیم، باید تمام متغیرهای محیط منطقه را شیرفهم بشویم. این مورد پایهای است و در محلهایی که مردم به مستندات(صفحات man، و غیره) توجه مینمایند، برای مستندسازی بینهایت مهم است. بعضی از این متغیرها ممکن است در سیستم شما فراهم نباشند، زیرا به نظر میرسد استانداردهای گوناگونی برای توسعه و رقابت وجود دارد....
در سیستمهای اخیر گنو، متغیرها به این ترتیب استفاده میشوند:
اگر LANGUAGE تنظیم است، آن را استفاده کنید، مگر اینکه LANG برابر با C تنظیم شود، در چنین حالتی LANGUAGE صرف نظر میشود. همچنین، بعضی برنامهها در حقیقت ابداً از LANGUAGE استفاده نمیکنند.
این به آن معنا میباشد که شما باید اول محیط جاری را برای دیدن اینکه کدام یک از این متغیرها قبلاً تنظیم شدهاند، کنترل نمایید. اگر آنها تنظیم شده باشند و شما ندانید، ممکن است آنها در بررسیهای شما دخالت کرده، شما را گیج کنند.
$ env | egrep 'LC|LANG' LANG=en_US.UTF-8 LANGUAGE=en_US:en_GB:en
این مثالی از یک سیستم دبیان است. در این حالت، متغیر LANGUAGE برقرار است، یعنی ما هر آزمایشی انجام بدهیم که با تغییر LANG درگیر بشود احتمالاً ناموفق است، مگر اینکه ما LANGUAGE را هم تغییر بدهیم. حال در اینجا مثال دیگری از یک سیستم دبیان دیگر:
$ env | egrep 'LC|LANG' LANG=en_US.utf8
در این حالت، تغییر LANG واقعاً کار خواهد کرد. سندی که یک کاربر در این سیستم، در مورد چگونگی انجام آزمایش محلیسازی بنویسد، شاید دستورالعملهایی ایجاد کند که برای کار کردن کاربر در سیستم اول شکست بخورد....
بنابراین، پیش بروید و با سیستم خودتان بررسی کنید و ببینید کدام کار میکند و کدام کار نمیکند. ممکن است شما اصلاً متغیر LANGUAGE نداشته باشید(محصوصاً اگر در گنو-لینوکس نباشید)، از اینرو ممکن است تنظیم آن برای شما نتیجهای نداشته باشد. شاید لازم باشد دستور locale -a را به کار ببرید تا ببینید کدام تنظیمات منطقه معتبر هستند. ممکن است لازم باشد یک مجموعه کاراکتری را در متغیر LANG تعیین نمایید(به عنوان مثال es_ES.utf8 به جای es_ES). شاید برای اینکه موجب کار کردن آنها بشوید، بایستی مناطق را در سیستم عامل خود ایجاد کنید(پردازشی که فراتر از حوزه این صفحه است، اما در سیستم دبیان متشکل از اجرای dpkg-reconfigure locales و پاسخ دادن به پرسشها است).
تلاش کنید به آنجا برسید که حداقل در دو زبان بتوانید پیغامهای خطا تولید کنید :
$ wc -q wc: invalid option -- 'q' Try `wc --help' for more information. $ LANGUAGE=es_ES wc -q wc: opción inválida -- q Pruebe `wc --help' para más información.
وقتی که بتوانید آن کار را به طور قابل قبولی انجام بدهید، میتوانید کار واقعیِ تولید اسکریپت bash با محلیسازی را شروع کنید.
این قسمت حداقل از جهت فهمیدن، سادهترین بخش است. هر رشته در $"..." با استفاده از امکانات پشتیبانی زبان محلی (NLS) سیستم ترجمه میشود. تمام رشتههای ثابت در برنامه خود را که میخواهید ترجمه شوند، یافته و علامتگذاری کنید. رشتههای شامل متغیرها یا سایر جایگزینیها را علامت نزنید. برای مثال
#!/bin/bash
echo $"Hello, world"
(به طوری که میتوانید ببینید، ما در اینجا با مورد بسیار ساده شروع میکنیم.)
Bash (حداقل بعد از 4.0) بسط منطقه را قبل از سایر جایگزینیها انجام میدهد. بدین معنی، در حالتی مانند این مورد:
echo $"The answer is $answer"
رشته لفظی $answer بخشی از رشته علامت زده خواهد شد. ترجمه نیز باید شامل $answer باشد، و bash جایگزینی متغیر را در رشته ترجمه شده انجام خواهد داد. ترتیبی که bash این جایگزینیها را انجام میدهد یک حفره امنیتی بالقوه را مطرح میکند که ما در اینجا آن را پوشش نخواهیم داد. (وصلهای ارائه شده است، اما هنوز خیلی ابتدایی است....)
سپس، آنچه "PO files" نامیده شده را بواسطه برنامه خودتان تولید کنید. این فایلها محتوی رشتههایی که علامتگذاری کردهایم، و ترجمه آنها(که بعداً قرار خواهیم داد) هستند.
با ایجاد یک فایل *.pot که یک الگو میباشد، شروع میکنیم.
bash --dump-po-strings hello > hello.pot
خروجی که این کد تولید میکند به این شکل خواهد بود:
#: hello:5
msgid "Hello, world"
msgstr ""
نام فایل شما(بدون پسوند .pot) domain متن قابل ترجمه شما نامیده میشود. domain در این زمینه مشابه نام یک بسته( package) است. به عنوان مثال، بسته coreutils گنو شامل تعداد بسیاری برنامههای کوچک است، اما تمام آنها متفقاً توزیع میگردند، و بنابراین، معقول است تمام ترجمههای آنها نیز با یکدیگر باشند. ما در این مثال از domain با نام hello استفاده میکنیم. در یک مثال بزرگترِ محتوی تعداد زیادی برنامه در یک مجموعه، احتمالاً باید نام کل مجموعه را استفاده کنیم.
این الگو برای هر زبانی که میخواهیم پشتیبانی نماییم، یکبار کپی خواهد شد. بیایید فرض کنیم میخواهیم ترجمههای اسپانیایی و فرانسوی را برای برنامههای خود پشتیبانی نماییم. ما دو فایل PO (یکی برای هر ترجمه) ایجاد خواهیم نمود، پس اجازه بدهید دو شاخه فرعی بسازیم و الگو را در هر یک از آنها کپی کنیم:
mkdir es fr cp hello.pot es/hello.po cp hello.pot fr/hello.po
این است آنچه ما در نوبت اول انجام میدهیم. اگر از قبل بعضی فایلهای جزئی یا حتی ترجمه تکمیل شده PO درآنجا وجود داشت، ما نمیخواستیم آنها را رونویسی کنیم. پس به جای آن، موارد ترجمه جدید را در فایل قدیمی PO ادغام مینمودیم. برای این کار از ابزار ویژهای به نام msgmerge استفاده مینماییم. اجازه بدهید فرض کنیم که مقدار بیشتری کُد(و رشتههای قابل ترجمه) به برنامه خودمان اضافه میکنیم:
vi hello bash --dump-po-strings hello > hello.pot msgmerge --update es/hello.po hello.pot msgmerge --update fr/hello.po hello.pot
مؤلف اصلی این صفحه مقداری یادداشت تهیه نموده است که من در اینجا دستنخورده رها میکنم. شاید سودمند واقع بشوند...؟
# step 5: try to merge existing po with new updates # remove duplicated strings by hand or with sed or something else # awk '/^msgid/&&!seen[$0]++;!/^msgid/' lang/nl.pot > lang/nl.pot.new msgmerge lang/nl.po lang/nl.pot
# step 5.1: try to merge existing po with new updates cp --verbose lang/pct-scanner-script-nl.po lang/pct-scanner-script-nl.po.old awk '/^msgid/&&!seen[$0]++;!/^msgid/' lang/pct-scanner-script-nl.pot > lang/pct-scanner-script-nl.pot.new msgmerge lang/pct-scanner-script-nl.po.old lang/pct-scanner-script-nl.pot.new > lang/pct-scanner-script-nl.po
# step 5.2: try to merge existing po with new updates touch lang/pct-scanner-script-process-nl.po lang/pct-scanner-script-process-nl.po.old awk '/^msgid/&&!seen[$0]++;!/^msgid/' lang/pct-scanner-script-process-nl.pot > lang/pct-scanner-script-process-nl.pot.new msgmerge lang/pct-scanner-script-process-nl.po.old lang/pct-scanner-script-process-nl.pot.new > lang/pct-scanner-script-process-nl.po
این مرحلهای است که 100% آن کار انسانی است. فایل PO هر زبان را ویرایش کنید و محلهای خالی را پُر کنید.
#: hello:5
msgid "Hello, world"
msgstr "Hola el mundo"
#: hello:6
msgid "How are you?"
msgstr ""
سیستم عامل شما، اگر شما را تا اینجا پیشآورده، احتمالاً از قبل چند برنامه محلی شده با کاتالوگهای ترجمه نصب شده درجایی مانند /usr/share/locale (یا جای دیگری) دارد. اگر میخواهید ترجمههای شما نیز در همان محل نصب بشوند، باید از اختیارات کاربر ارشد برخوردار باشید، و شما باید domain یا (namespace) ترجمه خود را به طوری مدیریت نمایید که از برخورد با تمام بستههای سیستمعامل اجتناب گردد.
اگر میخواهید از محل استاندارد سیستم برای ترجمههایتان استفاده کنید، آنوقت فقط لازم است در اندیشه انجام یک تغییر در برنامه خود باشید: تنظیم متغیر TEXTDOMAIN.
#!/bin/bash
TEXTDOMAIN=hello
echo $"Hello, world"
echo $"How are you?"
این متغیر به bash و کتابخانههای سیستم میگوید از کدام فایل MO در محل استاندارد استفاده نمایند. اگر میخواهید از مکان غیر استاندارد استفاده نمایید، آنوقت باید آن محل را نیز در متغیری به نام TEXTDOMAINDIR قرار بدهیم:
#!/bin/bash
TEXTDOMAINDIR=/usr/local/share/locale
TEXTDOMAIN=hello
echo $"Hello, world"
echo $"How are you?"
بنابر نیاز خود یکی از این موارد را به کار ببرید.
یک فایل MO در اصل یک فایل کامپایل شده PO میباشد. برنامهای به نام msgfmt عهدهدار این کامپایل نمودن است. اکنون ما فقط باید بگوییم فایل PO کجاست و فایل MO کجا نوشته شود.
msgfmt -o /usr/share/locale/es/LC_MESSAGES/hello.mo es/hello.po msgfmt -o /usr/share/locale/fr/LC_MESSAGES/hello.mo fr/hello.po یا mkdir -p /usr/local/share/locale/{es,fr}/LC_MESSAGES msgfmt -o /usr/local/share/locale/es/LC_MESSAGES/hello.mo es/hello.po msgfmt -o /usr/local/share/locale/fr/LC_MESSAGES/hello.mo fr/hello.po
(اگر ما بیش از دو ترجمه برای پشتیبانی داشتیم، میتوانستیم تقلید از ساختار /usr/share/locale برای تسهیل کپی گروهی فایلهای MO از دایرکتوری محلی به مخزن سیسمعامل را انتخاب نماییم. این به عنوان تمرین واگذار شد.)
آنچه قبلاً در باره متغیرهای محیط منطقه گفتیم را به خاطر بیاورید...مثالهای اینجا ممکن است در سیستم شما کار بکنند یا نکنند.
برنامه gettext میتواند برای بازیابی ترجمههای شخصی از کاتالوگ به کار برود:
$ LANGUAGE=es_ES gettext -d hello -s "Hello, world" Hola el mundo
همه رشتههای ترجمه نشده به حال خود رها میشوند:
$ LANGUAGE=es_ES gettext -d hello -s "How are you?" How are you?
و سرانجام، هیچ جایگزینی برای اجرای واقعی خود برنامه وجود ندارد:
wooledg@wooledg:~$ LANGUAGE=es_ES ./hello Hola el mundo How are you?
به طوری که میتوانید ببینید، هنوز برای مثال ما مقدار دیگری ترجمه وجود دارد که باید انجام بشود. برگردید به کار....
پرسش و پاسخ 98 (آخرین ویرایش 2012-03-11 00:08:39 توسط host-216-57-70-194)
مستندات در این مورد مبهم است، اما میتوانید به نوعی با دستورات داخلی پوسته آن را انجام دهید:
# Bash if [[ ( -L $name ) && ( ! -e $name ) ]] then echo "$name is a dangling symlink" fi
صفحه man در Bash به شما میگوید که "-L" «اگر فایل موجود باشد و پیوند نمادین باشد» True را برمیگرداند، و "-e" «اگر فایل موجود باشد» True را باز میگرداند. آنچه میتواند روشن نباشد، آنست که "-L" ملاحظه میکند که فایل خودش لینک باشد. اما، برای "-e"، فایل مقصد لینک نمادین است(جایی که لینک به آن اشاره میکند). به این دلیل است که شما برای دیدن آنکه پیوند نمادین منفصل است، به هر دو بررسی نیاز دارید، "-L" خود لینک را بررسی میکند، و "-e" جایی که لینک به آن اشاره میکند را بررسی میکند.
POSIX به طور مشابهی دارای همین بررسیها میباشد، بنابراین اگر بنا به دلایلی شما نمیتوانید از فرمان(ارجح) [[ استفاده کنید، همان بررسی میتواند با استفاده ازفرمان قدیمیتر [ انجام بشود:
# POSIX if [ -L "$name" ] && [ ! -e "$name" ] then echo "$name is a dangling symlink" fi
پرسش و پاسخ 97 (آخرین ویرایش 2012-01-13 09:52:29 توسط ght)
ssh رفتار فرمان راه دور پوسته یونیکس (rsh یا remsh) شامل این باگ، را شبیهسازی میکند. چند روش برای عبور موقت موجود است، و به طور دقیق وابسته آنست که شما چه چیزی لازم دارید.
نخست، اینجا توضیح کاملی از مشکل است:
~$ ~/bin/args make CFLAGS="-g -O" 2 args: 'make' 'CFLAGS=-g -O' ~$ ssh localhost ~/bin/args make CFLAGS="-g -O" Password: 3 args: 'make' 'CFLAGS=-g' '-O'
آنچه رخ میدهد آنست که در طرف سرویسگیرنده، فرمان و شناسههایش در یک رشته با یکدیگر منگنه میشوند، سپس از طریق ارتباط ssh به طرف سرویسدهنده رانده میشود، جایی که آن رشته به عنوان یک شناسه، برای تفکیک مجدد در اختیار پوسته شما قرار داده میشود. این آنچه ما میخواهیم نیست.
سادهترین راه عبور از این مشکل چسباندن همه چیز باهم در یک نقلقول منفرد، و اضافه کردن دستی نقلقولها عیناً در محلهای صحیح، میباشد، تا آماده کار با آن بشویم.
~$ ssh localhost '~/bin/args make CFLAGS="-g -O"' Password: 2 args: 'make' 'CFLAGS=-g -O'
پوستهِ رویِ میزبان راه دور شناسه را مجدداً تجزیه میکند، آن را به کلمات میشکند، و سپس اجرا مینماید.
مشکل نخست با این رویکرد آنست که، خسته کننده است . اگر ما از قبل هردو نوع نقلقول ، و جایگزینیهای بسیار زیاد پوسته را که باید انجام بشوند، داشته باشیم، آنوقت شاید عاقبت مجبور شویم مقدار انبوهی را با اضافه نمودن
روش دیگر حل و فصل این مسئله آن است که به جای عبور دادن فرمان(ها) به عنوان شناسه، آنها را به عنوان stdin برای پوسته راه دور ارسال کنیم. این روش در همه حالتها کار نخواهد کرد، این بدان خاطر است که فرمان در حال اجرا روی سیستم راه دور نمیتواند از stdin برای مقصود دیگری استفاده نماید، چون ما در حال مسدود نمودن stdin برای ارسال فرمانهای خود میباشیم. اما در وضعیتهایی که میتواند استفاده شود، کاملاً خوب کار میکند:
# POSIX # .برای استفاده توسط برنامه راه دور در دسترس نخواهد بود ssh remotehost sh <<EOF make CFLAGS="-g -O" EOF
حال اجازه بدهید مشکل واقعگرایانهتری را در نظر بگیریم: میخواهیم یک اسکریپت wrapper بنویسیم که make را روی میزبان راه دور با شناسههای فراهم شده توسط کاربر که دست نخورده همراه با آن عبور داده میشوند، فراخوانی میکند. این بسیار دشوارتر از آنست که در نگاه اول به نظر میرسد، به دلیل آنکه ما نمیتوانیم همه چیز را در یک کلمه به یکدیگر بچسبانیم -- فراخواننده اسکریپت میتواند شناسههای واقعاً پیچیده، نقلقولها، و نام مسیرهای شامل فاصلهها، و فوقکاراکترهای پوسته را استفاده کند، که لازم است تمام اینها به دقت حفاظت بشوند. خوشبختانه، bash روشی جهت محافظت از چنین مواردی به طور سالم برای ما فراهم نموده است: printf %q. با یک آرایه و یک حلقه همراه یکدیگر، میتوانیم یک wrapper بنویسم:
# Bash < 3.1 # sh باشد نه BASH پوسته حساب کاربری شما روی میزبان راه دور باید unset a i for arg; do a[i++]=$(printf %q "$arg") done exec ssh remotehost make "${a[@]}"
# Bash 3.1 and up # sh باشد نه BASH پوسته حساب کاربری شما روی میزبان راه دور باید unset a for arg; do printf -v temp %q "$arg" a+=("$temp") done exec ssh remotehost make "${a[@]}"
# Bash 4.1 and up # sh باشد نه BASH پوسته حساب کاربری شما روی میزبان راه دور باید unset a i for arg; do printf -v 'a[i++]' %q "$arg" done exec ssh remotehost make "${a[@]}"
اگر نیاز داشته باشیم که در میزبان راه دور قبل از اجرای make دایرکتوری را نیز تغییر بدهیم، میتوانیم آن را هم اضافه کنیم:
# Bash < 3.1 # sh باشد نه BASH پوسته حساب کاربری شما روی میزبان راه دور باید unset a i for arg; do a[i++]=$(printf %q "$arg") done exec ssh remotehost cd "$PWD" "&&" make "${a[@]}"
(اگر $PWD شامل کاراکتر فاصله باشد، آنوقت لازم است آن نیز با همان ترفند printf %q محافظت گردد، که به عنوان تمرین به خواننده واگذار میگردد.)
پرسش و پاسخ 96 (آخرین ویرایش 2012-06-18 13:16:12 توسط geirha)
ابتدا، بیایید برخی موضوعات زمینهای را بازبینی کنیم. موقعی که یک پردازش میخواهد پردازش دیگری را اجرا کند، یک فرزند fork()(منشعب) میکند، و پردازش فرزند یکی از فراخوانهای سیستمی خانواده exec* (مانندexecve())، را با دادن نام یا مسیر فایل برنامه پردازش جدید، نام پردازش جدید، لیست شناسهها برای پردازش جدید، و در بعضی حالتها، مجموعهای از متغیرهای محیط، فراخوانی میکند. از این قرار:
/* C */ execlp("ls", "ls", "-l", "dir1", "dir2", (char *) NULL);
محدودیتی(به طور معمول) برای تعداد شناسههایی که به این طریق میتواند عبور داده شود، وجود ندارد، اما در اکثر سیستمها، حدی برای اندازه کل لیست، وجوددارد. برای جزئیات بیشتر، http://www.in-ulm.de/~mascheck/various/argmax/ را ملاحظه کنید.
اگر شما در یک فراخوانی منفرد برنامه، سعی کنید (مثلاً) نامفایلهای بسیار زیادی را عبور بدهید، با موردی مشابه این مواجه میشوید:
$ grep foo /usr/include/sys/*.h bash: /usr/bin/grep: Arg list too long
ترفندهای گوناگونی وجود دارد که میتوانستید برای غلبه براین مورد به صورت تک موردی(فاقد عمومیت) به کار ببرید(اول تعویض دایرکتوری به /usr/include/sys، و سپس استفاده از grep foo *.h برای کوتاه نمودن طول هر نام فایل...)، اما اگر راهکار کاملا نیرومندی لازم داشته باشید چطور؟
بعضی اشخاص در اینجا دوست دارند xargs را به کار ببرند، اما این مورد مسائل خطیری دارد. این فرمان با کاراکترهای فضای سفید و نقلقول در ورودیاش به عنوان جداکننده کلمات رفتار میکند، که آن را برای مدیریت صحیح نامفایلها، نالایق میسازد. (برای تشریح مطلب در این خصوص، صفحه کاربرد find را ببینید.)
اگر عمل بازگشتی مورد قبول است، میتوانید به طور مستقیم find را استفاده کنید:
find /usr/include/sys -name '*.h' -exec grep foo /dev/null {} +
اگر بازگشت قابل قبول نیست اما شما find گنو را دارید، میتوانید این جایگزین غیرقابلحمل را به کار ببرید:
GNUfind /usr/include/sys -name '*.h' -maxdepth 1 -exec grep foo /dev/null {} +
(به یاد بیاورید که اگر grep بیش از یک نام فایل برای پردازش دریافت کند، تنها نامفایلها را چاپ خواهد کرد. پس، ما برای تضمین آنکه همواره حتی اگر -exec فقط یک نام به آن عبور دهد، حداقل دو نامفایل دارد، /dev/null را به عنوان نام فایل به آن عبور میدهیم.)
عمومیترین پیشنهاد استفاده از آرایه Bash و حلقهای برای پردازش در قطعات بزرگ است:
# Bash files=(/usr/include/*.h /usr/include/sys/*.h) for ((i=0; i<${#files[*]}; i+=100)); do grep foo "${files[@]:i:100}" /dev/null done
اینحا، ما پردازش یکصد عنصر در هر نوبت را انتخاب کردهایم، البته این اختیاری است، و شما میتوانید به نسبت پیش بینی شده برای اندازه هر عنصر، در مقایسه با مقدار ARG_MAX برنامه getconf سیستم مقصد، به مقدار بیشتر یا کمتر تنظیم کنید. اگر میخواهید تصوری به دست آورید، میتوانیدبا استفاده از ARG_MAX و اندازه بزرگترین عنصر محاسبه کنید، اما بازهم باید «ضرایب جبرانی» برای اندازه محیط و غیره را در نظر بگیرید. آسانتر است فقط یک مقدار محافظهکارانه را به امید آنکه بهترین مقدار باشد انتخاب نمود.
پرسش و پاسخ 95 (آخرین ویرایش 2010-01-06 14:23:30 توسط GreyCat)
متأسفانه، تجزیه خروجی فرمان df واقعاً معتبرترین روش تعیین پر شدن کامل دیسک در اکثر سیستمعاملها میباشد. به هر حال، لطفاً توجه نمایید که این کم ضررترین پاسخ است، نه بهترین جواب. تجزیه خروجی هر ابزار گزارش خط فرمانی هرگز خوشآیند نمیباشد. مقصود از این FAQ کوششی برای تشریح تمام مشکلات شناخته شده رویاروی این راهکار، و عبور موقت از آنها میباشد.
نخست، بزرگترین مشکل با df آن است که در تمام سیستمعاملها به صورت یکسان کار نمیکند. یونیکس به طور عمده به دو خانواده تقسیم میشود-- System V و BSD. در سیستمهای خانواده BSD(در این وضعیت، شامل لینوکس)، df یک گزارش قابل خواندن انسانی ارائه میکند:
~$ df Filesystem 1K-blocks Used Available Use% Mounted on /dev/sda2 8230432 3894324 3918020 50% / tmpfs 253952 8 253944 1% /lib/init/rw udev 10240 44 10196 1% /dev tmpfs 253952 0 253952 0% /dev/shm
در حالیکه، در سیستمهای همخانواده با System-V، خروجی به طور کامل متفاوت است:
$ df /net/appl/clin (svr1:/dsk/2/clin/pa1.1-hpux10HP-UXB.10.20): 1301728 blocks -1 i-nodes /net/appl/tool-share (svr2:/dsk/4/dsk3/tool/share): 51100992 blocks 4340921 i-nodes /net/appl/netscape (svr2:/dsk/4/dsk3/netscape/pa1.1-hpux10HP-UXB.10.20): 51100992 blocks 4340921 i-nodes /net/appl/gcc-3.3 (svr2:/dsk/4/dsk3/gcc-3.3/pa1.1-hpux10HP-UXB.10.20): 51100992 blocks 4340921 i-nodes /net/appl/gcc-3.2 (svr2:/dsk/4/dsk3/gcc-3.2/pa1.1-hpux10HP-UXB.10.20): 51100992 blocks 4340921 i-nodes /net/appl/tool (svr2:/dsk/4/dsk3/tool/pa1.1-hpux10HP-UXB.10.20): 51100992 blocks 4340921 i-nodes /net/home/wooledg (/home/wooledg ): 658340 blocks 87407 i-nodes /net/home (auto.home ): 0 blocks 0 i-nodes /net/hosts (-hosts ): 0 blocks 0 i-nodes /net/appl (auto.appl ): 0 blocks 0 i-nodes /net/vol (auto.vol ): 0 blocks 0 i-nodes /nfs (-hosts ): 0 blocks 0 i-nodes /home (/dev/vg00/lvol5 ): 658340 blocks 87407 i-nodes /opt (/dev/vg00/lvol6 ): 623196 blocks 83075 i-nodes /tmp (/dev/vg00/lvol4 ): 86636 blocks 11404 i-nodes /usr/local (/dev/vg00/lvol9 ): 328290 blocks 41392 i-nodes /usr (/dev/vg00/lvol7 ): 601750 blocks 80228 i-nodes /var (/dev/vg00/lvol8 ): 110696 blocks 14447 i-nodes /stand (/dev/vg00/lvol1 ): 110554 blocks 13420 i-nodes / (/dev/vg00/lvol3 ): 190990 blocks 25456 i-nodes
بنابراین، اولین سد راه شما، تشخیص آن خواهد بود که ممکن است نسبت به آنکه با کدام سیستم عامل کار میکنید، دستور متفاوتی لازم داشته باشید(به عنوان مثال bdf در HP-UX)، و شاید سیستمهایی باشند که واقعاً در آنها انجام این کار با اسکریپت پوسته به هیچ وجه امکانپذیر نباشد.
برای بقیه این مبحث، ما فرض خواهیم نمود که شما سیستمی با فرمان df همخانواده BSD در اختیار دارید.
مشکل بعدی آن است که قالب خروجی df در تمام سکوها(پلاتفرمها) یکسان نمیباشد.بعضی سکوها از خروجی شش ستونی و برخی از هفت ستونی استفاده میکنند. برخی سکوها(مانند لینوکس)، موقع گزارش فضای واقعی استفاده شده یا در دسترس، به طور پیشفرض بلوکهای یک کیلوبایتی به کار میبرند، دیگران، مانند OpenBSD یا IRIX، به طور پیشفرض بلوکهای 512 بایت را به کار میبرند و برای استفاده از کیلوبایتها گزینه -k را لازم دارند.
بدتر از آن، اغلب یک سطر خروجی در صفحه نمایش به چند سطر تقسیم خواهد شد. برای مثال(لینوکس):
Filesystem 1K-blocks Used Available Use% Mounted on ... svr2:/dsk/4/dsk3/tool/i686Linux2.4.27-4-686 35194552 7856256 25550496 24% /net/appl/tool
اگر نام دستگاه به اندازه کافی طولانی باشد(با فایلسیستمهای متصلشده شبکه خیلی رایج است)، df ممکن است در کوشش برای حفظ خوانایی ستونها برای انسان، خروجی را به دو سطر تقسیم کند. یا شاید نکند...برای مثال، OpenBSD 4.3 را ببینید:
~$ df Filesystem 512-blocks Used Avail Capacity Mounted on /dev/wd0a 253278 166702 73914 69% / /dev/wd0d 8121774 6904178 811508 89% /usr /dev/wd0e 8121774 6077068 1638618 79% /var /dev/wd0f 507230 12 481858 0% /tmp /dev/wd0g 8121774 5653600 2062086 73% /home /dev/wd0h 125253320 116469168 2521486 98% /export ~$ sudo mount 192.168.2.5:/var/cache/apt/archives /mnt ~$ df Filesystem 512-blocks Used Avail Capacity Mounted on /dev/wd0a 253278 166702 73914 69% / /dev/wd0d 8121774 6904178 811508 89% /usr /dev/wd0e 8121774 6077806 1637880 79% /var /dev/wd0f 507230 12 481858 0% /tmp /dev/wd0g 8121774 5653600 2062086 73% /home /dev/wd0h 125253320 116469168 2521486 98% /export 192.168.2.5:/var/cache/apt/archives 1960616 1638464 222560 88% /mnt
اکثر نگارشهای df گزینه -P را در اختیار شما قرار میدهند که به منظور میزان کردن خروجی است... نسبتاً. نگارشهای قدیمیتر OpenBSD حتی موقعی که گزینه -P فراهم میشود، بازهم سطرهای خروجی را تقسیم میکنند، اما لینوکس به طور کلی خروجی برای هر فایلسیستم در یک سطر را تحمیل میکند.
بنابراین، اگر میخواهید اسکریپت نیرومندی بنویسید، نمیتوانید فرض کنید خروجی برای یک فایلسیستم معین در یک سطر منفرد خواهد بود. ما بعداً به این مورد باز میگردیم.
شما مرتب بودن عمودی ستونها را نیز نمیتوانید فرض نمایید:
~$ df -P Filesystem 1024-blocks Used Available Capacity Mounted on /dev/hda1 180639 93143 77859 55% / tmpfs 318572 4 318568 1% /dev/shm /dev/hda5 90297 4131 81349 5% /tmp /dev/hda2 5763648 699476 4771388 13% /usr /dev/hda3 1829190 334184 1397412 20% /var /dev/sdc1 2147341696 349228656 1798113040 17% /data3 /dev/sde1 2147341696 2147312400 29296 100% /data4 /dev/sdf1 1264642176 1264614164 28012 100% /data5 /dev/sdd1 1267823104 1009684668 258138436 80% /hfo /dev/sda1 2147341696 2147311888 29808 100% /data1 /dev/sdg1 1953520032 624438272 1329081760 32% /mnt /dev/sdb1 1267823104 657866300 609956804 52% /data2 imadev:/home/wooledg 3686400 3336736 329184 92% /net/home/wooledg svr2:/dsk/4/dsk3/tool/i686Linux2.4.27-4-686 35194552 7856256 25550496 24% /net/appl/tool svr2:/dsk/4/dsk3/tool/share 35194552 7856256 25550496 24% /net/appl/tool-share
بنابراین، به طور واقعی چه کار میتوانید بکنید؟
گزینه -P را به کار ببرید. حتی اگر همه چیز را 100% سازگار نمیکند، به طور کلی آزاری ندارد. مطابق کُد منبع df.c در coreutils لینوکس، گزینه -P تضمین میکند که خروجی در یک سطر منفرد خواهد بود(اما این فقط برای لینوکس است).
منطقه خود را به C تنظیم کنید. شما نیازی به سرآیند ستونهای غیر انگلیسی درهم پیچیده ندارید.
اگر معتبر است، استفاده از "stat --file-system --format=" را در نظر بگیرید. اگر در موقعیت شما قابلیت حمل مسئلهای نیست، صفحه man فرمان stat را بررسی کنید. در سیستمهای بسیاری قادر خواهید بود اندازه بلوک، تعداد کل بلوکهای دیسک، وتعداد بلوکهای آزاد، همگی در قالب تعیین شده کاربر، را چاپ کنید.
به طور صریح یک فایلسیستم را انتخاب نمایید. اگر نتایج مربوط به یک فایلسیستم را میخواهید از چنین دستوری df -P | grep /dev/hda2 استفاده نکنید. نام یک شاخه یا یک دستگاه را به عنوان یک شناسه به فرمان df بدهید به این طریق فقط خروجی آن فایلسیستم را در مکان اول میبینید.
~$ df -P / Filesystem 1024-blocks Used Available Capacity Mounted on /dev/sda2 8230432 3894360 3917984 50% /
شمارش کلمات خروجی بدون رعایت سطرهایجدید. این یک راه غلبه بر مشکل سطرهایی است که به طور غیرقابل پیشبینی تقسیم میشوند. برای مثال، استفاده از آرایه Bash با نام df_arr:
~$ read -d '' -ra df_arr < <(LC_ALL=C df -P /); echo "${df_arr[11]}" 50%
به طوری که میتوانید ببینید، ما به سادگی تمامی خروجی را به داخل یک آرایه منفرد مکیدیم و سپس کلمه دوازدهم را گرفتیم(شمارش شاخص آرایه از صفر است). نگران آن نبودیم که آیا خروجی تقسیم شده یا خیر، به علت آنکه تعداد کلمات تغییر نمیکند.
حذف علامت درصد، مقایسه عدد با مرز تعیین شده، زمانبندی یک روش خودکار برای اجرای اسکریپت، و غیره. به عنوان تمرینهای شما واگذار گردید.
پرسش و پاسخ 94 (آخرین ویرایش 2013-08-10 20:27:02 توسط nrbg-4dbfc8a9)