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

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

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

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

مشکل در اعلان فرمان رنگی


من یک اعلان فرمان تفننی رنگی دارم، اما حالا به نظر نمی‌رسد bash بداند پهنای ترمینال من چقدر است. سطرها به طور نادرستی شکسته می‌شوند.

شما باید ‎\[‎ و ‎\]‎ را در اطراف هر یک از رشته‌های escape غیرقابل چاپ در اعلان خود قرار بدهید. از این قرار:

fancy_prompt() {
  local blue=$(tput setaf 4)
  local purple=$(tput setaf 5)
  local reset=$(tput sgr0)
  PS1="\[$blue\]\h:\[$purple\]\w\[$reset\]\\$ "
}

بدون ‎\[ \]‎‏، bash گمان خواهد کرد بایت هایی که رشته‌های escape برای کُدهای رنگ را تشکیل می‌دهند به طور واقعی فضایی را در نمایشگر اشغال خواهند نمود، بنابراین bash قادر نخواهد بود بداند که اشاره‌گر واقعاً کجا می‌باشد.

اگر شما بازهم مشکل دارید، به عنوان مثال، موقعی که تاریخچه فرمانها را با کلیدهای جهتی بالا و پایین مرور می‌کنید، اطمینان حاصل نمایید که گزینه checkwinsize تنظیم باشد:

shopt -s checkwinsize

به فصلANSI escape codes ویکی پدیا مراجعه نمایید.

به طور کلی‌تر، شما باید از نوشتن رشته‌های escape ترمینال به طور مستقیم در اعلان خود اجتناب نمایید، زیرا آنها لزوماً در میان تمام ترمینال‌هایی که اکنون یا در آینده استفاده خواهید نمود قابل حمل نیستند. از tput برای تولید رشته‌های صحیح برای ترمینال خود استفاده کنید( این برنامه به بانک اطلاعاتی terminfo یا termcap شما نگاه می‌کند).

