设为首页 收藏本站
查看: 515|回复: 0

[经验分享] Python for Bash scripters: A well-kept secret

[复制链接]

尚未签到

发表于 2017-5-2 10:01:58 | 显示全部楼层 |阅读模式
  http://magazine.redhat.com/2008/02/07/python-for-bash-scripters-a-well-kept-secret/
  



Python for
Bash scripters: A well-keptsecret



byNoah Gift


Hey you, ya you! Do you write Bash scripts?
Come here, I have a secret to tell you.
Python is easy to learn, and more powerful than Bash. I wasn’t supposed to tell you this–it’s supposed to be a secret. Anything more than a few lines of Bash could be done better in Python. Python
is often just as portable as Bash too. Off the top of my head, I can’t think of any *NIX operating systems, that don’t include Python. Even IRIX has Python installed.

If you can write a function in Bash, or even piece together a few commands into a script and make it executable, then you can learn Python. What usually throws Bash scripters off is they see something
object-oriented like this:


class FancyObjectOriented(object):
def __init__(self, stuff = "RegularStuff"):
self.stuff = stuff
def printStuff(self):
print "This method prints the %s object" % self.stuff

Object-oriented programming can be a real challenge to get the hang of, but fortunately in Python it is 100% optional. You don’t need to have a Computer Science degree to program in Python–you can
get started immediately if you know a few shortcuts. My goal here is to show Average Joe Bash scripter how to write in Python some of the things they would normally write in Bash. Even though it seems unbelievable, you can be a beginning Python programmer,
by the end of this article.



Baby steps


The very first thing to understand about Python, is that whitespace is significant. This can be a bit of a stumbling block for newcomers, but it will be old hat very quickly. Also, the shebang line
is different than it should be in Bash:

Python Shebang Line:

#!/usr/bin/env python

Bash Shebang Line:

#!/usr/bin/env bash

Knowing these two things, we can easily create the usual ‘Hello World’ program in Python, although whitespace won’t come into play just yet. Open up your favorite text editor and call the python
script, hello.py, and the bash script hello.sh.

Python Hello World script:

#!/usr/bin/env python
print "Hello World"

Bash Hello World script:

#!/usr/bin/env bash
echo Hello World

Make sure that you make each file executable by usingchmod +x hello.py, andchmod +x hello.sh.
Now if you run either script–./hello.pyor./hello.sh–you will get the obligatory “Hello World.”



Toddler: System calls in Python


Now that we got ‘Hello World’ out of the way, lets move on to more useful code. Typically most small Bash scripts are just a bunch of commands either chained together, or run in sequence. Because
Python is also a procedural language, we can easily do the same thing. Lets take a look at a simple example.

In order to take our toddler steps it is important to remember two things:
1. Whitespace is significant. Keep this in mind–I promise we will get to it. It is so important that I want to keep reminding you!
2. A module called subprocess needs to be imported to make system calls.
It is very easy to import modules in Python. You just need to put this statement at the top of the script to import the module:
import subprocess
Lets take a look at something really easy with the subprocess module. Lets execute an ls -l of the current directory.
Python ls -l command:

#!/usr/bin/env python
import subprocess
subprocess.call("ls -l", shell=True)

If you run this script it will do the exact same thing as runningls -lin Bash. Obviously writing 2 lines of Python to do one line of Bash
isn’t that efficient. But let’s run a few commands in sequence, just like we would do in Bash so you can get comfortable with how a few commands run in sequence might look. In order to do that I will need to introduce two new concepts: one for Python variables
and the other for lists (known as ‘arrays’ in Bash). Lets write a very simple script that gets the status of a few important items on your system. Since we can freely mix large blocks of Bash code, we don’t have to completely convert to Python just yet. We
can do it in stages. We can do this by assigning Bash commands to a variable.



Note:

If you are cutting and pasting this text, you MUST preserve the whitespace. If you are using vim you can do that by using paste mode:set paste
PYTHON

Python runs a sequence of system commands.


#!/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)

BASH

Bash runs a sequence of system commands.


#!/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

Python is much more forgiving about the way you quote and use variables, and lets you create a much less cluttered piece of code.


Childhood: Reusing code by writing functions


We have seen how Python can implement system calls to run commands in sequence, just like a regular Bash script. Let’s go a little further and organize blocks of code into functions. As I mentioned
earlier, Python does not require the use of classes and object-oriented programming techniques, so most of the full power of the language is still at our fingertips—even if we’re only using plain functions.

