一、Python如何处理重定向

1. 解释linux重定向

Linux重定向是指修改原来默认的一些东西,对原来系统命令的默认执行方式进行改变,比如说简单的我不想看到在显示器的输出而是希望输出到某一文件中就可以通过Linux重定向来进行这项工作。

                                                          --by 百度百科

2、简练linux重定向

标准输入、标准输出和错误输出

[root@python ~]# cat     #从键盘标准输入,然后打印在屏幕上。
"Hello world!!!"  
"Hello world!!!"         #ctrl+d结束键盘的输入
[root@python ~]# cat < /etc/hosts    #从文件标准输入,然后打印在屏幕上
127.0.0.1   localhost localhost.localdomain localhost4 localhost4.localdomain4
::1         localhost localhost.localdomain localhost6 localhost6.localdomain6

3、Python实现Linux重定向

在python的sys模块中有三个方法可以实现linux下重定向,那么我们接下来一起去学习下:

导入sys模块:import sys

查看sys模块的三个方法分别是sys.stdin、sys.stdout、sys.stderr

查看使用的帮助信息,具体的去了解用法和功能

In [2]: sys.stdin?
Type:       file
String Form:<open file '<stdin>', mode 'r' at 0x7f9b0f1ae0c0>
Docstring:
file(name[, mode[, buffering]]) -> file object

Open a file.  The mode can be 'r', 'w' or 'a' for reading (default),
writing or appending.  The file will be created if it doesn't exist
when opened for writing or appending; it will be truncated when
opened for writing.  Add a 'b' to the mode for binary files.
Add a '+' to the mode to allow simultaneous reading and writing.
If the buffering argument is given, 0 means unbuffered, 1 means line
buffered, and larger numbers specify the buffer size.  The preferred way
to open a file is with the builtin open() function.
Add a 'U' to mode to open the file for input with universal newline
support.  Any line ending in the input file will be seen as a '\n'
in Python.  Also, a file so opened gains the attribute 'newlines';
the value for this attribute is one of None (no newline read yet),
'\r', '\n', '\r\n' or a tuple containing all the newline types seen.

'U' cannot be combined with 'w' or '+' mode.

打开一个文件,有三种模式分别是read、write、append,而默认的方式是以read的模式进行打开一个文件。如果这个文件不存在它将要被创建;

当以write的模式打开这个文件的时候,它将被truncated;

增加一个b是以二进制文件的模式;增加一个+这种模式允许同时读和写。等等

[root@python lianxi]# python f1.py 
"Hello world!!!"
"Hello world!!!"
[root@python lianxi]# python f1.py < /etc/hosts
127.0.0.1   localhost localhost.localdomain localhost4 localhost4.localdomain4
::1         localhost localhost.localdomain localhost6 localhost6.localdomain6

代码如下:

[root@python lianxi]# cat f1.py 
#!/usr/bin/env python

import sys

f = sys.stdin
print f.read(),

4、文件对象的方法

4.1介绍python中打开文件的几种常用方法:

方法1:

>>> fp = file('/etc/passwd','r')
>>> data = fp.read()
>>> fp.close()
>>> fp = open('/etc/passwd','r')
>>> data = fp.read()
>>> fp.close()

方法2:

>>> with open('/etc/hosts','r') as fd:
...         data = fd.read()

这两种的区别就在于:方法1打开文件后要关闭文件,而方法2打开文件后不需要关闭文件。


4.2文件对象的方法:

fp.read()、fp.readline()、fp.readlines()、fp.write()、fp.close()


Python解释器中查看使用说明


对象fp 方法read(): 返回值为string

In [14]: fp.read?
Type:       builtin_function_or_method
String Form:<built-in method read of file object at 0x7f9afc02e1e0>
Docstring:
read([size]) -> read at most size bytes, returned as a string.

If the size argument is negative or omitted, read until EOF is reached.
Notice that when in non-blocking mode, less data than what was requested
may be returned, even if no size parameter was given.


>>> fp = open('/etc/hosts','r')
>>> print fp.read()    #不带参数,表示一次性读完
127.0.0.1   localhost localhost.localdomain localhost4 localhost4.localdomain4
::1         localhost localhost.localdomain localhost6 localhost6.localdomain6

>>> print fp.read()

