15.10. fileinput — 命令行过滤器框架 | 应用程序组成元素 |《python 3 标准库实例教程》| python 技术论坛-江南app体育官方入口
目的:创建命令行过滤程序来处理输入流中的行。
fileinput
模块是一个框架,用于创建用于将文本文件作为过滤器处理的命令行程序。
将m3u文件转换为rss
过滤器的一个示例是 ,该程序可将一组mp3文件转换为可以作为播客共享的rss feed。该程序的输入是一个或多个列出要分发的 mp3 文件的 m3u 文件。输出是打印到控制台的 rss feed。要处理输入,程序需要遍历文件名列表和
- 打开每个文件。
- 读取文件的每一行。
- 确定该行是否指向mp3文件。
- 如果有,请将新项目添加到rss feed。
- 打印输出。
所有这些文件处理都可能是手工编码的。它并不那么复杂,并且通过一些测试,甚至错误处理也将是正确的。但是fileinput
处理所有细节,因此简化了程序。
for line in fileinput.input(sys.argv[1:]):
mp3filename = line.strip()
if not mp3filename or mp3filename.startswith('#'):
continue
item = subelement(rss, 'item')
title = subelement(item, 'title')
title.text = mp3filename
encl = subelement(item, 'enclosure',
{'type': 'audio/mpeg',
'url': mp3filename})
input()
函数将要检查的文件名列表作为参数。如果列表为空,则模块从标准输入读取数据。该函数返回一个迭代器,该迭代器从正在处理的文本文件中生成单独的行。调用方只需要遍历每一行,跳过空格和注释,即可找到对 mp3 文件的引用。
here is the complete program.
fileinput_example.py
import fileinput
import sys
import time
from xml.etree.elementtree import element, subelement, tostring
from xml.dom import minidom
# establish the rss and channel nodes
rss = element('rss',
{'xmlns:dc': "http://purl.org/dc/elements/1.1/",
'version': '2.0'})
channel = subelement(rss, 'channel')
title = subelement(channel, 'title')
title.text = 'sample podcast feed'
desc = subelement(channel, 'description')
desc.text = 'generated for pymotw'
pubdate = subelement(channel, 'pubdate')
pubdate.text = time.asctime()
gen = subelement(channel, 'generator')
gen.text = 'https://pymotw.com/'
for line in fileinput.input(sys.argv[1:]):
mp3filename = line.strip()
if not mp3filename or mp3filename.startswith('#'):
continue
item = subelement(rss, 'item')
title = subelement(item, 'title')
title.text = mp3filename
encl = subelement(item, 'enclosure',
{'type': 'audio/mpeg',
'url': mp3filename})
rough_string = tostring(rss)
reparsed = minidom.parsestring(rough_string)
print(reparsed.toprettyxml(indent=" "))
此样本输入文件包含几个 mp3 文件的名称。
sample_data.m3u
# this is a sample m3u file
episode-one.mp3
episode-two.mp3
使用示例输入运行fileinput_example.py
会使用 rss 格式生成 xml 数据。
$ python3 fileinput_example.py sample_data.m3u
sample podcast feed
generated for pymotw
sun mar 18 16:20:44 2018
https://pymotw.com/
-
episode-one.mp3
-
episode-two.mp3
进度元数据
在前面的示例中,正在处理的文件名和行号并不重要。其他工具(例如类似grep的搜索)可能需要该信息。 fileinput
包括用于访问有关当前行的所有元数据的功能(filename()
,filelineno()
和lineno()
)。
fileinput_grep.py
import fileinput
import re
import sys
pattern = re.compile(sys.argv[1])
for line in fileinput.input(sys.argv[2:]):
if pattern.search(line):
if fileinput.isstdin():
fmt = '{lineno}:{line}'
else:
fmt = '{filename}:{lineno}:{line}'
print(fmt.format(filename=fileinput.filename(),
lineno=fileinput.filelineno(),
line=line.rstrip()))
在这些示例的源代码中,可以使用基本的模式匹配循环来查找字符串“ fileinput”
的出现。
$ python3 fileinput_grep.py fileinput *.py
fileinput_change_subnet.py:10:import fileinput
fileinput_change_subnet.py:17:for line in fileinput.input(files,
inplace=true):
fileinput_change_subnet_noisy.py:10:import fileinput
fileinput_change_subnet_noisy.py:18:for line in fileinput.input(
files, inplace=true):
fileinput_change_subnet_noisy.py:19: if fileinput.isfirstline
():
fileinput_change_subnet_noisy.py:21: fileinput.filena
me()))
fileinput_example.py:6:"""example for fileinput module.
fileinput_example.py:10:import fileinput
fileinput_example.py:30:for line in fileinput.input(sys.argv[1:]
):
fileinput_grep.py:10:import fileinput
fileinput_grep.py:16:for line in fileinput.input(sys.argv[2:]):
fileinput_grep.py:18: if fileinput.isstdin():
fileinput_grep.py:22: print(fmt.format(filename=fileinput
.filename(),
fileinput_grep.py:23: lineno=fileinput.f
ilelineno(),
文本也可以从标准输入中读取。
$ cat *.py | python fileinput_grep.py fileinput
10:import fileinput
17:for line in fileinput.input(files, inplace=true):
29:import fileinput
37:for line in fileinput.input(files, inplace=true):
38: if fileinput.isfirstline():
40: fileinput.filename()))
54:"""example for fileinput module.
58:import fileinput
78:for line in fileinput.input(sys.argv[1:]):
101:import fileinput
107:for line in fileinput.input(sys.argv[2:]):
109: if fileinput.isstdin():
113: print(fmt.format(filename=fileinput.filename(),
114: lineno=fileinput.filelineno(),
就地过滤
另一种常见的文件处理操作是修改文件所在的位置,而不是创建新文件。例如,如果子网范围更改,则可能需要更新 unix 主机文件。
etc_hosts.txt before modifications
##
# host database
#
# localhost is used to configure the loopback interface
# when the system is booting. do not change this entry.
##
127.0.0.1 localhost
255.255.255.255 broadcasthost
::1 localhost
fe80::1%lo0 localhost
10.16.177.128 hubert hubert.hellfly.net
10.16.177.132 cubert cubert.hellfly.net
10.16.177.136 zoidberg zoidberg.hellfly.net
自动进行更改的安全方法是根据输入内容创建一个新文件,然后将原始文件替换为编辑后的副本。 fileinput
使用inplace
选项自动支持此功能。
fileinput_change_subnet.py
import fileinput
import sys
from_base = sys.argv[1]
to_base = sys.argv[2]
files = sys.argv[3:]
for line in fileinput.input(files, inplace=true):
line = line.rstrip().replace(from_base, to_base)
print(line)
尽管脚本使用print()
,但由于fileinput
将标准输出重定向到要覆盖的文件,因此不会产生任何输出。
$ python3 fileinput_change_subnet.py 10.16 10.17 etc_hosts.txt
更新的文件具有10.16.0.0/16
网络上所有服务器的 ip 地址已更改。
修改后的 etc_hosts.txt
##
# host database
#
# localhost is used to configure the loopback interface
# when the system is booting. do not change this entry.
##
127.0.0.1 localhost
255.255.255.255 broadcasthost
::1 localhost
fe80::1%lo0 localhost
10.17.177.128 hubert hubert.hellfly.net
10.17.177.132 cubert cubert.hellfly.net
10.17.177.136 zoidberg zoidberg.hellfly.net
在开始处理之前,将使用原始名称加上.bak
创建备份文件。
fileinput_change_subnet_noisy.py
import fileinput
import glob
import sys
from_base = sys.argv[1]
to_base = sys.argv[2]
files = sys.argv[3:]
for line in fileinput.input(files, inplace=true):
if fileinput.isfirstline():
sys.stderr.write('started processing {}.'.format(
fileinput.filename()))
sys.stderr.write('directory contains: {}.'.format(
glob.glob('etc_hosts.txt*')))
line = line.rstrip().replace(from_base, to_base)
print(line)
sys.stderr.write('finished processing.')
sys.stderr.write('directory contains: {}.'.format(
glob.glob('etc_hosts.txt*')))
关闭输入后,将删除备份文件。
$ python3 fileinput_change_subnet_noisy.py 10.16. 10.17. etc_h
osts.txt
started processing etc_hosts.txt
directory contains: ['etc_hosts.txt.bak', 'etc_hosts.txt']
finished processing
directory contains: ['etc_hosts.txt']
另请参见
- –用于将列出 mp3 的 m3u 文件转换为适合用作播客 feed 的 rss 文件的脚本。
xml.etree
-使用 elementtree 生成 xml 的更多详细信息。
本译文仅用于学习和交流目的,转载请务必注明文章译者、出处、和本文链接
我们的翻译工作遵照 cc 协议,如果我们的工作有侵犯到您的权益,请及时联系江南app体育官方入口。