2.10. 脚本编程

2.10.1. 通过重定向/管道/文件接受输入

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import fileinput

with fileinput.input() as f_input:
    for line in f_input:
        print(line, end='')

2.10.2. 终止程序并给出错误信息

# f1
import sys
sys.stderr.write('It failed!\n')
raise SystemExit(1)

# f2
raise SystemExit('It failed!')

2.10.3. 解析命令行选项

import argparse
parser = argparse.ArgumentParser(description='Search some files')

parser.add_argument(dest='filenames',metavar='filename', nargs='*')

parser.add_argument('-p', '--pat',metavar='pattern', required=True,
                    dest='patterns', action='append',
                    help='text pattern to search for')

parser.add_argument('-v', dest='verbose', action='store_true',
                    help='verbose mode')

parser.add_argument('-o', dest='outfile', action='store',
                    help='output file')

parser.add_argument('--speed', dest='speed', action='store',
                    choices={'slow','fast'}, default='slow',
                    help='search speed')

args = parser.parse_args()

# Output the collected arguments
print(args.filenames)
print(args.patterns)
print(args.verbose)
print(args.outfile)
print(args.speed)

2.10.4. 运行时弹出密码输入提示

import getpass

print("=")
user = input('Enter your username: ')
print("==")
passwd = getpass.getpass()

def svc_login(user, passwd):
   if user=='root' and passwd == '123456':
      return True
   else:
      return False
   
if svc_login(user, passwd):    # You must write svc_login()
   print('Yay!')
else:
   print('Boo!')

2.10.5. 获取终端的大小

>>> import os
>>> os.get_terminal_size()
os.terminal_size(columns=135, lines=18)

2.10.6. 执行外部命令并获取它的输出

import subprocess

try:
    out_bytes = subprocess.check_output(['netstat','-a'], timeout=5,shell=True, stderr=subprocess.STDOUT)
except subprocess.TimeoutExpired as e:
    print(e)

import subprocess

# Some text to send
text = b'''
hello world
this is a test
goodbye
'''

# Launch a command with pipes
p = subprocess.Popen(['wc'],
          stdout = subprocess.PIPE,
          stdin = subprocess.PIPE)

# Send the data and get the output
stdout, stderr = p.communicate(text)

# To interpret as text, decode
out = stdout.decode('utf-8')
err =stderr.decode('utf-8')

2.10.7. 复制或者移动文件和目录

import shutil

# Copy src to dst. (cp src dst)
shutil.copy(src, dst)

# Copy files, but preserve metadata (cp -p src dst)
shutil.copy2(src, dst)

# Copy directory tree (cp -R src dst)
shutil.copytree(src, dst)

# Move src to dst (mv src dst)
shutil.move(src, dst)

2.10.8. 创建和解压归档文件

shutil 模块拥有两个函数—— make_archive() 和 unpack_archive() 可派上用场

2.10.9. 通过文件名查找文件


import os 
def find_file_name(start_path, file_name):
     for relpath, dirs, files in os.walk(start_path):
        if file_name in files:
            full_path = os.path.join(start_path, relpath, file_name)
            return os.path.normpath(os.path.abspath(full_path))


if __name__ == '__main__':
    print('='*10)
    print(find_file_name(r'.', os.path.basename(__file__)))
    print('='*10)

2.10.10. 读取配置文件

configparser 模块能被用来读取配置文件。

import configparser
cfg = configparser.ConfigParser()
cfg.read('./demo.ini')
print(cfg.get('server','nworkers'))

2.10.11. 给简单脚本增加日志功能

import logging 


logging.basicConfig(level=logging.DEBUG, 
                    format='%(asctime)s - %(levelname)s - %(message)s',
                    filename='a.log',
                    datefmt='%Y-%m-%d %H:%M:%S',
                    )

logging.critical('file no exist error')

2.10.12. 给函数库增加日志功能

import logging
log = logging.getLogger(__name__)
log.addHandler(logging.NullHandler())

def add(a,b):
    log.critical('add %s and %s', a, b)
    return a+b 

if __name__ == '__main__':
    logging.basicConfig()
    add(1,2)

2.10.13. 实现一个计时器

import time

class Timer(object):
    def __init__(self):
        self.elapsed = 0 

    def __enter__(self):
        self.start = time.perf_counter()
        return self

    def __exit__(self, *args):
        self.end = time.perf_counter()
        self.elapsed = self.end - self.start


with Timer() as t:
    time.sleep(1)

print(t.elapsed)

2.10.14. 限制cpu和mem

import signal
import resource
import os

def time_exceeded(signo, frame):
    print("Time's up!")
    raise SystemExit(1)

def set_max_runtime(seconds):
    # Install the signal handler and set a resource limit
    soft, hard = resource.getrlimit(resource.RLIMIT_CPU)
    resource.setrlimit(resource.RLIMIT_CPU, (seconds, hard))
    signal.signal(signal.SIGXCPU, time_exceeded)

if __name__ == '__main__':
    set_max_runtime(15)
    while True:
        pass

2.10.15. 启动一个WEB浏览器

In [1]: import webbrowser

In [2]: webbrowser.open('http://www.python.org')
Out[2]: True