چون tput یک فرمان خارجی است، هر چند مرتبه که لازم باشد، شما باید آن را اجرا کنید، به این علت پیشنهاد می‌کنیم نتایج آن را در متغیرها ذخیره کنید، و (به جای استفاده از‎ $(tput ...)‎ به طور مستقیم در PS1، که در هر نوبتی که اعلان نمایش داده می‌شود tput را اجرا می‌کند)، آنها را در ساختار اعلان به کار ببرید. به این ترتیب کُد تشکیل دهنده اعلان برای خواندن آسانتر از خود اعلان می‌باشد، و درطیف متنوعی از ترمینال‌ها کار می‌کند. (بعضی ترمینال‌ها شاید ویژگی‌هایی که سعی می‌کنید به کار ببرید را نداشته باشند ، از قبیل رنگها، بنابراین نتایج در وضعیت‌های پیچیده به اندازه ‎ 100%‎ قابل حمل نیستند. اما می‌توانید نزدیک شوید.)


  • یادداشت شخصی: بازهم من این جواب را ترجیح می‌دهم:

    BLUE=$(tput setaf 4)
    PURPLE=$(tput setaf 5)
    RESET=$(tput sgr0)
    PS1='\[$BLUE\]\h:\[$PURPLE\]\w\[$RESET\]\$ '

    من درک می‌کنم که اشخاص می‌خواهند از مخدوش شدن متغیر namespace زیرنویس 1 اجتناب کنند، بنابراین از تابع و بخش local استفاده می‌کنند، که به ترتیب استفاده از نقل‌قول دوگانه و نیاز به دوتایی نمودن بعضی از \ها نه تمام آنها راتحمیل می‌کنند (و دانستن این که کدام یک -- اوه!). من پیچیدگی غیر ضروری آن را تشخیص می‌دهم. مسلماً، در صورتی‌که توسط کسی یا در جایی BLUE رونویسی شود، ریسک ناچیزی از تصادم وجود دارد، اما از طرف دیگر، راه حل نقل‌قول دوگانه نیز حامل این ریسک است که ترمینال دارای کاراکترهای \ در رشته‌های escape خود می‌باشد. و چون محتویات رشته‌های escape در نقل‌قولهای دوگانه تجزیه می‌شوند، اما در روش نقل‌قول منفرد تجزیه نمی‌شوند، چنین ترمینالی می‌تواند موارد بسیاری را آشفته کند. مثال تفاوت:

     imadev:~$ FOO='\w'; PS1='$FOO\$ '
     \w$ FOO='\w'; PS1="$FOO\\$ "
     ~$ 

    فرض کنیم ترمینال ما از ‎ \w‎ در یک رشته escape استفاده می‌کند. یک ‎\w‎ داخل متغیری که در PS1 نقل‌قولی شده منفرد رجوع می‌شود، وقتی اعلان چاپ گردد فقط به ‎ \w‎ لفظی بسط داده می‌شود، که آنچه ما می‌خواهیم است. اما در نگارش نقل‌فول دوگانه ، ‎\w‎ که به طور مستقیم داخل متغیر PS1 گمارده شده، موقع چاپ اعلان، توسط bash ارزیابی می‌شود. حال، من واقعاً ترمینالی را که از چنین نشانه‌ای استفاده ‌کند نمی‌شناسم --این یک ایراد کاملاً نظری است. اما از طرف دیگر، ایراد وارده به استفاده از متغیرهایی مانند BLUE نیز همینطور است. و به هر حال برخی اشخاص شاید واقعاً بخواهند در پوسته‌هایشان از ‎ echo "$BLUE"‎ استفاده کنند. بنابراین من نمی‌خواهم بگویم پاسخ نقل‌قول منفرد بهتر است، بلکه دوست داشتم ببینم که به عنوان یک جایگزین در اینجا حفظ می‌شود. -- GreyCat

    • کاملاً صحیح. من در ابتدا قصد داشتم فقط‎ BLACK= ‎ را به ‎RESET= ‎  تغییر بدهم(چون همه از سفید روی سیاه استفاده نمی‌کنند)، اما بعد اندیشیدم اگر اعلان به متغیرهایی که متغیر هستند وابسته نباشد، بهتر خواهد شد. من به طور واضح در مورد احتمال چنین رشته‌های escape ترمینال آگاه نبودم، بنابراین فکر می‌کنم ذکر کردن نگارش اول نقل‌قول منفرد، می‌توانست ایده بهتری باشد و همچنین یادآوری آنکه اگر آن متغیرها تغییر کنند چه اتفاقی می‌افتد.

      من گمان می‌کنم شخص می‌توانست برای پیش‌گیری از تغییر تصادفی متغیرها و ضایع شدن اعلان فرمان، آنها را فقط خواندنی نیز بنماید، اگر چه احتمالاً آن نیز اشکالات دیگری خواهد داشت..؟ -- ~~~


پرسش و پاسخ 53 (آخرین ویرایش ‎ 2012-03-27 20:46:02 ‎ توسط GreyCat)


  1. مترجم: namespace مجموعه‌ای از شناسه‌های احتمالی برای یک مقصود است. تمام نامهایی که در یک namespace قرار می‌گیرند منحصر به فرد می‌باشند و چند قاعده تعیین می‌کنند که آیا نام احتمالی می‌تواند عضوی از آن namespace باشد، به عنوان نمونه آدرس پست الکترونیکی ساختار معینی دارد که شناخته شده است و با عناصری که فاقد آن ساختار باشند تداخل نمی‌کند.
    در اینجا تداخل کلمات به کار رفته برای رنگها با نام متغیرها، مورد نظر GreyCat است. (1)


تبدیل قالب DOS به قالب UNIX


چطور می‌توانم یک فایل را از قالب DOS به قالب UNIX تبدیل کنم( CRها را از CR-LF خاتمه دهنده سطرها حذف کنم)؟

در برخی سیستم‌ها برای علامت زدن انتهای سطر، کاراکترهای رفتن سر سطر‎(CR)‎به کار می‌روند. سه نوع مختلف انتهای سطر رایج است:

  • سیستم‌های یونیکس فقط از تعویض سطر(LF)ها استفاده می‌کنند.
  • سیستم‌های MS-DOS و Windows از یک جفت CR-LF استفاده می‌کنند.
  • سیستم‌های قدیمی Macintosh فقط از CRها استفاده می‌کنند.