Let’s write a simple function in Python and Bash and call them both in a script.


Note:

These two scripts will deliver identical output in Bash and Python, although Python handles default keyword parameters automatically in functions. With Bash, setting default parameters is much more work.PYTHON:

#!/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()

BASH:

#!/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


Teenager: Making reusable command-line tools


Now that you have the ability to translate simple Bash scripts and functions into Python, let’s get away from the nonsensical scripts and actually write something useful. Python has a massive standard
library that can be used by simple importing modules. For this example we are going to create a robust command-line tool with the standard library of Python, by importing the subprocess and optparse modules.

You can later use this example as a template to build your own tools that combine snippits of Bash inside of the more powerful Python. This is a great way to use your current knowledge to slowly
migrate to Python.

Embedding Bash to make Python command-line tools[1]:

#!/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()


Python’s secret sysadmin weapon: IPython


The skeptics in the Bash crowd are just about to say, “Python is pretty cool, but it isn’t interactive like Bash.” Actually, this is not true. One of the best kept secrets of the Python world isIPython.
I asked the creator of IPython, Fernando Perez, how IPython stacks up to classic Unix interactive shells. Rather than trying to replicate what he said, I’ll simply quote directly:



IPython is a replacement for the Python interactive environment that tries to incorporate the most common shell-like usage patterns in a natural way, while keeping 100% syntactic compatibility with
the Python language itself. In IPython, commands like ‘cd’ or ‘ls’ do what you’d expect of them, while still allowing you to type normal Python code. And since IPython is highly customizable, it ships with a special mode that activates even more defaults for
shell-like behavior. IPython custom modes are called profiles, and the shell profile can be requested via:


ipython -p sh

This will enable all the shell-like features by default. The links below show some basic information about the shell-like usage of IPython, though we still lack a comprehensive guide for all of
the features that actually exist under the hood.

http://ipython.scipy.org/moin/Cookbook/IpythonShell
http://ipython.scipy.org/moin/Cookbook/JobControl

IPython also contains a set of extensions for interactively connecting and manipulating tabular data, called ‘ipipe,’ that enables a lot of sophisticated exploration of filesystem objects and environment
variables. More information about ipipe can be found here:

http://ipython.scipy.org/moin/UsingIPipe


It is quite possible to use IPython as the only interactive shell for simple systems administration tasks. I recently wrotean
article for IBM Developerworks, in which I demonstrated using IPython to perform interactive SNMP queries using Net-SNMP with Python bindings:



Summary


Even if you can barely string together a few statements in Bash, with a little work you can learn Python and be productive very quickly. Your existing Bash skills can be slowly converted to Python
skills. And before you know it, you will be a full-fledged Python programmer.

I find Python easier to program in than Bash; you don’t have to deal with hordes of escaping scenarios, for one. Bash has its place–usually when you don’t have the ability to run Python–as Python
beats the pants off Bash as a scripting language.

I have included a link to all of the examples, and will have a souped-up version of the Python command-line tool with a few extra tricks sometime soon.
Let me close with saying that if you are interested in replacing Bash with Python, try to start out on the best possible foot and write tests that validate what you think you wrote actually works.
This is a huge leap in thinking, but it can propel your code and productivity to the next level. The easiest way to get started with testing in Python is to use doctests, and I have enclosed a link at the bottom of this article. Good luck!



References



  • 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



[1]This code example has been corrected. Feb 08, 2008, 11AM EST



About the author


Noah Gift is currently co-authoring a book for O’Reilly, “Python For *Nix Systems Administration,” (working title) due sometime in 2008. He works as a software engineer for Racemi, dealing with
Bash, Python, SNMP and a slew of *nix operating systems, including AIX, HP-UX, Solaris, Irix, Red Hat, Ubuntu, Free BSD, OS X, and anything else that has a shell. He is giving a talk at PyCon 2008–the annual Python Programming convention being held in Chicago–on
writing *nix command line tools in Python. When not sitting in front of a terminal, you might find him on a 20 mile run on a Sunday afternoon.





This entry was posted byNoah Gifton Thursday, February 7th, 2008 at 6:17 pm and is filed underdocumentation,Fedora,Red
Hat Enterprise Linux,technical. You can follow any responses to this entry through
theRSS 2.0feed. Both comments and pings are currently closed.

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-371962-1-1.html 上篇帖子: 学习python核心编程-第三章-课后习题笔记 下篇帖子: Divie into Python 读书笔记 第三章
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表