آموزش‌های خط فرمانی

این وبلاگ تلاش می‌کند گامی در حد بضاعت در جهت آموزش خط فرمان و اسکریپت‌نویسی پوسته گنو-لینوکس بردارد.

آموزش‌های خط فرمانی

این وبلاگ تلاش می‌کند گامی در حد بضاعت در جهت آموزش خط فرمان و اسکریپت‌نویسی پوسته گنو-لینوکس بردارد.

پرسش و پاسخ شماره ۱۵



چگونه می‌توانم یک دستور را با تمام فایل‌های دارای پسوند ‎ .gz‎ اجرا کنم؟

غالباً یک فرمان تعدادی فایل را به عنوان شناسه می‌پذیرد، به عنوان مثال:

    zcat -- *.gz

در برخی سیستم‌ها، به جای zcat باید از gzcat استفاده کنید. اگر هیچ یک در دسترس نیستند، یا اگر علاقمند به انجام بازیهای حدسی نمی‌باشید، فقط از ‎ gzip -dc‎ به جای آن استفاده کنید.

کاربرد -- از ایجاد نتایج غیر منتظره ناشی از نام فایلهایی که با علامت خط تیره آغاز می‌شوند، ممانعت می‌کند.

اگر یک حلقه آشکار می‌خواهید یا اگر فرمان شما نمی‌تواند شناسه‌های چندتایی را در یک فراخوانی قبول کند، حلقه for می‌تواند به کار برود:

    # Bourne
    for file in ./*.gz
    do
        echo "$file"
        # "$file" انجام کاری با
    done

برای انجام آن به طور بازگشتی، از find استفاده کنید:

    # Bourne
    find . -name '*.gz' -type f -exec do-something {} \;

اگر به دلایلی لازم است فایلها داخل پوسته پردازش بشوند، پس نتایج find را در حلقه‌ای بخوانید:

    # Bash
    while IFS= read -r file; do
        echo "Now processing $file"
        #  "$file" انجام کار مورد علاقه با
    done < <(find . -name '*.gz' -print)

این مثال از جایگزینی پردازش استفاده می‌کند(همچنین پرسش و پاسخ 24 را ببینید) هرچند لوله نیز در بسیاری از وضعیت‌ها می‌تواند مناسب باشد. به هرحال، نام فایلهایی که شامل سطرجدید می‌باشند را به طور صحیح مدیریت نمی‌کند. برای مدیریت نام‌فایلهای دلبخواهی، پرسش و پاسخ 20 را ببینید.


CategoryShell

پرسش و پاسخ 15 (آخرین ویرایش ‎ 2010-07-30 14:32:06 ‎ توسط GreyCat)


پرسش و پاسخ شماره ۱۴



چطور می‌توانم چند دستور را در یک مرحله تغییر مسیر بدهم؟

تغییر مسیر خروجی استاندارد یک فرمان منفرد به همین آسانی است:

    date > file

برای تغییر مسیر خروجی استاندارد خطا:

    date 2> file

برای تغییر مسیر هردو:

    date > file 2>&1

یا، روش تفننی‌تر:

    #  اما غیرقابل حمل  date > file 2>&1 معادل با ,Bash فقط در 
    date &> file

تغییر مسیر کل یک حلقه:

    for i in $list; do
        echo "Now processing $i"
        # more stuff here...
    done > file 2>&1

به هرحال، اگر باید خروجی فرمانهای بسیاری تغییر مسیر داده شود، این روش می‌تواند کسل کننده گردد. اگر تمام خروجی یک اسکریپت باید به یک فایل(به عنوان مثال فایل log بروند)، فرمان exec می‌تواند به کار برود:

    # "log.txt"   تغییر مسیر هردو خروجی استاندارد وخطا به فایل
    exec > log.txt 2>&1
    # می‌روند "log.txt" تمام خروجی از جمله خطای استاندارد اکنون به فایل

در غیر آن صورت، گروه‌بندی فرمانها، کمک می‌کند:

    {
        date
        # some other commands
        echo done
    } > messages.log 2>&1

در این مثال، خروجی تمام فرمانهای درون ابروها به فایل messages.log تغییر مسیر داده می‌شود.

مباحثه بیشتر

آموزش تشریحی ژرفکاوانه


CategoryShell

پرسش و پاسخ 14 (آخرین ویرایش ‎ 2010-07-01 13:04:42 ‎ توسط GreyCat)


پرسش و پاسخ شماره ۱۳



چگونه می‌توانم دو متغیر را به هم الحاق کنم؟ چگونه یک رشته را در یک متغیر اضافه (پیوست) کنم؟

در شل، عملگری(صریح) برای الحاق نمودن رشته‌ها (لفظی یا بدون ارجاع به متغیر) وجود ندارد، فقط می‌توانید آنها را در مجاورت هم بنویسید:

    var=$var1$var2

اگر طرف راست شامل کاراکترهای فضای سفید باشد، لازم است که نقل‌قولی بشود:

    var="$var1 - $var2"

اگر شما رشته‌ای الحاق می‌کنید که به قسمتی از نام متغیر شباهتی ندارد، تنها تمام آنها را در کنار یکدیگر قرار بدهید:

    var=$var1/.-

در غیر این صورت، ابروها یا نقل‌قولها می‌توانند برای رفع ابهام طرف راست به کار بروند:

    var=${var1}xyzzy
    #   به عنوان نام متغیر تفسیر خواهد شد var1xyzzy بدون ابروها

    var="$var1"xyzzy
    # ترکیب دستوری جایگزین

جایگزینی فرمان به خوبی می‌تواند به کار برود. سطر زیر یک فایل ثبت وقایع logname متشکل ازتاریخ جاری ایجاد می‌کند، که منجر به نامهایی به عنوان مثال مانند log.2004-07-26 می‌شود:

    logname="log.$(date +%Y-%m-%d)"

تفاوتی میان استفاده مجدد نام یک متغیر یا تخصیص مجدد مقدار(رشته‌ای که نگاه می‌دارد) دلخواه به آن، وجود ندارد:

    string="$string more data here"

Bash (از) نگارش 3.1 عملگر جدید ‎ +=‎ را دارد که ممکن است گاه گاهی ببینید:

    string+=" more data here"     # !بینهایت غیرقابل حمل

به طور معمول بهترین کار استفاده از ترکیب دستوری قابل حمل است.


CategoryShell

پرسش و پاسخ 13 (آخرین ویرایش ‎2009-12-30 08:27:15‎ توسط MatthiasPopp)


پرسش و پاسخ شماره ۱۲



به چه طریق می‌توانم یک فرمان شل را از یک برنامه غیرپوسته‌ای فراخوانی نمایم؟

می‌توانید از گزینه ‎ -c‎ پوسته برای اجرای شل جهت اجرای تکه کوتاهی از اسکریپت استفاده کنید:

sh -c 'echo "Hi!  This is a short script."'

این کار بدون وسیله‌ای برای عبور دادن داده‌ها به آن، روش قشنگ معمولاً بلااستفاده‌ای است. بهترین راه برای عبور دادن خُرده‌ای از داده‌ها به پوسته شما، ارائه آنها به عنوان پارامترهای مکانی است:

sh -c 'echo "Hi! This short script was run with the arguments: $@"' -- "foo" "bar"

به -- قبل از پارامترهای مکانی واقعی، توجه کنید. اولین شناسه‌ای که به پردازش شل می‌دهید(که شناسه‌ای برای گزینه ‎ -c‎ نیست) در متغیر‎ $0‎ قرار داده می‌شود. پارامترهای مکانی از ‎ $1‎ شروع می‌شوند، بنابراین ما یک placeholder کوچک در ‎$0‎ قرار می‌دهیم. این هر چیزی که شما مایل باشید می‌تواند باشد، در مثال، ما -- عمومی را به کار برده‌ایم.

این شیوه غالباً در اسکریپت‌نویسی پوسته، موقعی به کار می‌رود که می‌خواهید یک برنامه خط‌فرمانی غیر پوسته‌ای برخی کُدهای bash را اجرا کند، مثلاً با ‎find(1)‎:

find /foo -name '*.bar' -exec bash -c 'mv "$1" "${1%.bar}.jpg"' -- {} \;

در اینجا از find درخواست می‌کنیم فرمان bash را برای هر فایل ‎ *.bar‎ که پیدا می‌کند، به عنوان اولین پارامتر مکانی پردازش bash اجرا نماید. پردازش bash پس از انجام بسط پارامتر روی پارامتر مکانی اول، دستور mv را به منظور تغییر نام فایلهای با پسوند bar به فایلهای با پسوند jpg اجرا می‌کند.

به طور جایگزین، اگر برنامه غیرپوسته‌ای شما امکان تنظیم متغیرهای محیط را برای شما فراهم می‌کند، می‌توانید این کار را انجام بدهید و سپس با استفاده از متغیرهای معمولی همان نام آنها را بخوانید.

به طور مشابه، فرض کنید برنامه‌ای(مثلاً مدیریت فایل) به شما اجازه می‌دهد یک فرمان خارجی تعریف کنید که یک شناسه به آن ضمیمه خواهد شد، اما شما آن شناسه را جایی در وسط لازم دارید. در آن حالت:

#!/bin/sh
sh -c 'command foo "$1" bar' -- "$@"


CategoryShell

پرسش و پاسخ 12 (آخرین ویرایش ‎ 2011-04-12 20:01:42 ‎ توسط Lhunath)


پرسش و پاسخ شماره ۱۱



چگونه می‌توانم سطر شماره n از یک فایل را چاپ کنم؟

یک روش زمخت(بلکه غیر سریع)این است:

    sed -n ${n}p "$file"

اما حتی اگر فقط سطر سوم را خواسته باشید، این تمام فایل را می‌خواند، که برای اجتناب از آن می‌توان، جهت چاپ سطر ‎ $n‎ ازفرمان "p" استفاده کنیم و به دنبال آن "q" را برای خروج از اسکریپت به کار ببریم:

    sed -n "$n{p;q;}" "$file"

یک شیوه دیگر، ربودن آخرین سطر از یک لیست n سطری است:

   head -n $n $file | tail -n 1

راهکار دیگر، به کار بردن AWK است:

   awk "NR==$n{print;exit}" file

اگر بیش از یک سطر لازم باشد، وفق دادن هر یک از روشهای قبل آسان است:

   x=3 y=4
   sed -n "$x,${y}p;${y}q;" "$file"
                             #   چاپ می‌کند و خارج می‌شود $y تا$x سطرهای 
   head -n $y "$file" | tail -n $((y - x + 1))             #   همانطور‎
   head -n $y "$file" | tail -n +$x     # پشتیبانی کند tail اگر برنامه 
   awk "NR>=$x{print} NR==$y{exit}" "$file"            #  به همان طریق

در Bash نگارش 4، با استفاده از دستور داخلی mapfile یک راهکار فشرده مختص-bashمی‌تواند حاصل شود. با همراه کردن شناسه با گزینه ‎ -n ‎ این فرمان، بیش از یک سطر می‌تواند در آرایه MAPFILE خوانده شود:

   mapfile -ts $((n-1)) -n 1 < "$file"
   echo "${MAPFILE[0]}"

همچنین mapfile می‌تواند به طور مشابهی با head به کار برود، در صورتیکه از مسائل میانگیری لوله بودن ورودی اجتناب می‌شود:

   { mapfile -n $n; head -n 1; } <"$file"

See Also


CategoryShell

پرسش و پاسخ 11 (آخرین ویرایش ‎ 2012-02-27 02:27:07 ‎ توسط ormaaj)