>>>
>>> fp = open('/etc/hosts','r')
>>> print fp.read(50)    #带参数,表示每次仅读的字节大小,这样节省内存的开销
127.0.0.1   localhost localhost.localdomain localh
>>> print fp.read(50)
ost4 localhost4.localdomain4
::1         localhost
>>> print fp.read(50)
 localhost.localdomain localhost6 localhost6.local
>>> print fp.read(50)
domain6

>>> print fp.read(50)

>>> print fp.read(50)

---------------------------------华丽分割线---------------------------------

对象fp 方法readline(): 返回值为string

In [17]: fp.readline?
Type:       builtin_function_or_method
String Form:<built-in method readline of file object at 0x7f9afc02e1e0>
Docstring:
readline([size]) -> next line from the file, as a string.

Retain newline.  A non-negative size argument limits the maximum
number of bytes to return (an incomplete line may be returned then).
Return an empty string at EOF.
>>> fp = open('/etc/hosts','r')
>>> print fp.readline()    #不带参数表示每次仅读一行,按行读取
127.0.0.1   localhost localhost.localdomain localhost4 localhost4.localdomain4

>>> print fp.readline()
::1         localhost localhost.localdomain localhost6 localhost6.localdomain6

>>> print fp.readline()

---------------------------------华丽分割线---------------------------------

对象fp 方法readlines(): 返回值为list,每行为list的一个元素

In [18]: fp.readlines?
Type:       builtin_function_or_method
String Form:<built-in method readlines of file object at 0x7f9afc02e1e0>
Docstring:
readlines([size]) -> list of strings, each a line from the file.

Call readline() repeatedly and return a list of the lines so read.
The optional size argument, if given, is an approximate bound on the
total number of bytes in the lines returned.
>>> fp = open('/etc/hosts','r')
>>> print fp.readlines()
['127.0.0.1   localhost localhost.localdomain localhost4 localhost4.localdomain4\n', '::1         localhost localhost.localdomain localhost6 localhost6.localdomain6\n']

---------------------------------华丽分割线---------------------------------

用while循环对文件的每一行进行遍历

[root@python lianxi]# python f3.py 
127.0.0.1   localhost localhost.localdomain localhost4 localhost4.localdomain4
::1         localhost localhost.localdomain localhost6 localhost6.localdomain6
lines: 2

#####代码如下#####
[root@python lianxi]# cat f3.py 

fp = open('/etc/hosts','r')

n = 0
while True:
    line = fp.readline()
    if line:
    	print line,
    	n += 1
    else:
    	break
fp.close()
print 'lines: %s' % n


用for循环对文件的每一行进行遍历

[root@python lianxi]# python f4.py 
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin
adm:x:3:4:adm:/var/adm:/sbin/nologin
lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
sync:x:5:0:sync:/sbin:/bin/sync
shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
halt:x:7:0:halt:/sbin:/sbin/halt
mail:x:8:12:mail:/var/spool/mail:/sbin/nologin
uucp:x:10:14:uucp:/var/spool/uucp:/sbin/nologin
operator:x:11:0:operator:/root:/sbin/nologin
games:x:12:100:games:/usr/games:/sbin/nologin
gopher:x:13:30:gopher:/var/gopher:/sbin/nologin
ftp:x:14:50:FTP User:/var/ftp:/sbin/nologin
nobody:x:99:99:Nobody:/:/sbin/nologin
dbus:x:81:81:System message bus:/:/sbin/nologin
vcsa:x:69:69:virtual console memory owner:/dev:/sbin/nologin
saslauth:x:499:76:"Saslauthd user":/var/empty/saslauth:/sbin/nologin
postfix:x:89:89::/var/spool/postfix:/sbin/nologin
sshd:x:74:74:Privilege-separated SSH:/var/empty/sshd:/sbin/nologin
mysql:x:27:27:MySQL Server:/var/lib/mysql:/bin/bash
ntp:x:38:38::/etc/ntp:/sbin/nologin
git:x:498:498:git version control:/home/git:/bin/bash
allentuns:x:500:500::/home/allentuns:/bin/bash

#####代码如下#####
[root@python lianxi]# cat f4.py 

with open('/etc/passwd','r') as fd:
    data = fd.readlines()

for i in data:
    print i,

5、Python模块sys的介绍

5.1 sys模块输出