اگر شما در حال اجرای اسکریپتی در سیستم یونیکس می‌باشید، لازم است انتهای سطرها یونیکسی باشد(فقط LFها)، در غیر آنصورت مشکل خواهید داشت.

بررسی نوع خاتمه‌دهنده سطر

یک بازرسی ساده، فقط نگاه کردن به خروجی ‎cat -e‎ است:

cat -e yourscript

اگر چیزی مانند این را می‌بینید، آنوقت با سطرهای جدید سَبکِ CRLF سر و کار دارید:

command^M$
^M$
another command^M$

یک شیوه دیگر، استفاده از برنامه سودمند file برای پی بردن به نوع فایل است:

file yourscript

اگر فایل دارای CR باشد خروجی به شما می‌گوید که متن ASCII داری CR می‌باشد. توجه: این روش فقط در گنو-لینوکس صادق است. در سایر سیستم‌عامل‌ها، نتیجه file غیرقابل پیش‌بینی است، به استثنای آنکه اگر نوع فایل مانند فایل متن باشد کلمه "text" در جایی از نتیجه خروجی ظاهر می‌شود.

imadev:~$ printf 'DOS\r\nline endings\r\n' > foo
imadev:~$ file foo
foo:            commands text
arc3:~$ file foo
foo: ASCII text, with CRLF line terminators

در یک اسکریپت، گفتن آنکه کدام شیوه، قابل اعتمادترین روش خواهد بود، مشکل‌تر است. هر کدام که انجام بدهید، غیر مستدل خواهد بود. در تئوری، یک فایل غیر معیوب تولید شده توسط برنامه سودمند یونیکسی به سامان، تنها باید شامل LFها، و تولید شده توسط یک برنامه DOS، نباید شامل LF های ساده بدون یک CR مقدم، باشد. می‌توانید این مورد را با یک PCRE بررسی کنید.

# Bash و Ksh در پوسته‎

# [[ $(</dev/fd/0) == ~(P)(?<!$'\r')$'\n' ]] # ksh93 PCRE
pattern=*[^$'\r']$'\n'*
if [[ $(</dev/fd/0) == $pattern ]] <<<$'foo\r\nbar\r\nbaz\r'; then
    print 'File contains only CRLFs'
else
    print 'File contains at least one newline not preceded by a CR'
fi

تبدیل فایلها

ex یک روش استاندارد مناسب برای تبدیل CRLF به LF می‌باشد، و احتمالاً یکی از چند روش قابل اعتماد انجام آن به طور یکجا از داخل یک اسکریپت است:

ex -sc $'%s/\r$//e|x' file

البته، هر یک از زبانهای پویای قدرتمندتر برای انجام این کار با سهولت نسبی.

perl -pi -e 's/\r\n/\n/' filename

برخی سیستم‌ها دارای ابزارهای معتبر ویژه تبدیل، جهت انجام این کار به طور خودکار، هستند. dos2unix، recode، و fromdos برخی نمونه‌ها می‌باشند.

به طور دستی با ویرایشگری مانند nano انجام می‌شود:

nano -w yourscript

‎Ctrl-O‎ را تایپ کنید و قبل از تأیید، ‎Alt-D (DOS)‎ یا ‎Alt-M (Mac)‎ را برای تغییر قالب تایپ نمایید.

یا در Vim از ‎:set fileformat=unix‎ استفاده کنید و با ‎:w‎ ذخیره کنید. مراقبت کنید که مقدار fenc صحیح باشد (احتمالاً ‎utf-‎8).

برای آنکه به سادگی تمام CRها را از جریان ورودی پاک کنید، می‌توانید از ‎tr -d '\r' <infile >outfile‎ استفاده نمایید. البته، شما باید مطمئن باشید که نام این فایلها یکسان نباشد.

پرسش و پاسخ 52 (آخرین ویرایش ‎2013-02-10 15:48:58‎ توسط ormaaj)


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


من جستجوی تاریخچه درست مانند آن در tcsh می‌خواهم. چطور می‌توانم آن را به کلیدهای up و down مربوط کنم؟

فقط سطرهای زیر را در فایل ‎/etc/inputrc‎ یا فایل‎ ~/.inputrc‎ خود اضافه کنید:

"\e[A":history-search-backward
"\e[B":history-search-forward

