目录:
1.linux就这样学
2.linux学到了什么
3.学完linux就该这么学是什么程度
4.linux学出来是干嘛的
5.Linux 就该这么学
6.linux就该这么学
7.LINUX就该这么学
8.linux就该这么学看不懂
9.linux学习
10.学会linux
1.linux就这样学
写在前面对于自动化运维来讲Python是一个利器常用的自动化运维工具Ansible就是通过python编写博文为《Python Cookbook》读书笔记整理而来涉及的内容都是编写python运维脚本常用的一些知识点及Demo
2.linux学到了什么
理解不足小伙伴帮忙指正「 生命完美的答案,无非走过没有遗憾 —《天蓝》」脚本编程与系统管理解析命令行选项「如何能够解析脚本运行命令行选项(位于 sys.argv 中)」argparse 模块可被用来解析命令行选项
3.学完linux就该这么学是什么程度
常用来定义一个脚本的说明文档,一般我们写python脚本会通过if..else 的方式来提供一个脚本说明文档,python不支持switch所以很麻烦,其实,我们可以通过argparse来编写说明文档我们来看看怎么执行一个python脚本
4.linux学出来是干嘛的
对于熟悉Linux的小伙伴下面的文档在熟悉不过了,这个一个标准Linxu软件包的说明文档,文档中定义是软件包的说明┌──[root@liruilongs.github.io]-[~/python_demo] └─$./demo.py -h usage: demo.py [-h] -p pattern [-v] [-o OUTFILE] [
5.Linux 就该这么学
–speed {slow,fast}] [filename [filename …]] Search some files positional arguments: filename optional arguments: -h,
6.linux就该这么学
–help show this help message and exit -p pattern, –pat pattern text pattern to search
7.LINUX就该这么学
for -v verbose mode -o OUTFILE output file –speed {slow,fast} search speed
8.linux就该这么学看不懂
┌──[root@liruilongs.github.io]-[~/python_demo] └─$ 来看看这个脚本是如何编写的#!/usr/bin/env python3 import argparse
9.linux学习
# 脚本的描述 parser = argparse.ArgumentParser(description=Search some files) # 脚本接收的全部参数,用`filenames`接收 parser.add_argument(dest=
10.学会linux
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 argumentsprint(args.filenames) print(args.patterns) print(args.verbose) print(args.outfile)
print(args.speed) 为了解析命令行选项, 首先要创建一个ArgumentParser实例, 使用add_argument() 方法声明你想要支持的选项在每个add-argument()。
调用中:dest参数指定解析结果被指派给属性的名字 metavar 参数被用来生成帮助信息action 参数指定跟属性对应的处理逻辑,通常的值为 store , 被用来存储某个值或将多个参数值收集到一个列表中。
nargs 参数收集所有剩余的命令行参数到一个列表中在本例中它被用来构造一个文件名列表parser.add_argument(dest=filenames,metavar=filename, nargs=。
*) ┌──[root@liruilongs.github.io]-[~/python_demo] └─$python3 demo.py -p spam –pat=eggs foo.txt bar.txt
[foo.txt, bar.txt] [spam, eggs] False None slow ┌──[root@liruilongs.github.io]-[~/python_demo] └─$ action=store_true
根据参数是否存在来设置一个位置 Boolean 标志:parser.add_argument(-v, dest=verbose, action=store_true, help=verbose mode
) ┌──[root@liruilongs.github.io]-[~/python_demo] └─$python3 demo.py -v -p spam –pat=eggs foo.txt bar.txt
[foo.txt, bar.txt] [spam, eggs] True None slow action=store 参数接受一个单独值并将其存储为一个字符串parser.add_argument(
-o, dest=outfile, action=store, help=output file) ┌──[root@liruilongs.github.io]-[~/python_demo] └─$python3 demo.py -v -p spam
–pat=eggs -o liruilong foo.txt bar.txt [foo.txt, bar.txt] [spam, eggs] True liruilong slow action=append
参数说明允许某个参数重复出现多次,并将它们追加到一个列表中去required 标志表示该参数至少要有一个-p 和 –pat 表示两个参数形式都可使用parser.add_argument(-p, –pat
, metavar=pattern, required=True, dest=patterns, action=append,
help=text pattern to search for) ┌──[root@liruilongs.github.io]-[~/python_demo] └─$python3 demo.py -p spam foo.txt bar.txt [
foo.txt, bar.txt] [spam] False None slow ┌──[root@liruilongs.github.io]-[~/python_demo] └─$python3 demo.py –pat=eggs foo.txt bar.txt [
foo.txt, bar.txt] [eggs] False None slow ┌──[root@liruilongs.github.io]-[~/python_demo] └─$python3 demo.py -p spam –pat=eggs foo.txt bar.txt [
foo.txt, bar.txt] [spam, eggs] False None slow 如果一个都没有,会提示缺少参数 -p/–pat┌──[root@liruilongs.github.io]-[~/python_demo] └─$python3 demo.py foo.txt bar.txt usage: demo.py [-h] -p pattern [-v] [-o OUTFILE] [
–speed {fast,slow}] [filename [filename …]] demo.py: error: the following arguments are required: -p/
–pat ┌──[root@liruilongs.github.io]-[~/python_demo] └─$ choices={slow, fast}, 参数说明接受一个值,但是会将其和可能的选择值做比较,以检测其合法性:
parser.add_argument(–speed, dest=speed, action=store, choices={slow, fast}, default=
slow, help=search speed) ┌──[root@liruilongs.github.io]-[~/python_demo] └─$python3 demo.py
–pat=eggs –speed 123 foo.txt bar.txt usage: demo.py [-h] -p pattern [-v] [-o OUTFILE] [–speed {slow,fast}]
[filename [filename …]] demo.py: error: argument –speed: invalid choice: 123 (choose from slow, fast)
┌──[root@liruilongs.github.io]-[~/python_demo] └─$python3 demo.py –pat=eggs –speed fast foo.txt bar.txt
[foo.txt, bar.txt] [eggs] False None fast ┌──[root@liruilongs.github.io]-[~/python_demo] └─$ 一旦参数选项被指定,你就可以执行
parser.parse()方法了它会处理sys.argv的值并返回一个结果实例每个参数值会被设置成该实例中add_argument()方法的 dest 参数指定的属性值还很多种其他方法解析命令行选项可以会手动地处理 。
sys.argv 或者使用 getopt 模块但是,如果你采用本节的方式,将会减少很多冗余代码,底层细节argparse 模块已经帮你处理好了你可能还会碰到使用optparse库解析选项的代码尽管 optparse 和 argparse 很像
,但是后者更先进,因此在新的程序中你应该使用它运行时弹出密码输入提示「你写了个脚本,运行时需要一个密码此脚本是交互式的,因此不能将密码在脚本中硬编码,而是需要弹出一个密码输入提示,让用户自己输入」Python 的 getpass 模块
正是你所需要的你可以让你很轻松地弹出密码输入提示,并且不会在用户终端显示密码#!/usr/bin/env python3# -*- encoding: utf-8 -*-import getpass 。
defsvc_login(user, passwd):return user == passwd user = getpass.getuser() passwd = getpass.getpass()
if svc_login(user, passwd): print(Yay!) else: print(Boo!) 代码中getpass.getuser()不会弹出用户名的输入提示它会根据该。
用户的 shell 环境或者会依据本地系统的密码库(支持 pwd 模块的平台)来使用当前用户的登录名┌──[root@liruilongs.github.io]-[~/python_demo] └─$./pass.py Password:
#root Yay! 通过重定向/管道/文件接受输入在bash中编写pytohn脚本接收外部数据的方式,一般情况下,对于一般变量,我们用命令行变量的方式比较多(手动的处理 sys.argv ),对于文件内容或者bash命令输出
直接通过脚本内部获取需要的数据其实python 脚本也可以用其他方式来接收 传递给他的文件数据或者bash命令输出,包括将命令行的输出通过管道传递给该脚本、重定向文件到该脚本,或在命令行中传递一个文件名。
或文件名列表给该脚本这里通过 Python 内置的 fileinput 模块,可以实现重定向,管道,以文佳输出的方式传递数据到脚本内部#!/usr/bin/env python3# -*- encoding: utf-8 -*-。
“”” @File : filein.py @Time : 2022/05/01 06:05:43 @Author : Li Ruilong @Version : 1.0 @Contact : 1224965096@qq.com @Desc : None “””
# here put the import libimport fileinput with fileinput.input() as f_input: for line in f_input: print(
“脚本输出”, line, end=) 使用fileinput.input()方法可以获取当前输入脚本的数据,脚本里面用一个FileInput迭代器接收┌──[root@liruilongs.github.io]
-[~/python_demo] └─$vim filein.py ┌──[root@liruilongs.github.io]-[~/python_demo] └─$chmod +x filein.py
文件直接接收┌──[root@liruilongs.github.io]-[~/python_demo] └─$./filein.py /etc/passwd 脚本输出 root:x:0:0:root:/root:/bin/bash 脚本输出 bin:x:
1:1:bin:/bin:/sbin/nologin 脚本输出 daemon:x:2:2:daemon:/sbin:/sbin/nol 重定向接收┌──[root@liruilongs.github.io]-[~/python_demo] └─$./filein.py < /etc/passwd 脚本输出 root:x:。
0:0:root:/root:/bin/bash 脚本输出 bin:x:1:1:bin:/bin:/sbin/nologin 管道方式接收┌──[root@liruilongs.github.io]-[~/python_demo]。
└─$df-h文件系统容量已用可用已用%挂载点/dev/sda1150G22G129G15%/devtmpfs983M0983M0%/devtmpfs993M0993M0%/dev/shmtmpfs993M
17M976M2%/runtmpfs993M0993M0%/sys/fs/cgroupoverlay150G22G129G15%/var/lib/docker/overlay2/9fbd33d3485f02eadef6907a5b4eaead4a384684b66c572d822a2942a82ca0d5/merged
overlay150G22G129G15%/var/lib/docker/overlay2/85ff22ccaf2db68a0a863bc404d79d72fa6c8744424f50ba8fb6bfa83d56b56a/merged
tmpfs199M0199M0%/run/user/0┌──[root@liruilongs.github.io]-[~/python_demo]└─$df-h|./filein.py脚本输出文件系统容量
已用可用已用%挂载点脚本输出/dev/sda1150G22G129G15%/脚本输出devtmpfs983M0983M0%/dev脚本输出tmpfs993M0993M0%/dev/shm脚本输出tmpfs
993M17M976M2%/run脚本输出tmpfs993M0993M0%/sys/fs/cgroup脚本输出overlay150G22G129G15%/var/lib/docker/overlay2/9fbd33d3485f02eadef6907a5b4eaead4a384684b66c572d822a2942a82ca0d5/merged
脚本输出overlay150G22G129G15%/var/lib/docker/overlay2/85ff22ccaf2db68a0a863bc404d79d72fa6c8744424f50ba8fb6bfa83d56b56a/merged
脚本输出tmpfs199M0199M0%/run/user/0┌──[root@liruilongs.github.io]-[~/python_demo]└─$fileinput.input() 创建并返回一个
FileInput类的实例,该实例可以被当做一个上下文管理器使用因此,整合起来,如果我们要写一个打印多个文件输出的脚本,那么我们需要在输出中包含文件名和行号>>> import fileinput >>
> with fileinput.input(“/etc/passwd”) as f: … for line inf: … print(f.filename(),f.fileno(),f.lineno(),line,
end=) … /etc/passwd 31root:x:0:0:root:/root:/bin/bash /etc/passwd 32bin:x:1:1:bin:/bin:/sbin/nologin
/etc/passwd 33daemon:x:2:2:daemon:/sbin:/sbin/nologin /etc/passwd 34adm:x:3:4:adm:/var/adm:/sbin/nologin
/etc/passwd 35lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin /etc/passwd 36sync:x:5:0:sync:/sbin:/bin/sync
执行外部命令并获取它的输出「你想执行一个外部命令并以 Python 字符串的形式获取执行结果」使用subprocess.check_output()函数#!/usr/bin/env python3# -*- encoding: utf-8 -*-
import subprocess out_bytes = subprocess.check_output([netstat,-a]) out_text = out_bytes.decode(utf-8
) print(out_text) 执行下试试┌──[root@liruilongs.github.io]-[~/python_demo]└─$./py_sh.pyActiveInternetconnections
(serversandestablished)ProtoRecv-QSend-QLocalAddressForeignAddressStatetcp00localhost:23790.0.0.0:*LISTEN
tcp00vms55.rhce.cc:23790.0.0.0:*LISTENtcp00localhost:23800.0.0.0:*LISTENtcp00vms55.rhce.cc:23800.0.0.0
:*LISTENtcp000.0.0.0:webcache0.0.0.0:*LISTENtcp000.0.0.0:http0.0.0.0:*LISTEN如果被执行的命令以非零码返回,就会抛出异常下面的例子捕获到错误并获取返回码:。
try: out_bytes = subprocess.check_output([cmd,arg1,arg2]) except subprocess.CalledProcessError as
e: out_bytes = e.output # Output generated before error code = e.returncode # Return code默认情况下,
check_output() 仅仅返回输入到标准输出的值如果你需要同时收集标准输出和错误输出,使用stderr参数:out_bytes = subprocess.check_output([cmd,arg1
,arg2],stderr=subprocess.STDOUT) 如果你需要用一个超时机制来执行命令,使用 timeout 参数:try: out_bytes = subprocess.check_output([
cmd,arg1,arg2], timeout=5) except subprocess.TimeoutExpired as e: …. 通常来讲,命令的执行不需要使用到底层 shell 环境(比如 sh、bash)
一个字符串列表会被传递给一个低级系统命令,比如 os.execve() 如果你想让命令被一个shell 执行,传递一个字符串参数,并设置参数 shell=True . 有时候你想要Python去执行一个复杂的。
shell 命令的时候这个就很有用了,比如管道流、I/O 重定向和其他特性例如:out_bytes = subprocess.check_output(grep python | wc > out, shell=
True) 是在 shell 中执行命令会存在一定的安全风险,特别是当参数来自于用户输入时这时候可以使用 shlex.quote() 函数来将参数正确的用双引用引起来使用 check_output() 函数。
是执行外部命令并获取其返回值的最简单方式但是,如果你需要对子进程做更复杂的交互,比如给它发送输入,你得采用另外一种方法这时候可直接使用subprocess.Popen类#!/usr/bin/env python3。
# -*- encoding: utf-8 -*-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) 关于子进程,简单来看下┌──[root@liruilongs.github.io]-[~/python_demo]
└─$(pwd;echo$BASH_SUBSHELL;ps–forest)/root/python_demo1PIDTTYTIMECMD9324pts/000:00:00bash49906pts/000
:00:00\_bash49907pts/000:00:00\_ps┌──[root@liruilongs.github.io]-[~/python_demo]└─$pwd;echo$BASH_SUBSHELL;ps
–forest/root/python_demo0PIDTTYTIMECMD9324pts/000:00:00bash49908pts/000:00:00\_ps┌──[root@liruilongs.github.io]-[~/python_demo]
└─$也可以进程列表同协程结合的方式你既可以在子shell中 进行繁重的处理工作,同时也不会让子shell的I/O受制于终端┌──[root@liruilongs.github.io]-[~/python_demo]。
└─$coproc (sleep 10;ps –forest;sleep 10;ps –forest) [1] 50326 ┌──[root@liruilongs.github.io]-[~/python_demo]
└─$jobs[1]+ 运行中 coproc COPROC ( sleep 10; ps –forest; sleep 10; ps –forest ) & 如果直接丢到后台会自动在终端输出IO
┌──[root@liruilongs.github.io]-[~/python_demo]└─$(sleep10;ps–forest;sleep10;ps–forest)&[1]50335┌──[root@liruilongs.github.io]-[~/python_demo]
└─$ps–forestPIDTTYTIMECMD9324pts/000:00:00bash50335pts/000:00:00\_bash50336pts/000:00:00|\_sleep50337
pts/000:00:00\_ps┌──[root@liruilongs.github.io]-[~/python_demo]└─$PIDTTYTIMECMD9324pts/000:00:00bash50335
pts/000:00:00\_bash50340pts/000:00:00\_ps[1]+完成(sleep10;ps–forest;sleep10;ps–forest)┌──[root@liruilongs.github.io]-[~/python_demo]
└─$subprocess 模块对于依赖 TTY 的外部命令不合适用例如,你不能使用它来自动化一个用户输入密码的任务(比如一个 ssh 会话)这时候,你需要使用到第三方模块了,比如基于著名的 expect 家族的工具(pexpect 或类似的)(pexpect可以理解为Linux下的expect的Python封装、通过pexpect可以实现对ssh、ftp、passwd、telnet等命令行进行自动交互,而无需人工干涉来达到自动化的目的。
比如我们可以模拟一个FTP登录时所有交互,包括输入主机地址、用户名、密码、上传文件等,待出现异常还可以进行尝试自动处理)终止程序并给出错误信息「你想向标准错误打印一条消息并返回某个非零状态码来终止程序运行」
通过 python的raise SystemExit(3)命令可以主动抛出一个错误,通过sys.stderr.write将命令写到标准的输出端#!/usr/bin/env python3import sys sys.stderr.write(
It failed!\n) raise SystemExit(3) ┌──[root@liruilongs.github.io]-[~/python_demo] └─$vim err.py ┌──[root@liruilongs.github.io]-[~/python_demo] └─$./err.py It failed! ┌──[root@liruilongs.github.io]-[~/python_demo] └─$echo $?
3直接将消息作为参数传给SystemExit(),那么你可以省略其他步骤#!/usr/bin/env python3raise SystemExit(It failed!) 抛出一个 SystemExit
异常,使用错误消息作为参数,它会将消息在sys.stderr中打印,然后程序以状态码1退出┌──[root@liruilongs.github.io]-[~/python_demo] └─$./err.py It failed! ┌──[root@liruilongs.github.io]-[~/python_demo] └─$echo $?
1获取终端的大小「你需要知道当前终端的大小以便正确的格式化输出」使用 os.get terminal size() 函数来做到这一点#!/usr/bin/env python3# -*- encoding: utf-8 -*-。
import os sz = os.get_terminal_size() print(sz) print(sz.columns) print(sz.lines) ┌──[root@liruilongs.github.
io]-[~/python_demo] └─$./tim.py os.terminal_size(columns=99, lines=30) 9930 ┌──[root@liruilongs.github.
io]-[~/python_demo] └─$./tim.py os.terminal_size(columns=165, lines=30) 16530 ┌──[root@liruilongs.github.
io]-[~/python_demo] └─$ 复制或者移动文件和目录「复制或移动文件和目录,但是又不想调用 shell 命令」shutil 模块有很多便捷的函数可以复制文件和目录使用起来非常简单#!/usr/bin/env python3
# -*- encoding: utf-8 -*-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) 这里不多讲,熟悉Linux的小伙伴应该不陌生默认情况下,对于符号链接这些命令处理的是它指向的东西文件例如,如果源文件是一个符号链接,那么目标文件将会是符号链接
指向的文件如果你只想复制符号链接本身,那么需要指定关键字参数 follow_symlinksshutil.copytree(src, dst, symlinks=True) copytree() 可以让你在复制过程中选择性的忽略某些文件或目录。
你可以提供一个忽略函数,接受一个目录名和文件名列表作为输入,返回一个忽略的名称列表例如:defignore_pyc_files(dirname, filenames):return [name in filenames
if name.endswith(.pyc)] shutil.copytree(src, dst, ignore=ignore_pyc_files) 对于文件元数据信息,copy2() 这样的函数只能尽自己最大能力来保留它。
访问时间、创建时间和权限这些基本信息会被保留,但是对于所有者、ACLs、资源 fork 和其他更深层次的文件元信息就说不准了通常不会去使用 shutil.copytree() 函数来执行系统备份当处理文件名的时候,最好使用。
os.path中的函数来确保最大的可移植性>>> filename = /etc/docker/daemon.json>>> import os.path >>> os.path.basename(filename)
daemon.json>>> os.path.dirname(filename) /etc/docker>>> os.path.split(filename) (/etc/docker, daemon.json
) >>> os.path.join(/new/dir, os.path.basename(filename)) /new/dir/daemon.json>>> os.path.expanduser(~/guido/programs/daemon.json
) /root/guido/programs/daemon.json>>> 使用copytree()复制文件夹的一个棘手的问题是对于错误的处理,可以使用异常块处理,或者通过 参数 ignore dangling symlinks=True
忽略掉无效符号链接try: shutil.copytree(src, dst) except shutil.Error as e: for src, dst, msg in e.args[。
0]: # src is source name# dst is destination name# msg is error message from exception print(dst, src, msg)
创建和解压归档文件「创建或解压常见格式的归档文件(比如.tar, .tgz 或.zip)」shutil 模块拥有两个函数—— make archive() 和 unpack archive() 可派上用场,
>>> import shutil >>> shutil.unpack_archive(Python-3.3.0.tgz) >>> shutil.make_archive(py33,zip,Python-3.3.0
) /Users/beazley/Downloads/py33.zipmake archive() 的第二个参数是期望的输出格式可以使用get archive formats()获取所有支持的归档格式列表。
>>> import shutil >>> shutil.get_archive_formats() [(bztar, “bzip2ed tar-file”), (gztar, “gziped tar-file”
), (tar, uncompressed tar file), (xztar, “xzed tar-file”), (zip, ZIP file)] >>> 通过文件名查找文件「你需要写一个涉及到文件查找操作的脚本,比如对日志归档文件的重命名工具,你不想在 Python 脚本中调用 shell,或者你要实现一些 shell 不能做的功能。
」查找文件,可使用 os.walk() 函数,传一个顶级目录名给它#!/usr/bin/env python3 import os,sys def findfile(start, name):
for relpath, dirs, files inos.walk(start): if name in files: full_path = os.path.join(start, relpath, name)
print(os.path.normpath(os.path.abspath(full_path))) if __name__ == __main__: findfile(sys.argv[1
], sys.argv[2]) os.walk() 方法为我们遍历目录树,每次进入一个目录,它会返回一个三元组,包含相对于查找目录的相对路径,一个该目录下的目录名列表,以及那个目录下面的文件名列表┌──[root@liruilongs.github.io]-[~/python_demo] └─$.。
/find.py /etc/ passwd /etc/passwd /etc/pam.d/passwd ┌──[root@liruilongs.github.io]-[~/python_demo] └─$
对于每个元组,只需检测一下目标文件名是否在文件列表中如果是就使用os.path.join() 合并路径为了避免奇怪的路径名比如 ././foo//bar ,使用了另外两个函数来修正结果第一个是os.path.abspath()。
, 它接受一个路径,可能是相对路径,最后返回绝对路径第二个是os.path.normpath(),用来返回正常路径,可以解决双斜杆、对目录的多重引用的问题等os.walk(start)还有跨平台的优势并且,还能很轻松的加入其他的功能。
我们再演示一个例子,下面的函数打印所有最近被修改过的文件:#!/usr/bin/env python3 import os import time import sys def modified_within(top, seconds): now =
time.time() forpath, dirs, files inos.walk(top): for name in files: fullpath =
os.path.join(path, name) ifos.path.exists(fullpath): mtime = os.path.getmtime(fullpath)
if mtime > (now – seconds): print(fullpath) if __name__ == __main__: iflen(sys.argv) !=
3: print(Usage: {} dir seconds.format(sys.argv[0])) raise SystemExit(1) modified_within(sys.argv[
1], float(sys.argv[2])) 打印10分钟之前被修改的数据┌──[root@liruilongs.github.io]-[~/python_demo]└─$./find.py/etc/
10/etc/mtab┌──[root@liruilongs.github.io]-[~/python_demo]└─$ll/etc/mtablrwxrwxrwx.1rootroot1710月182018
/etc/mtab->/proc/self/mounts┌──[root@liruilongs.github.io]-[~/python_demo]└─$ll/proc/self/mounts-r–r–r–
1rootroot05月201:18/proc/self/mounts┌──[root@liruilongs.github.io]-[~/python_demo]└─$读取配置文件「怎样读取普通.ini 格式的配置文件?」
configparser 模块能被用来读取配置文件编写配置文件; config.ini ; Sample configuration file [installation] library=%(prefix)s/lib include=%(prefix)s/
include bin=%(prefix)s/bin prefix=/usr/local # Setting related to debug configuration [debug] log_errors=true show_warnings=False [server]
port: 8080nworkers: 32 pid-file=/tmp/spam.pid root=/www/root signature: ================================= Brought to you by the Python Cookbook =================================
>>> from configparser import ConfigParser >>> cfg = ConfigParser() >>> cfg.read(config.ini) [config.ini
] >>> cfg.sections() [installation, debug, server] >>> cfg.get(installation,library) /usr/local/lib>>
> cfg.getboolean(debug,log_errors) True >>> cfg.getint(server,port) 8080>>> cfg.getint(server,nworkers
) 32>>> print(cfg.get(server,signature)) ================================= Brought to you by the Python Cookbook =================================
>>> 如果有需要,你还能修改配置并使用cfg.write()方法将其写回到文件中>>> from configparser import ConfigParser >>> cfg = ConfigParser()
>>> cfg.read(config.ini) [config.ini] >>> cfg.set(server,port,9000) >>> cfg.set(debug,log_errors,False
) >>> import sys >>> cfg.write(sys.stdout) [installation] library = %(prefix)s/lib include = %(prefix)
s/include bin = %(prefix)s/bin prefix = /usr/local [debug] log_errors = False show_warnings = False [server] port =
9000 nworkers = 32 pid-file = /tmp/spam.pid root = /www/root signature = ================================= Brought to you by the Python Cookbook =================================
>>> 配置文件中的名字是不区分大小写解析值的时候,getboolean() 方法查找任何可行的值ConfigParser 能一次读取多个配置文件然后合并成一个配置后面读取的配置文件会覆盖前面的配置文件。
给简单脚本增加日志功能「你希望在脚本和程序中将诊断信息写入日志文件」python 脚本打印日志最简单方式是使用 logging 模块#`!/usr/bin/env python3# -*- encoding: utf-8 -*-。
import logging def main(): # Configure the logging system logging.basicConfig(filename=app.log
, level=logging.ERROR) # Variables (to make the calls that follow work) hostname =
www.python.org item = spam filename = data.csv mode = r# Example logging calls (insert into your program)
logging.critical(Host %s unknown, hostname) logging.error(“Couldnt find %r”, item) logging.warning(
Feature is deprecated) logging.info(Opening file %r, mode=%r, filename, mode) logging.debug(Got here
) if __name__ == __main__: main() 五个日志调用(critical(), error(), warning(), info(), debug()
)以降序方式表示不同的严重级别 basicConfig() 的level参数是一个过滤器所有级别低于此级别的日志消息都会被忽略掉每个logging操作的参数是一个消息字符串,后面再跟一个或多个参数构造最终的日志消息的时候我们使用了。
% 操作符来格式化消息字符串┌──[root@liruilongs.github.io]-[~/python_demo] └─$./logger.py ┌──[root@liruilongs.github.io]-[~/python_demo] └─$cat app.log CRITICAL:root:Host www.python.org unknown ERROR:root:Couldn。
t find spam ┌──[root@liruilongs.github.io]-[~/python_demo] └─$ 如果你想使用配置文件,可以像下面这样修改basicConfig()调用:import
logging import logging.config defmain():# Configure the logging system logging.config.fileConfig(
logconfig.ini) logconfig.ini[loggers]keys=root [handlers]keys=defaultHandler [formatters]keys=defaultFormatter
[logger_root]level=INFO handlers=defaultHandler qualname=root [handler_defaultHandler]class=FileHandler
formatter=defaultFormatter args=(app.log, a) [formatter_defaultFormatter]format=%(levelname)s:%(name)s:%(message)s
在调用日志操作前先执行下 basicConfig() 函数方法,可以找标准输出或者文件中输出basicConfig() 在程序中只能被执行一次如果你稍后想改变日志配置,就需要先获取 root logger。
,然后直接修改它logging.getLogger().level = logging.DEBUG 更多见日志模块文档https://docs.python.org/3/howto/logging-cookbook.html。
给函数库增加日志功能「你想给某个函数库增加日志功能,但是又不能影响到那些不使用日志功能的程序」对于想要执行日志操作的函数库,你应该创建一个专属的logger对象,并且像下面这样初始化配置:#!/usr/bin/env python3 # -*- encoding: utf。
-8 -*- import logging log = logging.getLogger(__name__) log.addHandler(logging.NullHandler()) # Example
function(for testing) def func(): log.critical(A Critical Error!) log.debug(A debug message) func()
使用这个配置,默认情况下不会打印日志,只有配置过日志系统,那么日志消息打印就开始生效logging.basicConfig() ┌──[root@liruilongs.github.io]-[~/python_demo] └─$./logg.py CRITICAL:__main__:A Critical Error!
通常来讲,不应该在函数库代码中自己配置日志系统,或者是已经有个已经存在的日志配置了调用getLogger( name )创建一个和调用模块同名的 logger 模块由于模块都是唯一的,因此创建的 logger 也将是唯一。
的所以当前进程中只有一个logging会生效log.addHandler(logging.NullHandler()) 操作将一个空处理器绑定到刚刚已经创建好的 logger 对象上一个空处理器默认会忽略调用所有的日志消息。
因此,如果使用该函数库的时候还没有配置日志,那么将不会有消息或警告出现在这里,根日志被配置成仅仅输出 ERROR 或更高级别的消息不过,somelib 的日志级别被单独配置成可以输出 debug 级别的消息,。
它的优先级比全局配置高像这样更改单独模块的日志配置对于调试来讲是很方便的,因为你无需去更改任何的全局日志配置——只需要修改你想要更多输出的模块的日志等级(这个还有待研究)实现一个计时器「你想记录程序执行多个任务所花费的时间」。
time 模块包含很多函数来执行跟时间有关的函数尽管如此,通常我们会在此基础之上构造一个更高级的接口来模拟一个计时器#!/usr/bin/env python3# -*- encoding: utf-8 -*-。
import time classTimer:def__init__(self, func=time.perf_counter): self.elapsed = 0.0self._func = func
self._start = None defstart(self): ifself._start is notNone: raise RuntimeError(
Already started) self._start = self._func() defstop(self): ifself._start is None:
raise RuntimeError(Not started) end = self._func() self.elapsed += end –
self._start self._start = None defreset(self): self.elapsed = 0.0 @property
#类的属性私有化,那么可以使用@property 使属性可以被外部访问并修改defrunning(self): returnself._start is not None def
__enter__(self): self.start() returnselfdef__exit__(self, *args): self.stop()
这个类定义了一个可以被用户根据需要启动、停止和重置的计时器它会在elapsed 属性中记录整个消耗时间下面是一个例子来演示怎样使用它:#!/usr/bin/env python3# -*- encoding: utf-8 -*-。
import time classTimer:def__init__(self, func=time.perf_counter): self.elapsed = 0.0self._func = func
self._start = None defstart(self): ifself._start is notNone: raise RuntimeError(
Already started) self._start = self._func() defstop(self): ifself._start is None:
raise RuntimeError(Not started) end = self._func() self.elapsed += end –
self._start self._start = None defreset(self): self.elapsed = 0.0 @property
#类的属性私有化,那么可以使用@property 使属性可以被外部访问并修改defrunning(self): returnself._start is not None def
__enter__(self): self.start() returnselfdef__exit__(self, *args): self.stop()
defcountdown(n): while n > 0: n -= 1# Use 1: Explicit start/stop t = Timer() t.start() countdown(
1000000) t.stop() print(t.elapsed) # Use 2: As a context manager with t: countdown(1000000) print(t.elapsed) with Timer() as
t2: countdown(1000000) print(t2.elapsed) 这里通过__enter__,__exit__ ,使用with 语句以及上下文管理器协议可以省略计时器打开和关闭操作。
(关于上下文管理协议,即with语句,为了让一个对象兼容with语句,必须在这个对象的类中声明__enter__和__exit__方法,,__enter__在出现with语句被调用,__exit__在代码执行完毕被调用,可以参考open()方法)
┌──[root@liruilongs.github.io]-[~/python_demo]└─$./times.py0.051916488002461850.120386167003744050.06592946800083155
在计时中要考虑一个底层的时间函数问题 一般来说, 使用 time.time()或time.clock()计算的时间精度因操作系统的不同会有所不同而使用time.perf_counter() 函数可以确保使用系统上面。
最精确的计时器限制脚本的内存和CPU的使用量「你想对在 Unix 系统上面运行的程序设置内存或 CPU 的使用限制」cpu 限制resource 模块能同时执行这两个任务例如,要限制 CPU 时间,下面的代码在windows平台执行不了,但是Linux是可以的。
#!/usr/bin/env python3# -*- encoding: utf-8 -*-import signal import resource import os deftime_exceeded
(signo, frame): print(“Times up!”) raise SystemExit(1) defset_max_runtime(seconds):# 安装信号处理程序并设置资源限制
soft, hard = resource.getrlimit(resource.RLIMIT_CPU) # 限制CUP使用时间为15秒 resource.setrlimit(resource.RLIMIT_CPU, (seconds, hard))
# 进程即将结束,给一个信号量,加一个回调 signal.signal(signal.SIGXCPU, time_exceeded) if __name__ == __main__: set_max_runtime(
15) whileTrue: pass程序运行时,SIGXCPU 信号在时间过期时被生成,然后执行清理并退出┌──[root@liruilongs.github.io]-[~/python_demo] └─$vim cpu.py ┌──[root@liruilongs.github.io]-[~/python_demo] └─$chmod +x cpu.py ┌──[root@liruilongs.github.io]-[~/python_demo] └─$./cpu.py Time。
s up! 内存限制这暂时没有好的Demo…#!/usr/bin/env python3# -*- encoding: utf-8 -*-import resource deflimit_memory
(maxsize): soft, hard = resource.getrlimit(resource.RLIMIT_AS) resource.setrlimit(resource.RLIMIT_AS, (maxsize, hard))
# 0.5 * 1024 ^ 6 = 576460752303423488 设置最大内存500M limit_memory(576460752303423488) 程序运行到没有多余内存时会抛出 MemoryError 异常。
setrlimit() 函数被用来设置特定资源上面的软限制和硬限制软限制是一个值,当超过这个值的时候操作系统通常会发送一个信号来限制或通知该进程.>>> resource.RLIMIT_AS 9硬限制是用来指定软限制能设定的最大值。
通常来讲,这个由系统管理员通过设置系统级参数来决定尽管硬限制可以改小一点,但是最好不要使用用户进程去修改>>> resource.getrlimit(resource.RLIMIT_AS) (-1, -1
) setrlimit() 函数还能被用来设置子进程数量、打开文件数以及类似系统资源的限制(cgroup)启动一个WEB浏览器「通过脚本启动浏览器并打开指定的 URL 网页」webbrowser 模块能被用来启动一个浏览器,并且与平台无关
Windows PowerShell 版权所有 (C) Microsoft Corporation保留所有权利 尝试新的跨平台 PowerShell https://aka.ms/pscore6 PS 。
E:\docker> python Python 3.9.0 (tags/v3.9.0:9cf6752, Oct 52020, 15:23:07) [MSC v.192732 bit (Intel)] on win32 Type
“help”, “copyright”, “credits”or”license”for more information. >>> >>> import webbrowser >>> webbrowser.open(
http://www.python.org) True >>> 新窗口打卡网站webbrowser.open_new(http://www.python.org) 当前窗口打开一个tab页webbrowser
.open_new_tab(http://www.python.org) 指定浏览器类型,可以使用 webbrowser.get() 函数>>> c = webbrowser.get(firefox)
>>> c.open(http://www.python.org) True >>> c.open_new_tab(http://docs.python.org) True >>>
2. 分享目的仅供大家学习和交流,您必须在下载后24小时内删除!
3. 不得使用于非法商业用途,不得违反国家法律。否则后果自负!
4. 本站提供的源码、模板、插件等等其他资源,都不包含技术服务请大家谅解!
5. 如有链接无法下载、失效或广告,请联系管理员处理!
6. 本站资源售价只是赞助,收取费用仅维持本站的日常运营所需!
7. 如遇到加密压缩包,请使用WINRAR解压,如遇到无法解压的请联系管理员!
8. 精力有限,不少源码未能详细测试(解密),不能分辨部分源码是病毒还是误报,所以没有进行任何修改,大家使用前请进行甄别
丞旭猿论坛
暂无评论内容