[root@python lianxi]# python f5.py > /dev/null
stderr:hello world
[root@python lianxi]# python f5.py 2> /dev/null
print:hello world!!!
stdout:hello world
[root@python lianxi]# python f5.py > /dev/null 2>& 1
[root@python lianxi]# 
[root@python lianxi]# cat f5.py 
import sys

print 'print:hello world!!!'
sys.stdout.write('stdout:hello world\n')   
sys.stderr.write('stderr:hello world\n')

博文一开始就介绍了sys模块的重定向,大家也知道sys.stdout是标准重定向,可以重定向到/dev/null空洞中;sys.stderr是错误重定向可以把屏幕上的错误输出重定向到 2> /dev/null中?那么问题来了,为什么print和strdout是一样的效果呢?

其实是这样的:print通常是调用一个stdout对象的write方法。print具有以下特征:

(1)print会先进行格式转换

(2)print会在自后加上换行符

结果不然,print还有另外一个强大的功能就是print结合sys.stdout和sys.stderr,接下来大家意洽来看


print结合stderr

[root@python lianxi]# python f6.py 2> /dev/null 
stdout,good
[root@python lianxi]# cat f6.py 
import sys

print >> sys.stderr,'hello world!!!'
sys.stdout.write('stdout,good\n')

二、Python简单wc命令统计

1、简单的wc命令

linux命令的实现
[root@python lianxi]# wc /etc/hosts
  2  10 158 /etc/hosts
 2行 10单词 158字节
 
Python模块实现简单wc统计
[root@python lianxi]# python f7.py < /etc/hosts
2 10 158
from sys import stdin

data = stdin.read()
lines = data.count('\n')
words = len(data.split())
chars = len(data)
print lines,words,chars

2、sys.argv使用

In [20]: sys.argv?
Type:       list
String Form:['/usr/bin/ipython']
Length:     1
Docstring:
list() -> new empty list
list(iterable) -> new list initialized from iterable's items
list() -> 返回值为一个空的列表
list(iterable) -> 从迭代的元素中返回到一个新的列表
[root@python lianxi]# python f8.py /etc/hosts
sys.argv:  ['f8.py', '/etc/hosts']
127.0.0.1   localhost localhost.localdomain localhost4 localhost4.localdomain4
::1         localhost localhost.localdomain localhost6 localhost6.localdomain6
[root@python lianxi]# cat f8.py 
import sys

print 'sys.argv: ',sys.argv
f = open(sys.argv[1])
for i in f:
    print i,

3、修改wc脚本能够接受参数

[root@python lianxi]# python wc.py /etc/hosts
2 10 158
[root@python lianxi]# cat wc.py 
from sys import argv

with open(argv[1]) as fd:
    data = fd.read()
    lines = data.count('\n')
    words = len(data.split())
    chars = len(data)
    print '%(lines)s %(words)s %(chars)s' % locals()

三、Python实现真正的命令行参数wc

1、脚本能够实现的功能

(1)统计单个文件、多个文件的行数、单词数、字符数

(2)如果只有一个文件,那么显示结果汇总也就是合计;如果是多个文件显示汇总合计信息

(3)对传递的文件进行判断,是否为文件、文件是否存在等等情况

(4)支持选项,比如只统计多个文件的大小或总共有多少行都是可以的

(5)支持管道输入

2、python的wc脚本

#!/usr/bin/env python
#coding:utf8
#
import os,sys
from optparse import OptionParser

parser = OptionParser()
parser.add_option('-l','--lines',
                        dest='lines',
                        action='store_true',
                        default=False,
                        help='only count lines',
                        )

parser.add_option('-w','--words',
                        dest='words',
                        action='store_true',
                        default=False,
                        help='only count words',
                        )

parser.add_option('-c','--chars',
                        dest='chars',
                        action='store_true',
                        default=False,
                        help='only count chars',
                        )

options,args = parser.parse_args()

def getCount(data):
        lines = data.count('\n')
        words = len(data.split())
        chars = len(data)
        return lines,words,chars
        #print '%(lines)s %(words)s %(chars)s' % locals()

def print_wc(lines,words,chars,fn):
        if options.lines:
                print lines,
        if options.words:
                print words,
        if options.chars:
                print chars,
        print fn


if not (options.lines or options.words or options.chars):
    options.lines,options.words,options.chars = True, True, True

