Python 内置模块 之 os、sys、subprocess

时间:2021-01-05 22:39:40

 

OS  用于提供系统级别的操作

官方文档

os.getcwd() 获取当前工作目录,即当前python脚本工作的目录路径
os.chdir(
"dirname") 改变当前脚本工作目录;相当于shell下cd
os.curdir 返回当前目录: (
'.')
os.pardir 获取当前目录的父目录字符串名:(
'..')
os.makedirs(
'dirname1/dirname2') 可生成多层递归目录
os.removedirs(
'dirname1') 若目录为空,则删除,并递归到上一级目录,如若也为空,则删除,依此类推
os.mkdir(
'dirname') 生成单级目录;相当于shell中mkdir dirname
os.rmdir(
'dirname') 删除单级空目录,若目录不为空则无法删除,报错;相当于shell中rmdir dirname
os.listdir(
'dirname') 列出指定目录下的所有文件和子目录,包括隐藏文件,并以列表方式打印
os.remove() 删除一个文件
os.rename(
"oldname","newname") 重命名文件/目录
os.stat(
'path/filename') 获取文件/目录信息
os.sep 输出操作系统特定的路径分隔符,win下为
"\\",Linux下为"/"
os.linesep 输出当前平台使用的行终止符,win下为
"\t\n",Linux下为"\n"
os.pathsep 输出用于分割文件路径的字符串
os.name 输出字符串指示当前使用平台。win
->'nt'; Linux->'posix'
os.system(
"bash command") 运行shell命令,直接显示
os.environ 获取系统环境变量
os.path.abspath(path) 返回path规范化的绝对路径
os.path.split(path) 将path分割成目录和文件名二元组返回
os.path.dirname(path) 返回path的目录。其实就是os.path.split(path)的第一个元素
os.path.basename(path) 返回path最后的文件名。如何path以/或\结尾,那么就会返回空值。即os.path.split(path)的第二个元素
os.path.exists(path) 如果path存在,返回True;如果path不存在,返回False
os.path.isabs(path) 如果path是绝对路径,返回True
os.path.isfile(path) 如果path是一个存在的文件,返回True。否则返回False
os.path.isdir(path) 如果path是一个存在的目录,则返回True。否则返回False
os.path.join(path1[, path2[, ...]]) 将多个路径组合后返回,第一个绝对路径之前的参数将被忽略
os.path.getatime(path) 返回path所指向的文件或者目录的最后存取时间 即 access time
os.path.getctime(path) 返回path所指向的文件或者目录的属性修改时间 即 change time
os.path.getmtime(path) 返回path所指向的文件或者目录的最后修改时间 即 motify time

 

sys 用于提供对解释器相关的操作

官方文档

sys.argv[n]        命令行参数List,第一个元素是程序本身路径
sys.exit(n) 退出程序,正常退出时exit(0)
sys.version 获取Python解释程序的版本信息
sys.path 返回模块的搜索路径,初始化时使用PYTHONPATH环境变量的值
sys.platform 返回操作系统平台名称
sys.stdin      标准输入,默认为键盘
sys.stdout      标准输出,默认为屏幕
sys.err       标准错误输出,默认为屏幕

>>> help(print)
Help on built-in function print in module builtins:

print(...)
    print(value, ..., sep=' ', end='\n', file=sys.stdout, flush=False)
    
    Prints the values to a stream, or to sys.stdout by default.
    Optional keyword arguments:
    file:  a file-like object (stream); defaults to the current sys.stdout.
    sep:   string inserted between values, default a space.
    end:   string appended after the last value, default a newline.
    flush: whether to forcibly flush the stream.

>>> sys.stdout.write('hello')
hello5

输出重定向
>>> with open('out.log','w') as f:
     print('test',file=f)

# cat out.log
test
>>> sys.stdin.readline()[:-1] # -1 to discard the '\n' in input stream

 

subprocess  系统命令操作

os.system , os.spawn* 可以执行shell命令 , subprocess 模块也可以执行命令并提供了更丰富的功能。

官方文档

>>> help(subprocess)

This module allows you to spawn processes, connect to their
input
/output/error pipes, and obtain their return codes.

Main API
========
run(...): Runs a command, waits
for it to complete, then returns a
CompletedProcess instance. # 返回一个已经完成的子进程实例
Popen(...): A
class for flexibly executing a command in a new process

Constants
---------
DEVNULL: Special value that indicates that os.devnull should be used
PIPE: Special value that indicates a pipe should be created
STDOUT: Special value that indicates that stderr should go to stdout

Older API
=========
call(...): Runs a command, waits
for it to complete, then returns
the
return code. # 执行命令,返回状态码

  >>> retcode= subprocess.call(['ls','-l'])
  >>> retcode= subprocess.call('ls -l', shell=True)

check_call(...): Same as call() but raises CalledProcessError()
if return code is not 0 # 执行命令,如果执行状态码是 0 ,则返回0,否则抛异常

  >>> retcode= subprocess.check_call(['ls','-l'])
  >>> retcode= subprocess.check_call('ls -l', shell=True)

check_output(...): Same as check_call() but returns the contents of
stdout instead of a
return code # 执行命令,如果状态码是 0 ,则返回执行结果,否则抛异常
  
  >>> subprocess.check_output('ls')
  b'anaconda-ks.cfg\ndbbackup\nscripts\n'

getoutput(...): Runs a command
in the shell, waits for it to complete,
then returns the output
# 接收字符串格式命令,并返回结果

  >>> subprocess.getoutput('ls')
  'anaconda-ks.cfg\ndbbackup\nscripts'
   getstatusoutput(...): Runs a command in the shell, waits for it to complete, 
     then returns a (status, output) tuple
