在工作中,我们通常会选择使用 Python 语言来编写命令行,以代替 Shell 脚本来解决系统管理的问题。Python 既可以当作脚本语言来使用,也可以用以编写大型的服务;而作为脚本语言使用时,Python 提供了很多功能来编写命令行工具,并且很多的 Python 开源项目也可以用来快速构建命令行工具。
Python 命令行 系列文章,将对 Python 命令行工具的构建展开介绍,大纲如下:
- Python 标准库提供的命令行工具
- ini 格式的配置文件解析
- Python 解析命令行参数
- 标准库 logging 的使用
- 使用开源项目快速构建强大的命令行工具
下面,我们就开始第一部分 Python 标准库提供的命令行工具 的学习吧~
获取命令行参数 - sys.argv
"""test_argv.py"""
from __future__ import print_function
import sys
print(sys.argv)
运行结果:
print(sys.argv)sys.argv
列表保存了所有的命令行参数,第一个参数为命令行程序的名称,其余参数均以字符串的形式保存在该列表中。sys.argv
是一个保存命令行参数的普通列表,因此我们在程序中可以对该列表进行修改:
"""
test_argv.py
sys.argv is a list, so we can modify it.
"""
from __future__ import print_function
import os
import sys
def main():
sys.argv.append("")
filename = sys.argv[1]
if not os.path.isfile(filename):
raise SystemExit('{} does not exist.'.format(filename))
elif not os.access(filename, os.R_OK):
raise SystemExit('{} is not accessible.'.format(filename))
else:
print('Get {}!'.format(filename))
if __name__ == '__main__':
main()
上面的代码,从命令行获取文件名称,然后判断文件是否存在,以及是否可读。其中,我们使用 sys.argv[1]
来获取文件名称,为避免没有传参而是直接运行程序,造成的 sys.argv[1]
索引越界,我们在程序的开始,向 sys.argv
中添加了一个空字符串。
运行结果:
相当于访问一个不存在的文件 访问一个存在并可达的文件 访问一个没有读权限的文件注:上述第一次和第三次的运行结果,退出状态都是 1 ,而只有在访问存在并可读的文件时,退出状态才为 0 。这是因为,
SystemExit
不仅可以在退出时打印错误信息,还会以非 0 的返回码退出程序。
读取标准输入 - sys.stdin
fileinput
sys.stdin
我们知道 Shell 脚本独特的一个优点就是管道,管道可以连接不同的 Linux 指令,使用管道我们可以用多个简单的命令来实现一个复杂的功能。因此,工作当中,我们通常也会使用管道来结合 Python 语言和 Shell 脚本的优势。
在 Python 标准库的 sys 库中,具有三种文件描述符:标准输入(sys.stdin
)、标准输出(sys.stdout
)和标准错误(sys.stderr
)。如:下面的代码从标准输入读取内容,并打印到命令行终端:
from __future__ import print_function
import sys
for i,line in enumerate(sys.stdin):
print("line {}: {}".format(i, line), end="")
运行结果:
sys.stdin 从标准输入读取内容sys.stdin
其实是一个普通文件对象,除了从标准输入读取内容外,我们也可以使用 sys.stdin
调用文件对象的方法:
from __future__ import print_function
import sys
def get_content_lines():
return sys.stdin.readlines()
def get_content():
return sys.stdin.read()
def main():
sys.argv.append("")
if not sys.argv[1]:
print(get_content_lines())
else:
print(get_content())
if __name__ == "__main__":
main()
运行结果:
sys.stdin.readlines、sys.stdin.readfileinput
熟悉 Linux 系统的同学想必对 awk
都很熟悉,awk
功能强大,但语法复杂,小编是一直都记不住... ... 不过,有了 sys.stdin
,我们完全可以不使用 awk
语言,原因有以下两点:
- Python 命令可以和 Linux 下的管道进行较好地结合;
- Python 语言具有比
awk
应用领域广泛、可读性好、功能强大、语法清晰等诸多优点; - Python 标准模块 fileinput 可以支持多文件处理。
因此,我们完全可以在 Linux 下使用 Python 代替 awk
进行数据处理。上面提到 fileinput 支持多文件处理,接下来我们就来详细介绍下 fileinput 的使用。
fileinput 提供了比 sys.stdin
更加通用的功能:
- fileinput 会遍历
sys.argv[1:]
列表,依次读取命令行参数给出的多个文件; - 如果列表为空,则 fileinput 将会从标准输入中读取内容。
调用 fileinput.input()
方法即可按行读取内容:
from __future__ import print_function
import fileinput
for num, line in enumerate(fileinput.input()):
print("LINE {}: {}".format(num, line), end="")
运行结果:
fileinput 可以从标准输入读取数据 fileinput 从 sys.argv 中读取多个文件fileinput 除了支持读取多个文件,也提供了一些方法,以便返回当前读取的内容属于哪一个文件,fileinput 中常用的方法如下:
方法 | 用途 |
---|---|
filename | 当前读取的文件名 |
fileno | 文件的描述符 |
filelineno | 正在读取的行是当前文件的第几行 |
isfirstline | 正在读取的行是否是当前文件的第一行 |
isstdin | 正在读取文件还是直接从标准输入读取内容 |
下面是一个例子:
from __future__ import print_function
import fileinput
for line in fileinput.input():
metadata = [fileinput.filename(), fileinput.fileno(), fileinput.filelineno(), fileinput.isfirstline(), fileinput.isstdin()]
if metadata[3]:
print("\n=============================\n")
print(*metadata, end=" ")
print(line, end="")
运行结果:
fileinput 常用方法错误信息 - SystemExit
本篇文章前面的篇幅主要讨论了,Python 如何从标准输入读取内容。下面我们将介绍如何向标准输出及错误输出中写入内容。与标准输入类似,我们借助 sys.stdout
sys.stderr
即可:
import sys
sys.stdout.write('Hi\n')
sys.stderr.write('Mia\n')
首先,我们将标准输出从定向到 /dev/null
,则终端只剩下标准错误:
下面,我们将标准错误从定向到 dev/null
,则终端只剩下标准输出:
或者可以使用 Jupyter Notebook 来查看运行结果,更为直观:
标准输出和标准错误
注意:在实际工作中,一般情况下都不会直接调用
stdout.write
来输出内容,因为 print 函数默认输出到命令行终端。
当 Python 程序执行失败时,通常需要在标准错误中输出错误信息,然后以非零的返回码退出程序。常见的做法有以下两种:
sys.stderr
+ sys.exit(1)
import sys
sys.stderr.write('error message.')
sys.exit(1)
运行结果:
raise SystemExit("error message.")
raise SystemExit('error message.')
运行结果:
读取密码 - getpass
等待用户输入密码
打印用户名及密码
总结:
getpass
是一个非常简单的 Python 标准库,主要包含getuser
函数 和getpass
函数。前者用来从环境变量中获取用户名,后者用来等待用户输入密码。
网友评论