if args:
    total_lines,total_words,total_chars = 0, 0, 0
    for fn in args:
        if os.path.isfile(fn):
            with open(fn) as fd:
                data = fd.read()
                lines,words,chars = getCount(data)
                total_lines += lines
                total_words += words
                total_chars += chars
                print_wc(lines,words,chars,fn)
        elif os.path.isdir(fn):
                tup = (sys.argv[0],fn)
                sys.stderr.write('python %s : %s: Is a directory\n' % tup)
        else:
                tup = (sys.argv[0],fn)
                print 'python %s : %s: No such file or directory' % tup

    if len(args) > 1:
                print_wc(total_lines,total_words,total_chars,'total')

else:
    fn = ''
    data = sys.stdin.read()
    lines,words,chars = getCount(data)
    print_wc(lines,words,chars,fn)

脚本参数解释

OptionParse是python的一个模块,可以实现真正意义上的命令行参数
-c/--chars:命令行选项
dest:为选项定义变量名,值chars就是-c选项的命令
default=False: chars的值为False 意思默认情况下命令不带-c选项
help:选项解释说明部分

3、python脚本测试

[root@python lianxi]# python wc.py /etc/hosts
2 10 158 /etc/hosts
[root@python lianxi]# python wc.py /etc/hosts /etc/issue
2 10 158 /etc/hosts
3 9 47 /etc/issue
5 19 205 total
[root@python lianxi]# python wc.py /etc/hosts /etc/issue /etc/passwd
2 10 158 /etc/hosts
3 9 47 /etc/issue
24 35 1093 /etc/passwd
29 54 1298 total
[root@python lianxi]# python wc.py /etc/hosts /etc/issue /etc/passwd -l
2 /etc/hosts
3 /etc/issue
24 /etc/passwd
29 total
[root@python lianxi]# python wc.py /etc/hosts /etc/issue /etc/passwd -lw
2 10 /etc/hosts
3 9 /etc/issue
24 35 /etc/passwd
29 54 total
[root@python lianxi]# python wc.py /etc/hosts /etc/issue /etc/passwd -lwc
2 10 158 /etc/hosts
3 9 47 /etc/issue
24 35 1093 /etc/passwd
29 54 1298 total
[root@python lianxi]# python wc.py /etc/
python wc.py : /etc/: Is a directory
[root@python lianxi]# python wc.py /etc/nihaobucunzai.txt
python wc.py : /etc/nihaobucunzai.txt: No such file or directory

[root@python lianxi]# python wc.py /etc/nihaobucunzai.txt > /dev/null 
[root@python lianxi]# python wc.py /etc/ 2> /dev/null

---------------------------------------------华丽分割线------------------------------------

更新时间 2015-02-05 这次更新我们就一起聊聊Python的hashlib模块和__name__的形式

一、Python的hashlib模块

1、hashlib模块和hashlib方法

Python模块hashlib;

hashlib对象的方法如下:

hashlib.md5     hashlib.new     hashlib.sha1    

hashlib.sha224  hashlib.sha256  hashlib.sha384  hashlib.sha512

导入hashlib模块是前提,然后才能使用对应的方法

import hashlib


(1)hashlib.new

In [9]: hashlib.new?
Type:       function
String Form:<function __hash_new at 0x7fa8c793f1b8>
File:       /usr/lib64/python2.6/hashlib.py
Definition: hashlib.new(name, string='', usedforsecurity=True)
Docstring:
new(name, string='') - Return a new hashing object using the named algorithm;
optionally initialized with a string.

对应的返回值:返回一个新的hash对象使用指定的算法对一个字符串。

name:指定使用的算法,比如md5、sha1

string:对哪个字符串进行加密

>>> import hashlib
>>> hashlib.new('md5',string='hello world!!!').hexdigest()		
'f6835168c4823ac89c1bc97154a675a8'

#hexdigest() 使加密后的结果以十六进制显示


(2)hashlib.md5

>>>: m = hashlib.md5()
>>>: m.update?	
Type:       builtin_function_or_method
String Form:<built-in method update of _hashlib.HASH object at 0x18146f0>
Docstring:  Update this hash object's state with the provided string.

描述:在提供的字符串中更新这个hash对象的状态

特点:使用update更新hash对象。多次调用update和使用串联的参数一次调用update是等价的

接下来我们用个小例子来证明update的特点:

这种是多次update的效果
>>> m = hashlib.md5()    #创建一个加密对象
>>> m.update('aaabbb')     #更新字符串
>>> m.hexdigest()              #显示加密后的结果
'6547436690a26a399603a7096e876a2d'
>>> m.update('cccddd')
>>> m.hexdigest()
'057cea2fc37aabd4a59462d3fd28c93b'

