{این مقاله، نوشتهی نوح گیفت، مربوط به سال ۲۰۰۸ است، توضیحات بیشتر درباره این نویسنده، و پیوند به مقالهی اصلی را در پایان مقاله خواهید یافت}
اهل اسکریپ نویسی هستید؟ آیا در بَش (Bash) اسکریپت مینویسید؟ آیا میدانید یادگیری پایتون بسیار ساده است و نسبت به بَش قویتر میباشد؟
هر اسکریپتی که بیش از چند خط باشد، در پایتون بهتر است!
اکثر اوقات پایتون هم به اندازهی بش قابل حمل است. هر چه فکر میکنم نمیتوانم سیستم عاملی را با پسوند «نیکس» به یاد آورم که در آن پایتون به صورت پیشفرض وجود نداشته باشد. پایتون حتی در IRIX هم نصب است.
اگر میتوانید تابعی را در Bash بنویسید، یا حتی اگر در همین حد یاد گرفتهاید که چند دستور را در یک اسکریپت کنار هم بگذارید و آنها را قابل اجرا کنید، پس حتما پایتون هم میتوانید یاد بگیرید.
یکی از چیزهایی که اسکریپتنویسان بش گاها از آن دوری میکنند، دیدن قطعهای از برنامههای شیگرا مثل این است:
class FancyObjectOriented(object):
def __init__(self, stuff = "RegularStuff"):
self.stuff = stuff
def printStuff(self):
print "This method prints the %s object" % self.stuff
عادت کردن به برنامهنویسی شیگرا گاهی واقعا زمانبر است، اما خوشبختانه در پایتون این کار ۱۰۰٪ دلبخواه است.
لازم نیست حتما مدرک کامپیوتر داشته باشید تا بتوانید در پایتون بنویسید، با دانستن چند میانبر، میتوانید همین الآن شروع کنید.
هدف از این مقاله این است که به اسکریپتنویسان متوسط در بش، نشان دهد که چگونه میتوانند برخی از چیزهایی را که معمولا در بش مینویسند، در پایتون بنویسند.
با اینکه ممکن است غیرممکن به نظر برسد، تا پایان این مقاله میتوانید یک پایتون نویس مبتدی باشید!
چند قدم اول
اولین چیزی که در پایتون اهمیت دارد این است که فاصلهگذاریها مهم هستند. در نظر گرفتن این امر ممکن است برای بعضی از تازهواردها کمی مشکل باشد، ولی خیلی زود به آن عادت میکنند.
در ضمن خط اول اسکریپتی که به پایتون نوشته میشود، کمی تفاوت دارد.
خط اول (shebang line) در پایتون:
#!/usr/bin/env python
خط اول در بش:
#!/usr/bin/env bash
با دانستن این دو نکته، خیلی راحت نوشتن همان برنامهی مشهور Hello World را آغاز میکنیم. (البته در این برنامه هنوز به نکتهی فاصلهگذاری، احتیاجی نداریم)
ویرایشگر متن مورد علاقهی خود را باز کنید، و با اسکریپتهای پایتون و بش زیر را به ترتیب با نامهای hello.py و hello.sh ذخیره کنید.
اسکریپت Hello World در پایتون:
#!/usr/bin/env python print "Hello World"
اسکریپت Hello World در بش:
#!/usr/bin/env bash echo Hello World
حتما قبل از تلاش برای اجرا کردن، اسکریپتهای خود را با استفاده از دستورات chmod +x hello.py و chmod +x hello.sh قابل اجرا کنید.
حال اگر اسکریپتهایتان را با استفاده از دو دستور ./hello.py و ./hello.sh اجرا کنید، همان نتیجهی همیشگی، یعنی Hello World را مشاهده خواهید کرد.
چند قدم دوم: فراخواندن سیستم از پایتون
حالا که Hello World را از سر راه برداشتیم، بریم سراغ دستوری که کمی بدرد بخورتر باشد.
یک اسکریپت بش به طور معمول از مجموعهای از دستورات تشکیل شده که به گونهای به هم پیوند خوردهاند، یا فقط به ترتیب اجرا میشوند. از آنجایی که پایتون هم یک زبان پروسهای است، خیلی راحت میشود همان کارها را انجام داد. بیایید نگاهی به یک مثال ساده داشته باشیم.
برای برداشتن چندقدم دوم، به یاد داشتن دو چیز الزامیست:
- فاصلهگذاری اهمیت دارد. این را در ذهنتان فرو کنید. قول میدهم که لازم شود. آنقدر مهم است که میخواهم یکسره آن را به شما یادآوری کنم!
- برای فراخوانی سیستم در پایتون، باید ماژولی به نام subprocess را import (وارد) کرد.
فراخوانی ماژولها در پایتون بسیار ساده است، کافیست این عبارات را در بالای اسکریپت خود جای دهید تا ماژول وارد شود:
import subprocess
بیایید با استفاده از ماژول subprocess، یک کار خیلی ساده انجام دهیم. بیایید دستورls -l را در پوشهی کنونی اجرا کنیم.
#!/usr/bin/env python
import subprocess
subprocess.call("ls -l", shell=True)
اگر این اسکریپت را اجرا کنید، دقیقا همان کاری را خواهد کرد که ls -l در بش میکند.
مسلم است که نوشتن دو خط پایتون برای دستوری که با یک خط در بش اجرا میشود چندان هم بهینه نیست. ولی بیایید چند دستور پشت سر هم را همان طور که در بش مینویسیم در پایتون هم بنویسیم تا کمی بیشتر با قیافهی دستورات پشت سر هم در پایتون آشنا شوید. برای این کار باید شما را با دو مفهوم جدید آشنا کنم: یکی متغیرها، دیگری لیستها (که در بش به نام آرایه میشناسیم).
بایید یک اسکریپت خیلی ساده بنویسیم که وضعیت چند مورد مهم دربارهی سیستمعامل را به دست میآورد. همان طور که گفتیم میتوان مجموعهی بزرگی از دستورات بش را از طریق پایتون اجرا کرد، بنابراین لازم نیست همه چیز را به زبان پایتون بنویسیم (هر جا بلد نبودید، به همان زبان بش بنویسید). میتوانیم این کار را در چند مرحله انجام دهیم. مثلا میتوانیم دستورات بش را در یک متغیر ذخیره کنم.
توجه: جعبهی دستورات زیر، خودش شامل دکمههایی برای رونوشت برداری (کپی کردن) میشود، ولی اگر با روش دیگری رونویسی میکنید، یادتان نرود که فاصلهگذاریها مهم هستند!
مجموعه از دستورات سیستمی در پایتون:
#!/usr/bin/env python
import subprocess
#Note that Python is much more flexible with equal signs. There can be spaces around equal signs.
MESSAGES = "tail /var/log/messages"
SPACE = "df -h"
#Places variables into a list/array
cmds = [MESSAGES, SPACE]
#Iterates over list, running statements for each item in the list
#Note, that whitespace is absolutely critical and that a consistent indent must be maintained for the code to work properly
count=0
for cmd in cmds:
count+=1
print "Running Command Number %s" % count
subprocess.call(cmd, shell=True)
اجرای چند دستور پشت سر هم در بش:
#!/usr/bin/env bash
#Create Commands
SPACE=`df -h`
MESSAGES=`tail /var/log/messages`
#Assign to an array(list in Python)
cmds=("$MESSAGES" "$SPACE")
#iteration loop
count=0
for cmd in "${cmds[@]}"; do
count=$((count + 1))
printf "Running Command Number %s \n" $count
echo "$cmd"
done
پایتون درمورد نحوهی گذاشتن کوتیشنها («») و استفاده از متغیرها، خیلی بخشنده تر است. کد پایتون معمولا گسیختگی کمتری دارد.
چند قدم سوم: استفادهی دوباره از کدها با استفاده از توابع
تا اینجا یاد گرفتیم چگونه دستورات فراخوانی سیستم را در پایتون به کار گیریم تا دستورات به ترتیب اجرا شوند، دقیقا مثل یک اسکریپت بش معمولی.
بیایید کمی جلوتر برویم و بلوکههای کدمان را در توابع سازماندهی کنیم.
همان طور که قبلا گفتم، لزومی ندارد که حتما در پایتون از کلاسها و تکنیکهای برنامهنویسی شیگرا استفاده کنید، بنابراین حتی اگر فقط از توابع استفاده کنیم، قسمت بزرگی از قدرت برنامهنویسی پایتون را همچنان در دست داریم.
بیایید یک تابع ساده را هم در بش و هم در پایتون بنویسیم و هر دوی آنها را در یک اسکریپت فراخوانی کنیم.
توجه:
این دو اسکریپت در بش و پایتون نتایج یکسانی میدهند، با این وجود پایتون پارامترهای کلیدی پیشفرض را به صورت خودکار ساماندهی میکند ولی در بش، تنظیم پارامتر پیشفرض کار خیلی بیشتری میطلبد.
پایتون:
#!/usr/bin/env python
import subprocess
#Create variables out of shell commands
MESSAGES = "tail /var/log/messages"
SPACE = "df -h"
#Places variables into a list/array
cmds = [MESSAGES, SPACE]
#Create a function, that takes a list parameter
#Function uses default keyword parameter of cmds
def runCommands(commands=cmds):
#Iterates over list, running statements for each item in the list
count=0
for cmd in cmds:
count+=1
print "Running Command Number %s" % count
subprocess.call(cmd, shell=True)
#Function is called
runCommands()
بش:
#!/usr/bin/env bash
#Create variables out of shell commands
SPACE=`df -h`
MESSAGES=`tail /var/log/messages`
LS=`ls -l`
#Assign to an array(list in Python)
cmds=("$MESSAGES" "$SPACE")
function runCommands ()
{
count=0
for cmd in "${cmds[@]}"; do
count=$((count + 1))
printf "Running Command Number %s \n" $count
echo "$cmd"
done
}
#Run function
runCommands
چند قدم چهارم: ساخت ابزارهای خط فرمانی که قابل استفادهی دوباره باشند
حالا که یاد گرفتید اسکریپتهای بش ساده را به پایتون ترجمه کنید، بیایید به جای نوشتن اسکریپتهای ناکارامد، چیزی بنویسیم که واقعا به درد بخورد.
پایتون کتابخانههای استاندارد بسیار گستردهای دارد که به راحتی میتوان آنها را import کرد. در این مثال میخواهیم با استفاده از کتابخانهی استاندارد پایتون، یک ابزار خط فرمان درست و حسابی بسازیم. ماژولهای مورد نیاز برای اینکار subprocess و optparse هستند.
بعدها میتوانید از این مثال به عنوان قالبی برای ابزارهای خودتان که از بش در داخل پایتون (که قدرتمند تر است) استفاده میکنند، بهره ببرید. (این روشی خوب برای استفاده از دانستههای کنونیتان برای مهاجرت آرام به پایتون است)
استفاده از بش برای ساختن ابزار خط فرمان پایتون:
#!/usr/bin/env python
import subprocess
import optparse
import re
#Create variables out of shell commands
#Note triple quotes can embed Bash
#You could add another bash command here
#HOLDING_SPOT="""fake_command"""
#Determines Home Directory Usage in Gigs
HOMEDIR_USAGE = """
du -sh $HOME | cut -f1
"""
#Determines IP Address
IPADDR = """
/sbin/ifconfig -a | awk '/(cast)/ { print $2 }' | cut -d':' -f2 | head -1
"""
#This function takes Bash commands and returns them
def runBash(cmd):
p = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE)
out = p.stdout.read().strip()
return out #This is the stdout from the shell command
VERBOSE=False
def report(output,cmdtype="UNIX COMMAND:"):
#Notice the global statement allows input from outside of function
if VERBOSE:
print "%s: %s" % (cmdtype, output)
else:
print output
#Function to control option parsing in Python
def controller():
global VERBOSE
#Create instance of OptionParser Module, included in Standard Library
p = optparse.OptionParser(description='A unix toolbox',
prog='py4sa',
version='py4sa 0.1',
usage= '%prog [option]')
p.add_option('--ip','-i', action="store_true", help='gets current IP Address')
p.add_option('--usage', '-u', action="store_true", help='gets disk usage of homedir')
p.add_option('--verbose', '-v',
action = 'store_true',
help='prints verbosely',
default=False)
#Option Handling passes correct parameter to runBash
options, arguments = p.parse_args()
if options.verbose:
VERBOSE=True
if options.ip:
value = runBash(IPADDR)
report(value,"IPADDR")
elif options.usage:
value = runBash(HOMEDIR_USAGE)
report(value, "HOMEDIR_USAGE")
else:
p.print_help()
#Runs all the functions
def main():
controller()
#This idiom means the below code only runs when executed from command line
if __name__ == '__main__':
main()
ابزار مخفی پایتون برای مدیر سیستم: IPython
مخالفینی که طرف بش را میگرفتند میروند که رفته رفته بگویند: «پایتون خیلی جالبه، ولی مثل بش تعاملی نیست». در واقع این حرف درست نیست، یکی از مهمترین رازهای پایتون که به خوبی مخفی مانده IPython است. من از سازندهی آیپایتون، فرناندو پِرِز، پرسیدم: چطوری میشه که آیپایتون با شل تعاملی یونیکس برابری میکنه؟ به جای اینکه سعی کنم گفتهی او را از زبان خودم بیان کنم، مستقیما گفتهی خودش را اینجا میآورم:
آیپایتون یک جایگزین برای محیط تعاملی پایتون است که سعی دارد در حالی که همخوانی ساختاری دستورات خود را با پایتون ۱۰۰٪ حفظ میکند، معمولترین استفادههای شلمانند کاربران را در خود جای دهد. در آیپایتون فرمانهایی مانند cd و ls همان کارهایی را میکنند که از آنها انتظار دارید، در حالی همچنان به شما اجازه میدهد دستورات همیشگی پایتون را بنویسید. و از آنجایی که آیپایتون به شدت قابل سفارشی کردن است، با یک وضعیت ویژه تحویل داده میشود که پیشفرضهای بیشتری را برای رفتار شبهشل فعال میکند. وضعیتهای سفارشی آیپایتون پروفایل نام دارند، و پروفایل شل را میتوان با دستور زیر فعال کرد:
ipython -p shبا این کار همهی ویژگیهای شلمانند، به صورت پیشفرض فعال میشوند. پیوندهای زیر برخی از کاربردهای شلمانند آیپایتون را نمایش میدهند، با این وجود ما هنوز یک راهنمای جامع برای ویژگیهایی که در واقع زیر پوست هستند، کم داریم.
http://ipython.scipy.org/moin/Cookbook/IpythonShell
http://ipython.scipy.org/moin/Cookbook/JobControl
آیپایتون همچنین شامل یک سری افزونه برای ارتباط برقرار کردن و مدیریت کردن دادههای جدولی است که ipipe نامیده میشود، که با استفاده از آن میتوان بسیاری از شناساییهای پیچیدهی متغیرهای محیطی و شیءهای filesystem را انجام داد. اطلاعات بیشتر در مورد ipipe را میتوان اینجا پیدا کرد:
http://ipython.scipy.org/moin/UsingIPipe
استفاده از آیپایتون به عنوان تنها شل تعاملی برای انجام وظایف سادهی مدیریتی کاملا عملی است. من به تازگی مقالهای برای توسعهدهندگان آیبیام نوشتهام که در آن استفاده از آیپایتون را برای انجام interactive SNMP queries به وسیلهی Net-SNMP شرح دادم.
خلاصه
اگر فقط میتوانید به سختی چند عبارت سادهی بش بنویسید، با کمی کار میتوانید پایتون یاد بگیرید و خیلی زود به نتیجه برسید. تواناییهای بشِ شما، میتوانند رفتهرفته به پایتون تبدیل شوند، و قبل از اینکه متوجه شوید یک برنامهنویس تمامعیار پایتون خواهید شد.
من پایتون را برای برنامهنویسی از بش سادهتر یافتم؛ به عنوان نمونه، لازم نیست با انبوه سناریوهای فرار دستوپنجه نرم کنید. بش جایگاه خودش را دارد – معمولا وقتی به پایتون دسترسی ندارید – ولی پایتون حصار بش به عنوان یک زبان اسکریپتنویسی را برمیچیند.
من پیوندی به تمام مثالها ذکر کردهام، و به زودی یک نسخهی پختهتر از ابزار خطفرمان پایتون به همراه چند ترفند بیشتر، اضافه خواهم کرد.
بگذارید اینگونه تمام کنم که اگر مایلید بش را با پایتون جایگزین کنید، سعی کنید بهترین قدم را بردارید، و تستهایی بنویسید که مشخص کند آنچه نوشتهاید واقعا کار میکند. این جهش بزرگی در فکر است، اما میتواند کدها و تولیداتِ شما را به سمتِ مرحلهی بعد سوق دهد. آسانترین راه برای شروع تستکردن در پایتون استفاده از doctests است و من در انتهای مقاله یک لینک برای آن گذاشتهام. موفق باشید!
منابع
- Subversion Repository For Examples
- Checklist Based Testing For SysAdmins
- Doctests
- Online Bash Scripting Guide
- Python Tutorial
- IPython
- Jeff Rush Show Me Do Tutorial
- PEP8
- Net-SNMP and IPython
دربارهی نویسنده
نوح گیفت، یکی از نویسندگان کتاب Python for Unix and Linux System Administration از انتشارات O’Reilly است. او در Racemi به عنوان یک مهندس نرمافزار فعال بوده و با Bash، Python، SNMP و انواع سیستمهای عامل *nix از جمله AIX, HP-UX, Solaris, Irix, Red Hat, Ubuntu, Free BSD, OS X و هر چیزی که شل داشته باشد، سروکار دارد. اگر او را پای terminal پیدا نکردید، میتوانید او را در حال ورزش در یک بعدازظهر یکشنبه پیدا کنید.
نکات تکمیلی
- این مقاله نه قدرت واقعی پایتون را نشان میدهد و نه قدرت واقعی بش را (هدف این نبوده). خیلی فرامین را میتوان به گونههای بهتری هم نوشت، مثلا بهجای فراخوانی دستورات “ls” و “df” میتوان مستقیما readdir() یا statvfs() استفاده کرد و…
- در نسلهای قدیمی پایتون (۲.۳ به قبل)، دسترسی به subprocess متفاوت است، به جای آن میتوان از
os.system()یا این استفاده کرد. ولی subprocess مزیت دارد. (این تغییر و رشد سریع پایتون را میتوان یکی از معایب آن دانست که باعث میشود کدها از نسخهای به نسخهی دیگر نیاز به دستکاری پیدا کنند، البته در حال حاضر پایتون ۲٫۶ یک نسخهی پایدار محسوب میشود) - برنامههای شلی که در این مقاله نوشته شده ممکن است چندان بهینه نباشند. (سخت نگیرید)
- این مقاله قصد ندارد بگوید بش را باید انداخت دور! بلکه هدف معرفی پایتون به عنوان یک زبان اسکریپت نویسی قوی برای بسیاری از کاربران عادی است.
تشکر
خواهش : )