Python对Linux系统的管理
一、OS模块常用功能
1、os模块打开文件
方法如下:
os.open(filename, flag, [,mode])
flag参数说明:
os.O_CREAT # 创建文件
os.O_RDONLY # 只读方式打开
os.O_WRONLY # 只写方式打开
os.O_RDWR # 读写方式打开
2、os模块对文件进行操作
常用方法如下:
# 读取文件
os.read(fd, buffersize)
# 写入文件
os.write(fd, string)
# 文件指针操作
os.lseek(fd, pos, how)
# 关闭文件
os.close(fd)
代码演示:
文件创建和写入
import os
# 打开文件
fd = os.open("abc.txt", os.O_RDWR | os.O_CREAT)
# 写入字符串
str = "Hello Python!"
ret = os.write(fd, bytes(str, 'UTF-8'))
# 输入返回值
print("写入的位数为: ")
print(ret)
print("写入成功")
# 关闭文件
os.close(fd)
print("关闭文件成功!!")
文件读取
import os
# 打开文件
fd = os.open("abc.txt", os.O_RDWR)
# 读取文本
ret = os.read(fd, 6)
print(ret)
# 关闭文件
os.close(fd)
print("关闭文件成功!!")
3、os模块管理文件和目录
常用方法如下:
os方法 | 说明 |
---|---|
getcwd() | 获取当前目录 |
listdir(path) | 返回当前目录下所有文件组成的列表 |
chdir(path) | 切换目录 |
rename(old, new) | 修改文件或者目录名 |
mkdir(path [,mode]) | 创建目录 |
makedirs(path [,mode]) | 创建多级目录 |
rmdir(path) | 删除目录(目录必须为空目录) |
removedirs(path) | 删除多级目录(目录必须为空目录) |
remove(path) | 删除文件 |
代码演示:
# coding=utf-8
import os
print(os.getcwd()) # pwd
print(os.listdir()) # ls
os.chdir('/opt') # cd /opt
os.rename('abc.txt','test.txt') # mv abc.txt test.txt
os.remove('read.py') # rm -f abc.txt
os.mkdir('test') # mkdir dir1
os.makedirs('demo/abc') # mkdir -p dir2/dir22
os.rmdir('test') # 目录必须为空
os.removedirs('demo') # 目录必须为空
4、os模块管理文件权限
os方法 | 说明 |
---|---|
access(path, mode) | 判断该文件权限:F_OK表示该路径存在; 权限:R_OK,W_OK,X_OK |
chmod(path, mode) | 修改文件权限:0o755 |
chown(path, uid, gid) | 更改文件所有者,如果不修改可以设置为 -1 |
代码演示:
import os
# 测试路径是否存在:os.F_OK
res = os.access('test.txt',os.F_OK)
print(res)
# 测试当前用户对该文件是否有读的权限
res = os.access('test.txt',os.R_OK)
print(res)
# 测试当前用户对该文件是否有写的权限
res = os.access('test.txt',os.W_OK)
print(res)
# 测试当前用户对该文件是否有执行的权限
res = os.access('test.txt',os.X_OK)
print(res)
# 更改当前用户的权限
os.chmod('test.txt',0o755)
# 更改文件的所有者
os.chown('test.txt', 1001, 1002)
5、os.path模块管理文件与路径
(1)拆分路径
os.path方法 | 说明 |
---|---|
os.path.split(path) | 返回一个二元组,包含文件的路径和文件名 |
os.path.dirname(path) | 返回文件的路径 |
os.path.basename(path) | 返回文件名 |
os.path.splitext(path) | 返回一个去掉文件扩展名的部分和扩展名的二元组 |
代码演示:
In [10]: os.getcwd()
Out[10]: '/opt/os_demo'
In [11]: os.listdir()
Out[11]: ['os_access.py', 'test.txt']
In [12]: path = '/opt/os_demo/test.txt'
In [13]: os.path.split(path)
Out[13]: ('/opt/os_demo', 'test.txt')
In [14]: os.path.dirname(path)
Out[14]: '/opt/os_demo'
In [15]: os.path.basename(path)
Out[15]: 'test.txt'
In [16]: os.path.splitext(path)
Out[16]: ('/opt/os_demo/test', '.txt')
(2)构建路径
os.path方法 | 说明 |
---|---|
os.path.expanduser(path) | 展开用户的HOME目录,如 |
os.path.abspath(path) | 得到文件或路径的绝对路径 |
os.path.join(path) | 根据不同的操作系统平台,使用不同的路径分隔符拼接路径 |
os.path.isabs(path) | 检查一个路径是不是一个绝对路径 |
代码演示:
In [19]: os.path.expanduser('~')
Out[19]: '/root'
In [20]: os.path.expanduser('~oracle')
Out[20]: '/home/oracle'
In [21]: os.path.expanduser('~accp')
Out[21]: '/home/accp'
In [22]: os.path.expanduser('~acp')
Out[22]: '~acp' # 错误演示
In [23]: os.path.abspath('.')
Out[23]: '/opt/os_demo'
In [24]: os.path.abspath('..')
Out[24]: '/opt'
In [25]: os.path.join('/opt/os_demo','test.txt')
Out[25]: '/opt/os_demo/test.txt'
In [26]: os.path.isabs('/opt/os_demo/')
Out[26]: True
In [27]: os.path.isabs('.')
Out[27]: False
(3)获取文件属性
os.path方法 | 说明 |
---|---|
os.path.getatime(path) | 返回最近访问时间(浮点型秒数) |
os.path.getmtime(path) | 返回最近文件修改时间 |
os.path.getctime(path) | 返回文件 path 创建时间 |
os.path.getsize(path) | 返回文件大小,如果文件不存在就返回错误 |
代码演示:
In [33]: os.path.getatime(path)
Out[33]: 1587547270.7306058 # 时间戳
In [34]: os.path.getmtime(path)
Out[34]: 1587547270.7306058
In [35]: os.path.getctime(path)
Out[35]: 1587548055.4721448
In [36]: os.path.getsize(path)
Out[36]: 0
(4)判断文件类型
os.path方法 | 说明 |
---|---|
os.path.isfile(path) | 判断路径是否为文件 |
os.path.isdir(path) | 判断路径是否为目录 |
os.path.islink(path) | 判断路径是否为链接 |
os.path.ismount(path) | 判断路径是否为挂载点 |
代码演示:
In [37]: os.path.isfile(path)
Out[37]: True
In [38]: os.path.isdir(path)
Out[38]: False
In [39]: os.path.islink(path)
Out[39]: False
In [40]: os.path.ismount(path)
Out[40]: False
6、os模块执行shell命令
os.system()的作用:
执行shell命令
返回shell命令的返回值
命令的输出会输出到标准输出
代码演示:
os.system(‘cls’)
案例1:编写自动安装Python的脚本
实现步骤:
下载Python版本源码
安装Python需要的依赖库
编译安装Python
伪代码:
1. 判断用户是不是root
2. 如果是,等待用户输入Python版本
3. 执行shell命令下载源码包
4. 安装依赖开发包
5. 编译安装Python
脚本内容如下(基于Python2):
auto_install_python.py
# coding=utf-8
import os
# 判断用户是否是root用户
if os.getuid() == 0:
pass
else:
print
'当前用户不是root用户!'
SystemExit(1)
# 安装Python依赖库
cmd_module = 'yum -y install wget gcc zlib-devel bzip2-devel openssl-devel ncurses-devel sqlite-devel readline-devel tk-devel gdbm-devel db4-devel libpcap-devel xz-devel libffi-devel'
res = os.system(cmd_module)
if res != 0:
print
'Python依赖库安装失败,请重新执行该脚本。'
SystemExit(1)
else:
print
'python依赖库安装成功!'
# 输入Python版本,下载Python源码包到本地目录
# wget url
version = raw_input('请输入Python版本:(3.6/3.8)')
if version == '3.6':
url = 'https://www.python.org/ftp/python/3.6.10/Python-3.6.10.tgz'
else:
url = 'https://www.python.org/ftp/python/3.8.1/Python-3.8.1.tgz'
cmd = 'wget ' + url
res = os.system(cmd)
if res != 0:
print 'Python源码包下载失败!'
SystemExit(1)
else:
print('======================>>>Python源码包下载成功!')
# 解压Python源码包
# tar zxvf Python-3.6.10.tgz
if version == '3.6':
package_name = 'Python-3.6.10'
else:
package_name = 'Python-3.8.1'
res = os.system('tar zxvf ' + package_name + '.tgz')
if res != 0:
print '解压失败。。。'
SystemExit(1)
else:
print('#########################解压成功!#########################')
# 配置语言
os.system('export LANG=zh_CN.UTF-8')
os.system('export LANGUAGE=zh_CN.UTF-8')
# 切换到Python目录
os.chdir(package_name)
os.system('./configure --prefix=/usr/local/python3')
res = os.system('make && make install')
if res !=0:
print '源码编译失败。。。'
SystemExit(1)
else:
print('####################Python安装成功,请进行验证!####################')
# 修改用户环境变量
os.system('echo "export PYTHON3=/usr/local/python3" >>~/.bash_profile')
os.system('echo "export PATH=$PYTHON3/bin:$PATH" >>~/.bash_profile')
os.system("source ~/.bash_profile")
os.system('cat ~/.bash_profile')
print('####################用户环境变量已修改,请进行验证!####################')
os.system('python3 --version')
7、os.walk函数遍历目录树
os.walk() 方法遍历某个目录及其子目录,对于每一个目录,walk()函数返回一个三元组(dirpath、dirnames、filenames)。其中dirpath保存的是当前目录,dirnames是当前目录下的子目录列表,filenames是当前目录下的文件列表。
# coding=utf-8
import os
for root, dirs, files in os.walk(".", topdown=False):
for name in files:
print(os.path.join(root, name))
for name in dirs:
print(os.path.join(root, name))
os.walk() 方法是一个简单易用的文件、目录遍历器,可以帮助我们高效的处理文件、目录方面的事情。
案例2:打印最常用的10条Linux命令
import os
from collections import Counter
count = Counter()
with open(os.path.expanduser('~/.bash_history')) as f:
for line in f:
cmd = line.strip().split()
if cmd:
count[cmd[0]] +=1
print(count.most_common(10))
二、使用ConfigParser类解析配置文件
Python中有ConfigParser类,可以很方便的从配置文件中读取数据(如DB的配置,路径的配置),所以可以自己写一个函数,实现读取config配置。
1、配置文件的格式
节: [session]
参数(键=值) name=value
mysql配置文件部分内容如下:
[client]
port = 3306
user = mysql
password = mysql
host = 127.0.0.1
[mysqld]
basedir = /usr
datadir = /var/lib/mysql
tmpdir = /tmp
skip-external-locking
2、ConfigParser类的使用方法
(1)创建configParser对象
In [1]: import configparser
In [2]: cf = configparser.ConfigParser(allow_no_value=True)
(2)读取配置文件内容
In [3]: cf.read('my.inf')
Out[3]: ['my.ini']
(3)获取配置文件信息
sections: 返回一个包含所有章节的列表
options:返回一个包含章节下所有选项的列表
has_section:判断章节是否存在
has_options:判断某个选项是否存在
items:以元组的形式返回所有的选项
get、getboolean、getint、getfloat:获取选项的值
方法测试:
In [4]: cf.sections()
Out[4]: ['client', 'mysqld']
In [5]: cf.has_section('client')
Out[5]: True
In [6]cf.options('client')
Out[6]: ['port', 'user', 'password', 'host']
In [7]: cf.has_option('client','user')
Out[7]: True
In [8]: cf.get('client','port')
Out[8]: '3306'
In [9]: cf.getint('client','port')
Out[9]: 3306
(4)修改配置文件
常用方法:
remove_section:删除一个章节
add_section:添加一个章节
remove_option:删除一个选项
set:添加一个选项
write:将ConfigParser兑现中的数据保存到文件中
方法测试:
In [11]: cf.remove_section('client')
Out[11]: True
In [12]: cf.write(open('my.ini', 'w'))
In [13]: cf.add_section('client')
In [14]: cf.set('client','port','3306')
In [15]: cf.set('client','user','mysql')
In [16]: cf.set('client','password','mysql')
In [17]: cf.set('client','host','127.0.0.1')
In [18]: cf.write(open('my.ini','w'))
In [19]: cf.remove_option('client','host')
Out[19: True
In [20]: cf.write(open('my.ini','w'))
三、查找文件
1、使用fnmatch找到特定文件
fnmatch.fnmatch()函数一次只能处理一个文件
import os
import fnmatch
for item in os.listdir('.'):
if os.path.isfile(item):
# if fnmatch.fnmatch(item, '*.jpg'):
if fnmatch.fnmatch(item, '[a-e]*'):
# if fnmatch.fnmatch(item, '[a-g]?.txt'):
# if fnmatch.fnmatch(item, '[!a-c]*'):
print(item)
fnmatch.filter()函数一次可以处理多个文件
import os
import fnmatch
items = os.listdir('.')
files = fnmatch.filter(items, '[a-c]*')
print(files)
2、使用glob找到特定文件
标准库glob的作用相当于os.listdir()加上fnmatch。使用glob以后,不需要调用os.listdir()获取文件列表,直接通过模式匹配即可。如下所示:
import glob
files = glob.glob('*.jpg')
print(files)
案例3:找到目录下最大(或最老)的10个文件
四、高级文件处理接口shutil
1、复制文件和文件夹
shutil.copy(file1,file2)
shuti.copytree(dir1, dir2)
2、文件和文件夹的移动与重命名
shutil.move(file1, file2)
shutil.move(file, dir)
3、删除目录
shutil.rmtree(dir)
os.unlink(file)
五、文件内容管理
1、目录和文件对比
filecmp模块包含了比较目录和文件的操作。
目录结构如下,其中,a.txt和c.txt内容是一样的,a_copy.txt是a.txt的拷贝。
├─dir1
│ │ a.txt
│ │ a_copy.txt
│ │ b.txt
│ │ c.txt
│ └─subdir1
│ sa.txt
└─dir2
│ a.txt
│ b.txt
│ c.txt
├─subdir1
│ sb.txt
└─subdir2
(1)比较两个文件
使用filecmp模块的cmp函数比较两个文件是否相同,如果文件相同则返回True,否则返回False。
In [1]: import filecmp
In [2]: cd dir1
E:\git-project\python_project\cloud33\Python常用模块\compare\dir1
In [3]: filecmp.cmp('a.txt','b.txt')
Out[3]: False
In [4]: filecmp.cmp('a.txt','c.txt')
Out[4]: True
In [5]: filecmp.cmp('a.txt','a_copy.txt')
Out[5]: True
(2)比较多个文件
filecmp目录下还有一个名为cmpfiles的函数,该函数用来同时比较两个不同的目录下的多个文件,并且返回一个三元组,分别包含相同的文件、不同的文件和无法比较的文件。示例如下:
In [6]: filecmp.cmpfiles('dir1','dir2',['a.txt','b.txt','c.txt','a_copy.txt'])
Out[6]: (['a.txt', 'b.txt', 'c.txt'], [], ['a_copy.txt'])
cmpfiles函数同时用来比较两个目录下的文件,也可以使用该函数比较两个目录。但是,在比较两个目录时,需要通过参数指定可能的文件,因此比较繁琐。
(3)比较目录
filecmp中还有一个名为dircmp的函数,用来比较两个目录。调用dircmp函数以后,会返回一个dircmp类的对象,该对象保存了诸多属性,我们可以通过查看这些属性获取目录之间的差异。如下所示:
In [7]: d = filecmp.dircmp('dir1','dir2')
In [8]: d.report()
diff dir1 dir2
Only in dir1 : ['a_copy.txt']
Only in dir2 : ['subdir2']
Identical files : ['c.txt']
Differing files : ['a.txt', 'b.txt']
Common subdirectories : ['subdir1']
In [9]: d.left_list
Out[9]: ['a.txt', 'a_copy.txt', 'b.txt', 'c.txt', 'subdir1']
In [10]: d.right_list
Out[10]: ['a.txt', 'b.txt', 'c.txt', 'subdir1', 'subdir2']
In [11]: d.left_only
Out[11]: ['a_copy.txt']
In [12]: d.right_only
Out[12]: ['subdir2']
2、MD5校验和比较
校验码是通过散列函数计算而成,是一种从任何数据中创建小的数字“指纹”的方法。散列函数把消息或数据压缩成摘要,使得数据量变小,便于进行比较。MD5是目前使用最广泛的散列算法。
MD5哈希一般用于检查文件的完整性,尤其常用于检查文件传输、磁盘错误或其他情况下文件的正确性。
Linux下计算一个文件的MD5校验码,如下所示:
[root@192 demo]# md5sum a.txt
d41d8cd98f00b204e9800998ecf8427e a.txt
在Python中计算文件的MD5校验码也非常简单,使用标准库hashlib模块即可。如下所示:
import hashlib
d = hashlib.md5()
with open('b.txt') as f:
for line in f:
d.update(line.encode('utf-8'))
print(d.hexdigest())
# 或者可以这样(最常见的写法,常用于图片的命名)
>>> hashlib.md5(b'123').hexdigest()
'202cb962ac59075b964b07152d234b70'
# 也可以使用hash.new()这个一般方法,hashlib.new(name[, data]),name传入的是哈希加密算法的名称,如md5
>>> hashlib.new('md5', b'123').hexdigest()
'202cb962ac59075b964b07152d234b70'
六、使用Python管理压缩包
1、tarfile
(1)读取tar包
import tarfile
with tarfile.open('cmake-3.17.0.tar.gz') as t:
for member in t.getmembers():
print(member.name)
with tarfile.open('cmake-3.17.0.tar.gz') as t:
t.extractall()
t.extract('cmake-3.17.0/Help','a')
常用方法说明:
getmembers():获取tar包中的文件列表
member.name:获取tar包中文件的文件名
extract(member, path):提取单个文件
extractall(path, memebers):提取所有的文件
(2)创建tar包
import tarfile
with tarfile.open('readme.tar', mode='w') as out:
out.add('read.txt')
(3)读取与创建压缩包
import tarfile
with tarfile.open('tarfile_add.tar',mode='r:gz') as out:
pass
with tarfile.open('tarfile_add.tar',mode='r:bz2') as out:
pass
案例4:备份指定文件到压缩包中
import os
import fnmatch
import tarfile
import datetime
def is_file_math(filename, patterns):
'''查找特定类型的文件'''
for pattern in patterns:
if fnmatch.fnmatch(filename, pattern):
return True
return False
def find_files(root, patterns=['*']):
for root, dirnames, filenames in os.walk(root):
for filename in filenames:
if is_file_math(filename, patterns):
yield os.path.join(root, filename)
patterns = ['*.txt','*.md']
now = datetime.datetime.now().strftime('%Y_%m_%d_%H_%M_%S')
filename = 'backup_all_file_{0}.tar.gz'.format(now)
with tarfile.open(filename, 'w') as f:
for item in find_files('.', patterns):
f.add(item)
2、zipfile
(1)读取zip文件
import zipfile
demo_zip = zipfile.ZipFile('read.zip')
print(demo_zip.namelist())
demo_zip.extractall('1')
demo_zip.extract('a.jpg','2')
常用方法说明:
namelist():返回zip文件中包含的所有文件和文件夹的字符串列表
extract(filename, path):从zip文件中提取单个文件
extractall(path):从zip文件中提取所有文件
(2)创建zip文件
import zipfile
newZip = zipfile.ZipFile('new.zip',mode='w')
newZip.write('a.jpg')
newZip.close()
(3)Python命令行调用zipfile
zipfile模块提供的命令行接口包含的选项:
-l:显示zip格式压缩包中的文件列表
-e:提取zip格式的压缩包
-c:创建zip格式的压缩包
-t:验证文件是不是一个有效的zip格式压缩包
示例如下所示:
# 创建zip文件
python -m zipfile -c new1.zip archive_tar.py
# 查看zip文件列表
python -m zipfile -l new1.zip
File Name Modified Size
archive_tar.py 2020-04-26 16:32:54 239
# 提取zip文件到指定目录
python -m zipfile -e new1.zip new_dir
3、shutil创建和读取压缩包
shutil支持的格式如下:
import shutil
print(shutil.get_archive_formats())
[('bztar', "bzip2'ed tar-file"), ('gztar', "gzip'ed tar-file"), ('tar', 'uncompressed tar file'), ('xztar', "xz'ed tar-file"), ('zip', 'ZIP file')]
(1)创建压缩包
# 参数1:生成的压缩包文件名
# 参数2:压缩包的格式
# 参数3:压缩的目录
shutil.make_archive('a.jpg','gztar', 'ddd')
(2)解压
# 参数1:需要解压的压缩包
# 参数2:解压的目录
print(shutil.unpack_archive('a.jpg.tar.gz','jpg'))
七、Python执行外部命令
1、subprocess模块简介
这个模块用来创建和管理子进程。它提供了高层次的接口,用来替换os.system()、os.spawn*()、os.popen*()、os.popen2.*()和commands.*等模块和函数。
subprocess提供了一个名为Popen的类启动和设置子进程的参数,由于这个类比较复杂,subprosess还提供了若干便利的函数,这些函数都是对Popen类的封装。
2、subprocess模块的便利函数
(1)call
call函数的定义如下
subprocess.call(args, *, stdin=None, stdout=None, stderr=None, shell=False)
示例如下:
In [1]: import subprocess
In [2]: subprocess.call(['ls','-l'])
总用量 8
-rw-------. 1 root root 2049 8月 11 2019 anaconda-ks.cfg
-rw-r--r--. 1 root root 2077 8月 11 2019 initial-setup-ks.cfg
drwxr-xr-x. 2 root root 21 4月 22 16:32 os
drwxr-xr-x. 2 root root 6 8月 11 2019 公共
drwxr-xr-x. 2 root root 6 8月 11 2019 模板
drwxr-xr-x. 2 root root 6 8月 11 2019 视频
drwxr-xr-x. 2 root root 6 8月 11 2019 图片
drwxr-xr-x. 2 root root 6 8月 11 2019 文档
drwxr-xr-x. 2 root root 6 8月 11 2019 下载
drwxr-xr-x. 2 root root 6 8月 11 2019 音乐
drwxr-xr-x. 2 root root 6 8月 11 2019 桌面
Out[2]: 0
In [3]: subprocess.call('exit 1', shell=True)
Out[3]: 1
(2)check_call
check_all函数的作用与call函数类似,区别在于异常情况下返回的形式不同。
对于call函数,工程师通过捕获call命令的返回值判断命令是否执行成功,如果成功则返回0,否则的话返回非0。对于check_call函数,如果执行成功,返回0,如果执行失败,抛出subprocess.CallProseccError异常,示例如下所示:
In [6]: subprocess.check_call(['ls','-l'])
总用量 8
-rw-------. 1 root root 2049 8月 11 2019 anaconda-ks.cfg
-rw-r--r--. 1 root root 2077 8月 11 2019 initial-setup-ks.cfg
drwxr-xr-x. 2 root root 21 4月 22 16:32 os
drwxr-xr-x. 2 root root 6 8月 11 2019 公共
drwxr-xr-x. 2 root root 6 8月 11 2019 模板
drwxr-xr-x. 2 root root 6 8月 11 2019 视频
drwxr-xr-x. 2 root root 6 8月 11 2019 图片
drwxr-xr-x. 2 root root 6 8月 11 2019 文档
drwxr-xr-x. 2 root root 6 8月 11 2019 下载
drwxr-xr-x. 2 root root 6 8月 11 2019 音乐
drwxr-xr-x. 2 root root 6 8月 11 2019 桌面
Out[6]: 0
In [7]: subprocess.check_call('lsljdl', shell=True)
/bin/sh: lsljdl: 未找到命令
---------------------------------------------------------------------------
CalledProcessError Traceback (most recent call last)
<ipython-input-7-885ea94380a9> in <module>
----> 1 subprocess.check_call('lsljdl', shell=True)
/usr/local/python3/lib/python3.8/subprocess.py in check_call(*popenargs, **kwargs)
362 if cmd is None:
363 cmd = popenargs[0]
--> 364 raise CalledProcessError(retcode, cmd)
365 return 0
366
CalledProcessError: Command 'lsljdl' returned non-zero exit status 127.
(3)check_output
In [8]: output = subprocess.check_output(['df','-h'])
In [9]: print(output.decode())
文件系统 容量 已用 可用 已用% 挂载点
/dev/mapper/cl-root 37G 5.1G 32G 14% /
devtmpfs 897M 0 897M 0% /dev
tmpfs 912M 84K 912M 1% /dev/shm
tmpfs 912M 9.0M 903M 1% /run
tmpfs 912M 0 912M 0% /sys/fs/cgroup
/dev/sda1 1014M 173M 842M 18% /boot
tmpfs 183M 16K 183M 1% /run/user/42
tmpfs 183M 0 183M 0% /run/user/0
In [10]: lines = output.decode().split('\n')
In [11]: lines
Out[11]:
['文件系统 容量 已用 可用 已用% 挂载点',
'/dev/mapper/cl-root 37G 5.1G 32G 14% /',
'devtmpfs 897M 0 897M 0% /dev',
'tmpfs 912M 84K 912M 1% /dev/shm',
'tmpfs 912M 9.0M 903M 1% /run',
'tmpfs 912M 0 912M 0% /sys/fs/cgroup',
'/dev/sda1 1014M 173M 842M 18% /boot',
'tmpfs 183M 16K 183M 1% /run/user/42',
'tmpfs 183M 0 183M 0% /run/user/0',
'']
In [12]: for line in lines[1:-1]:
...: if line:
...: print(line.split()[-2])
...: t
14%
0%
1%
1%
0%
18%
1%
0%
3、subprocess模块的Popen类
# coding=utf-8
import subprocess
def execute_cmd(cmd):
p = subprocess.Popen(cmd, shell=True,
stdin=subprocess.PIPE,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE)
stdout, stderr = p.communicate()
if p.returncode != 0:
return p.returncode, stderr
return p.returncode, stdout
execute_cmd('ls')
八、综合案例:使用Python部署MongoDB
看一个综合案例,使用Python不俗MongoDB数据库。在这个例子中,将会用到各种与系统管理相关的标准库,包括os、os.path、shutil、tarfile和subprocess模块。
假设当前目录下存在一个MongoDB安装包,我们的Python程序需要将他解压到当前目录的mongo目录下,并且当前目录创建一个mongodata目录用老保存MongoDB的数据库文件。
在部署MongoDB数据库之前,当前目录下的文件结构如下:
.
├── auto_install_mongodb.py
└── ./mongodb-linux-x86_64-rhel70-4.2.3.tgz
程序部署完成后,当前目录的文件结构大致如下:
.
├── ./auto_install_mongodb.py
├── ./mongo
│ ├── ./mongo/bin
│ │ ├── ./mongo/bin/bsondump
│ │ ├── ./mongo/bin/install_compass
│ │ ├── ./mongo/bin/mongo
│ │ ├── ./mongo/bin/mongod
│ │ ├── ./mongo/bin/mongodump
│ │ ├── ./mongo/bin/mongoexport
│ │ ├── ./mongo/bin/mongofiles
│ │ ├── ./mongo/bin/mongoimport
│ │ ├── ./mongo/bin/mongoreplay
│ │ ├── ./mongo/bin/mongorestore
│ │ ├── ./mongo/bin/mongos
│ │ ├── ./mongo/bin/mongostat
│ │ └── ./mongo/bin/mongotop
│ ├── ./mongo/LICENSE-Community.txt
│ ├── ./mongo/MPL-2
│ ├── ./mongo/README
│ ├── ./mongo/THIRD-PARTY-NOTICES
│ └── ./mongo/THIRD-PARTY-NOTICES.gotools
├── ./mongodata
│ ├── ./mongodata/collection-0-4813754152483353608.wt
│ ├── ./mongodata/collection-2-4813754152483353608.wt
│ ├── ./mongodata/collection-4-4813754152483353608.wt
│ ├── ./mongodata/diagnostic.data
│ │ ├── ./mongodata/diagnostic.data/metrics.2020-04-27T10-17-57Z-00000
│ │ └── ./mongodata/diagnostic.data/metrics.interim
│ ├── ./mongodata/index-1-4813754152483353608.wt
│ ├── ./mongodata/index-3-4813754152483353608.wt
│ ├── ./mongodata/index-5-4813754152483353608.wt
│ ├── ./mongodata/index-6-4813754152483353608.wt
│ ├── ./mongodata/journal
│ │ ├── ./mongodata/journal/WiredTigerLog.0000000001
│ │ ├── ./mongodata/journal/WiredTigerPreplog.0000000001
│ │ └── ./mongodata/journal/WiredTigerPreplog.0000000002
│ ├── ./mongodata/_mdb_catalog.wt
│ ├── ./mongodata/mongod.lock
│ ├── ./mongodata/mongod.log
│ ├── ./mongodata/sizeStorer.wt
│ ├── ./mongodata/storage.bson
│ ├── ./mongodata/WiredTiger
│ ├── ./mongodata/WiredTigerLAS.wt
│ ├── ./mongodata/WiredTiger.lock
│ ├── ./mongodata/WiredTiger.turtle
│ └── ./mongodata/WiredTiger.wt
└── ./mongodb-linux-x86_64-rhel70-4.2.3.tgz
MongoDB下载地址如下:
wget https://fastdl.mongodb.org/linux/mongodb-linux-s390x-rhel72-4.3.3.tgz
MongoDB是当下最流行的文档数据库,具有很好的易用性。启动一个MongoDB数据库实例,只需要执行一下几条shell命令即可:
tar -zxf mongodb-linux-x86_64-rhel70-4.2.3.tgz
mv mongodb-linux-x86_64-rhel70-4.2.3 mongo
mkdir mongodata
mongo/bin/mongod --fork --logpath mongodata/mongod.log --dbpath mongodata
这里给出的shell命令,只是为了便于不熟悉MongoDB的人了解MongoDB数据库的启动过程,还有很多的情况没有考虑。例如,要将当前目录下的MongoDB安装包解压到当前目录下的mongo目录中,但是当前目录下已经存在一个名为mongo的目录,则会报错
下面的程序时使用Python部署MongoDB数据库的完整代码,这段程序综合应用了很多与系统管理相关的模块。如下所示:
# coding=utf-8
import subprocess
import os
import shutil
import tarfile
def execute_cmd(cmd):
'''执行shell命令'''
p = subprocess.Popen(cmd, shell=True,
stdin=subprocess.PIPE,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE)
stdout, stderr = p.communicate()
if p.returncode != 0:
return p.returncode, stderr
return p.returncode, stdout
def unpackage_mongo(package, package_dir):
unpackage_dir = os.path.splitext(package)[0]
if os.path.exists(unpackage_dir):
shutil.rmtree(unpackage_dir)
if os.path.exists(package_dir):
shutil.rmtree(package_dir)
# 解压
t = tarfile.open(package, 'r:gz')
t.extractall('.')
print('tar is ok.')
# 重命名mongodb-linux-x86_64-rhel70-4.2.3为mongo
shutil.move(unpackage_dir, 'mongo')
def create_datadir(data_dir):
if os.path.exists(data_dir):
shutil.rmtree(data_dir)
os.mkdir(data_dir)
def format_mongod_commamd(package_dir, data_dir, logfile):
mongod = os.path.join(package_dir, 'bin', 'mongod')
mongod_format = """{0} --fork --dbpath {1} --logpath {2}"""
return mongod_format.format(mongod, data_dir, logfile)
def start_mongod(cmd):
returncode, out = execute_cmd(cmd)
if returncode != 0:
raise SystemExit('execute {0} error:{1}'.format(cmd, out.decode()))
else:
print('execute {0} sucessfully.'.format(cmd))
def main():
package = 'mongodb-linux-x86_64-rhel70-4.2.3.tgz'
cur_dir = os.path.abspath('.')
package_dir = os.path.join(cur_dir, 'mongo')
data_dir = os.path.join(cur_dir, 'mongodata')
logfile = os.path.join(data_dir, 'mongod.log')
if not os.path.exists(package):
raise SystemExit('{0} not found.'.format(package))
unpackage_mongo(package, package_dir)
create_datadir(data_dir)
start_mongod(format_mongod_commamd(package_dir, data_dir, logfile))
main()
代码说明:
在这段过程中,我们首先在main函数中定义了几个变量,包括当前目录的路径,MongoDB二进制文件所在的路径、MongoDB数据目录所在的路径,以及MongoDB的日志问紧啊
随后,我们判断MongoDB的安装包是否存在,如果不存在,则通过抛出SystemExit异常的方式结束程序
在unpackage_mongo函数中,我们通过Python程序得到MongoDB安装包解压以后的目录。如果目录已经存在,则删除该目录。随后,我们使用tarfile解压MongoDB数据库,解压完成后,将命令重命名为mongo目录
在create_datadir目录红,我们首先判断MongoDB数据库目录是否存在,如果存在,则删除该目录,随后在创建MongoDB数据库目录
在start_mongod函数中,我们执行MongoDB数据库的启动命令启动MongoDB数据库。为了在Python代码中执行shell命令,我们使用了subprocess库,我们将subprocess库执行shell命令的瑞吉封装成execute_cmd函数,在执行shell命令时,直接调用该函数即可