سپس bash را مجدداً راه‌اندازی کنید( یا logout نموده ودوباره وارد شوید، یا با اجرای‎ exec bash‎).

readline(قسمتی از bash که ورودی ترمینال را اداره می‌کند) نام کلیدها ازقبیل up arrow را نمی‌شناسد. به جای آن شما باید به طور دستی آن رشته escape که کلید مورد نظر  به ترمینال بخصوص شما ارسال می‌کند را تشحیص بدهید(به طور معمول با فشردن ‎ Ctrl-V‎ و سپس کلید مورد پرسش)، و آنرا درفایل ‎ .inputrc‎ درج کنید، به طوری که در فوق نشان داده شد. ‎\e‎ رشته کاراکتر Escape در readline را معنی می‌دهد. ترفند ‎ Ctrl-V ‎   کاراکتر Escape را به صورت ‎ ^[‎ نشان می‌دهد. شما باید تشخیص بدهید که آن ‎ ^[‎ مقدم، یک کاراکتر Escape است، و خودتان جایگزینی را انجام بدهید.


CategoryShell

پرسش و پاسخ 51 (آخرین ویرایش ‎ 2008-11-22 21:53:31 ‎ توسط GreyCat)


قرار دادن فرمان در متغیر


من سعی دارم دستوری را در یک متغیر قرار بدهم، اما موارد پیچیده همیشه ناموفق است!

برخی اشخاص کوشش می‌کنند مواردی مشابه این کد را انجام بدهند:

    # مثالی که کار نمی‌کند
    args="-s 'The subject' $address"
    mail $args < $body

این کُد به دلیل تفکیک کلمه و به علت آنکه نقل‌قول‌های منفرد داخل متغیر لفظی هستند نه گرامری، شکست می‌خورد. وقتی که ‎$args‎ بسط داده می‌شود، چهار کلمه می‌شود. ‎ 'The‎ دومین کلمه، و ‎ subject'‎ سومین کلمه است.

برای بدست آوردن یک درک بهتر از آنکه شل چگونه تعیین می‌کند کدام شناسه‌ها در دستور شما هستند، بخش شناسه ها را بخوانید.

بنابراین، چطور این کار را انجام بدهیم؟ تمام آن بستگی به این دارد که چه کاری است!

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

من تلاش می‌کنم فرمانی را ذخیره کنم به طوری که بعداً بدون تکرار آن در هر نوبت، آن را اجرا کنم

اگر شما می‌خواهید فرمانی را برای استفاده بعدی آن در ظرفی قرار بدهید، تابع را به کار ببرید. متغیرها داده را نگاه می‌دارند، توابع کُدها را نگاه می‌دارند.

    pingMe() {
        ping -q -c1 "$HOSTNAME"
    }

    [...]
    if pingMe; then ..

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

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

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

    # این را انجام ندهید
    args=$recipient
    if [[ $subject ]]; then
        args+=" -s $subject"
    fi
    mail $args < $bodyfilename

به طوری که دیده‌ایم، این رویکرد وقتیکه subject شامل فضای سفید باشد ناموفق است. واقعاً به اندازه کافی قوی نیست.

همین‌طور، اگر شما به راستی نیاز دارید یک فرمان به طور پویا(متغیر نسبت به زمان) ایجاد کنید، هر شناسه را در یک عضو جداگانه آرایه قرار بدهید، این چنین:

    # یا بالاتر bash 3.1 مثال کارگر در
    args=("$recipient")
    if [[ $subject ]]; then
        args+=(-s "$subject")
    fi
    mail "${args[@]}" < "$bodyfilename"

(برای جزئیات بیشتر در مورد ترکیب دستوری آرایه پرسش و پاسخ شماره 5 را ببینید.)

اغلب، این پرسش موقعی می‌رسد که شخصی در حال تلاش برای استفاده از dialog برای ساختن یک منوی متحرک می‌باشد. فرمان dialog نمی‌تواند hard-coded زیرنویس 1 بشود، به دلیل آنکه پارامترهایش بر اساس داده‌هایی که تنها در زمان اجرا در دسترس هستند، فراهم می‌شود(به عنوان مثال تعداد اقلام منو). برای یک مثال از چگونگی انجام این کار به طور صحیح، پرسش و پاسخ شماره 40 را ببینید.

می‌خواهم یک وظیفه را عمومی کنم در حالتی که ابزار سطح پایین بعداً تغییر می‌کند

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

در مثال mail، ما در ترکیب دستوری فرمان mail یونیکس، وابستگی hard-coded فراهم نموده‌ایم -- و مخصوصاً نگارشهایی از فرمان mail که اجازه می‌دهند موضوع بعد از گیرنده تعیین بشود، که شاید همیشه این حالت نباشد. شخص نگهدارنده اسکریپت ممکن است تصمیم بگیرد ترکیب دستوری را به طوری اصلاح نماید که گیرنده آخر ظاهر شود، که صحیح‌ترین شکل است، یا ممکن است آنها به سبب تغییرات سیستم پستی داخلی شرکت، به طور کلی mail را تعویض کنند، و مواردی از این قبیل. داشتن چندین فراخوانی mail پراکنده در سرتاسر اسکریپت در این موقعیت وضع را پیچیده می‌کند.

کاری که احتمالاً باید انجام دهید، این است:

    #  POSIX

    #  ارسال ایمیل به کسی‎
    #  بدنه نامه را از ورودی استاندارد می‌خواند‎
    #
    #  sendto address [subject]

    #
    sendto() {
	# unset -v IFS
        # mail ${2:+-s "$2"} "$1"
        MailTool ${2:+--subject="$2"} --recipient="$1"
    }

    sendto "$address" "The Subject" <"$bodyfile"

اینجا، بسط پارامتر کنترل می‌کند ‎$2‎ (موضوع اختیاری) به چیزی بسط یافته است. اگر اینطور باشد، بسط ‎ -s "$2"‎ را به فرمان mail اضافه می‌کند. اگر نه، به هیچ وجه بسط، گزینه ‎ -s‎ را اضافه نمی‌کند.

پیاده‌سازی اصلی اسکریپت، فرمان استاندارد یونیکس،‎ mail(1)‎ را به کار می‌برد. بعداً اسکریپت توضیح‌گذاری شد و با چیزی به نام MailTool که به طور فی‌البداهه مخصوص این مثال ساخته شده بود، تعویض گردید. اما به روشن ساختن این مفهوم خدمت می‌کرد که: حتی اگر ابزار پشتیبان تغییر نماید، فراخوانی تابع تغییر نمی‌کند. همچنین توجه نمایید که، مثال ‎mail(1)‎ فوق، برای جداکردن گزینه شناسه از بسط پارامتر نقل‌قولی شده داخلی به تفکیک کلمه استناد می‌کند. این یک استثنای قابل توجه است که در آن تفکیک کلمه قابل قبول و مطلوب است. این مورد بی خطر است زیرا گزینه کُد شده به طور ایستا، شامل هیچ کاراکتر glob نمی‌باشد، و بسط پارامتر برای ممانعت از globbing بعدی نقل‌قولی می‌شود. شما باید مطمئن شوید که IFS به منظور به دست آوردن نتایج مورد انتظار، به یک مقدار معقول تنظیم گردیده است.

من یک ثبت وقایع از عملیات اسکریپت خود می‌خواهم

دلیل دیگری که مردم سعی می‌کنند فرمانها را در متغیرها قرار بدهند این است که آنها می‌خواهند اسکریپت‌هایشان هر فرمان را قبل از اجرای آن چاپ کند. اگر تمام آنچه شما می‌خواهید این است، پس به سادگی از دستور ‎set -x‎ استفاده کنید، یا اسکریپت خود را با ‎ #!/bin/bash -x‎ یا ‎bash -x ./myscript‎ احضار کنید. توجه کنید که می‌توانید این حالت را با استفاده از ‎ set +x‎ و ‎set -x‎ خاموش و روشن کنید.

شایان توجه است که نمی‌توانید یک خط لوله دستور را داخل یک متغیر آرایه‌ای قرار بدهید و بعد با استفاده از تکنیک‎ "${array[@]}"‎ آن را اجرا کنید. تنها راه ذخیره یک خط لوله در یک متغیر، اضافه نمودن(با احتیاط!) لایه‌ای از نقل‌قولها در صورت لزوم ، ذخیره در یک متغیر رشته‌ای، و سپس استفاده از eval یا sh برای اجرای متغیر می‌باشد. این به دلایل امنیتی پیشنهاد نمی‌شود. همان مورد با فرمانهای در بر گیرنده تغییر مسیر، جملات if یا while، وغیره فراهم می‌گردد.

بعضی اشخاص دچار دردسر می‌شوند به علت آنکه می‌خواهند اسکریپتی داشته باشند که دستوراتشان از جمله تغییر مسیرها را قبل از اجرای آنها چاپ کند. ‎set -x‎ دستور را بدون تغییرمسیرها نمایش می‌دهد. اشخاص سعی می‌کنند با انجام موردی مانند کُد زیر آن را رفع و رجوع کنند:

    # مثالی که عمل نمی‌کند
    command="mysql -u me -p somedbname < file"
    ((DEBUG)) && echo "$command"
    "$command"

(این به قدری رایج است که من به طور صریح آن را قرار می‌دهم، ولواینکه گمان می‌کنم تکرار مطلبی است که قبلاً نوشتم.)

یکبار دیگر، این کار نمی‌کند. حتی یک آرایه در اینجا کار نمی‌کند. تنها موردی که در اینجا عمل می‌کند پوشش دادن فرمان با دقت زیاد برای مطمئن شدن از آنکه فوق کاراکترها باعث مشکلات خطیر امنیتی نخواهند شد، و سپس استفاده از eval یا sh برای خواندن مجدد دستور است. لطفاً این کار را انجام ندهید! یک روش برای ثبت وقایع کامل فرمان بدون متوسل شدن به استفاده از eval یا sh، استفاده از ‎DEBUG trap‎ می‌باشد. یک نمونه کد عملی:

   trap 'printf %s\\n "$BASH_COMMAND" >&2' DEBUG 

با فرض اینکه شما در حال ثبت کردن خطای استاندارد می‌باشید.

توجه کنید که نمایندگی تغییر مسیر، به وسیله ‎BASH_COMMAND‎ باز هم تحت تأثیر این باگ قرار می‌گیرد. به نظر می‌رسد تا اندازه‌ای در git تعمیر شده، اما کامل نیست. انتظار نداشته باشید صحیح باشد.

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

    # مثال کارگر
    echo "mysql -u me -p somedbname < file"
    mysql -u me -p somedbname < file

به هیچ وجه متغیر استفاده نکنید. دقیقاً فرمان را کپی و paste کنید، یک لایه نقل‌قول اضافی در اطراف آن قرار بدهید(گاهی اوقات مهارت‌آمیز)، و یک echo پیش از آن ضمیمه کنید.

پیشنهاد شخصی من دقیقاً استفاده از ‎ set -x‎ و دلواپس آن نبودن است.


CategoryShell

پرسش و پاسخ 50 (آخرین ویرایش ‎2013-04-13 18:52:30‎ توسط geirha)


  1. مترجم: hard-coded به رفتاری گفته می‌شود که داده ‌ها به طور مستقیم داخل برنامه و احتمالاً در چندین محل نوشته می‌شوند به طوری که به آسانی نمی‌توانند اصلاح شوند. (1)


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


چگونه می‌توانم به روزرسانی‌های دوره‌ای یا پیوست کردن‌ها به یک فایل راببینم؟(مثل: رشد فایل log )

tail -f‎ رشد یک فایل ثبت وقایع را به شما نشان می‌دهد. در بعضی سیستم‌ها(برای مثال OpenBSD)، این به طور خودکار تبدیل یک فایل لاگ به فایل جدیدی با همان نام را دنبال می‌کند(که به طور معمول همانست که شما می‌خواهید). برای به دست آوردن همین توانایی در سیستم‌های گنو، به جای آن از ‎ tail -F‎ استفاده کنید.

این فقط در صورتی مفید است که به روزرسانی‌های فایل پس از آخرین نوبتی که آنرا دیده‌اید، مورد نیازتان باشد.

# آغاز می‌شود n=1 با تنظیم 
   tail -n $n testfile; n="+$(( $(wc -l < testfile) + 1 ))"

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


CategoryShell

پرسش و پاسخ 49 (آخرین ویرایش ‎ 2010-06-25 20:17:30 ‎ توسط MatthiasPopp)