整合update的所有字符串一次性md5,然后查看效果
>>> m = hashlib.md5()
>>> m.update('aaabbbcccddd')
>>> m.hexdigest()
'057cea2fc37aabd4a59462d3fd28c93b'

呵呵,结果是一直的啊!!!哈哈哈

2、md5和sha1的适用场景

md5经常用来做用户密码的存储。而sha1则经常用作数字签名

>>> a = 'Hello , Allentuns'
>>> print hashlib.md5(a).hexdigest()
1490de1169f6e53f3d8aef43577f05cd
>>> print hashlib.sha1(a).hexdigest()
dcbaaae330347bfc35e31b0d0aff9a1440ea2716
>>> print hashlib.sha224(a).hexdigest()
d843643466a615d72a4f97e2693deefa41bf3f1f36f76add6ddceeba
>>> print hashlib.sha256(a).hexdigest()
44fe3dfd7a0a49647fb99625382e8af3167f8df662b833b7d33ff0409b538a5a
>>> print hashlib.sha384(a).hexdigest()
1757ad1e90f0cc7fcea80cae0942d2ff9f13b5f0c8d6b7d702b71c395a7d9da6f824fe81b7ddfa6e447d49cef8d44efc
>>> print hashlib.sha512(a).hexdigest()
2e8b0747918f492ede366c0774dd35794d2690b2fa79cd7ce8532a7b70f69afb55b9b3a68277f4a993b702dacc9f27610ce2257290d5c885f780722d76162b7f

二、Python求文件的大小

1、需求:传递一个参数(本地路径),然后计算路径下所有文件的大小,并单独显示最大的文件

#!/usr/bin/env python
#coding:utf8
#Author:Allentuns

import sys,os

dict = {}
for p,d,f in os.walk(sys.argv[1]):
       for i in f:
           path_file = os.path.join(p,i)
	   size = os.path.getsize(path_file)
	   dict[path_file] = size 
	   
by_size = sorted(dict.iteritems(), key = lambda asd:asd[1], reverse = True)
print '%s\t\t\t%s' % ('path_to_path','filename')
print '+'*50
for i in by_size:
	print '%s\t%s' % i

print '\n'
print '+'*15 + 'Maximum file current path' + '+'*15
max_size = by_size[0]
filename =  max_size[0]
size = max_size[1]/1024
print '%s %sk' %(filename,size)

2、执行结果如下:

path_to_path			filename
++++++++++++++++++++++++++++++++++++++++++++++++++
/home/nihao	31697
/home/allentuns/.viminfo	4988
/home/allentuns/.bash_history	2686
/home/allentuns/ssh.py	572
/home/git/.ssh/known_hosts	395
/home/allentuns/.ssh/known_hosts	394
/home/allentuns/.bash_profile	215
/home/allentuns/.bashrc	124
/home/git/.bash_history	120
/home/allentuns/ip.txt	117
/home/allentuns/.profile	26
/home/allentuns/.bash_logout	18


+++++++++++++++Maximum file current path+++++++++++++++
/home/nihao 30k

三、了解一下__name__

1、我们先看一个例子

[root@python lianxi]# cat f1.py    #只有一行代码
print __name__
[root@python lianxi]# cat f2.py    #有两行代码
import f1    #导入文件f1
print __name__    #打印

接下来我们来看执行结果

[root@python lianxi]# cat f1.py
print __name__
[root@python lianxi]# cat f2.py
import f1
print __name__

结论:

(1)如果__name__是在当前直接引用的,那么执行的结果是__main__

(2)如果__name__是被其它python程序调用的,那么执行的结果是文件的名字

程序调用的特点:

import f1

在我们执行导入的时候,其实f1中的程序也被从头到尾的执行了一遍,有时候我们只是想用程序的一部分函数等,我们就必须采用一些特殊的方法也就是我们今天聊的话题:

[root@python lianxi]# python f1.py
f1: __main__
[root@python lianxi]# python f2.py
f2: __main__
[root@python lianxi]# cat f1.py
if __name__ == '__main__':
	print 'f1:',__name__
[root@python lianxi]# cat f2.py
import f1
print 'f2:',__name__

这样上面的问题就得到很好的解决。