# 接收字符串格式命令,返回元组形式,第1个元素是执行状态,第2个是命令结果

>>> subprocess.getstatusoutput('ls')
  (0, 'anaconda-ks.cfg\ndbbackup\nscripts')


subprocess实例操作方法

poll()  Check if child process has terminated. 没终止返回None,结束返回0

wait()  Wait for child process to terminate. Returns returncode attribute.

communicate() 等待子进程结束,可以指定超时时间, 如communicate(timeout=3), 如果超过指定时间没结束,则抛出异常 TimeoutExpired: Command 'x' timed out after 3 seconds

terminate() 终止所启动进程

stdin 标准输入
stdout 标准输出
stderr 标准错误

pid  The process ID of the child process.

returncode  子进程执行结束的返回码

注:使用 subprocess 模块的 Popen 调用外部程序,如果 stdout 或 stderr 参数是 pipe,并且程序输出超过操作的 pipe size时,如果使用 Popen.wait() 方式等待程序结束获取返回值,会导致死锁,程序卡在 wait() 调用上。 官方推荐使用 Popen.communicate()。这个方法会把输出放在内存,而不是管道里,所以这时候上限就和内存大小有关了,一般不会有问题。而且如果要获得程序返回值,可以在调用communicate() 之后取 returncode 的值。

 subprocess.run  大多数情况下能满足需求

>>> obj=subprocess.run('ls -l /dev/null',shell=True)
crw
-rw-rw- 1 root root 1, 3 Oct 18 2016 /dev/null

>>> print(obj)
CompletedProcess(args
='ls -l /dev/null', returncode=0)

>>> obj=subprocess.run('ls -l /dev/null',shell=True,stdout=subprocess.PIPE)
>>> obj.stdout
b
'crw-rw-rw- 1 root root 1, 3 Oct 18 2016 /dev/null\n'

 

subprocess.Popen

Popen更强大,可以与执行的命令或启动的子进程进行交互

# python  进入python交互

>>> obj = subprocess.Popen(["python"], stdin=subprocess.PIPE, stdout=subprocess.PIPE)

# pstree |grep python   
        |      `-sshd---bash---python---python  # 可以看到Popen fork出一个python子进程

>>> obj.pid  #查看子进程的id
14552

父进程和子进程之间可以通过管道通信 ,subprocess.PIPE

Python 内置模块 之 os、sys、subprocess

Popen 常用参数:
  • args:shell命令,可以是字符串或者序列类型(如:list,元组)
  • shell:True, False(默认) ,设置为True 表示以字符串形式接收命令
  • bufsize:指定缓冲。0 无缓冲,1 行缓冲,其他 缓冲区大小,负值 系统缓冲
  • cwd:用于设置子进程的当前目录
  • stdin, stdout, stderr:分别表示程序的标准输入、标准输出、标准错误输出,可以是 subprocess.PIPE 或 其他程序、文件。
  • env:用于指定子进程的环境变量。如果env = None,子进程的环境变量将从父进程中继承。
  • universal_newlines:不同系统的换行符不同,True -> 同意使用 \n
  • preexec_fn:只在Unix平台下有效,用于指定一个可执行对象(callable object),它将在子进程运行之前被调用  
 
>>> cmd='ifconfig'
>>> obj=subprocess.Popen(args=cmd,shell=True,stdout=subprocess.PIPE,stderr=subprocess.PIPE)
>>> obj.stdout.read()

>>> obj=subprocess.Popen('cat >> test.txt',shell=True,stdin=subprocess.PIPE)>>> obj.stdin.write(b'1st line \n') # 通过管道输出或写入到 cat子进程,因为cat写入的是文件,所以要将字符串转换成byte
>>> obj.stdin.write(b
'2nd line \n')
>>> obj.stdin.write(b
'3rd line \n')
>>> obj.stdin.close() # 关闭管道输入,此时cat执行结束
>>> subprocess.getoutput('cat test.txt')
'1st line \n2nd line \n3rd line '

>>> obj=subprocess.Popen('uname -n',shell=True,stdout=subprocess.PIPE) 
>>> obj.stdout.read() # 通过管道将 uname -n 的执行结果读出, stdin 和 stdout都是一个管道文件对象,所以需要write(),read()等操作方法写入或读出
b'VM_200_111_centos\n'


>>> obj=subprocess.Popen('uname -n',shell=True,stdout=subprocess.PIPE,stderr=subprocess.PIPE)
>>> obj.wait()
0
>>> obj.communicate() # returns a tuple (stdoutdata, stderrdata). 返回一个元组
(b'VM_200_111_centos\n', None)

>>> obj=subprocess.Popen('xxx',shell=True,stdout=subprocess.PIPE,stderr=subprocess.PIPE)
>>> obj.communicate()
(b'', b'/bin/sh: xxx: command not found\n')
>>> obj=subprocess.Popen('top -bn 10',shell=True,stdout=subprocess.PIPE,stderr=subprocess.STDOUT
>>> obj.wait() # 卡死
>>> obj.communicate()

>>> obj = subprocess.Popen(["python"], stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=True)
>>> obj.stdin.write("print('welcome to python3')\n")
>>> obj.stdin.close()
>>> obj.stdout.read()
'welcome to python3\n'
>>> obj.stdout.close()
>>> obj.stdout.read()
ValueError: I/O operation on closed file. #管道已经关闭

这里不知道为什么不使用 universal_newlines=True 就会出如下异常
TypeError: a bytes-like object is required, not 'str