利用Python进行正则表达式匹配、文件复制与备份
1. 正则表达式中的转义字符
正则表达式中有许多转义字符,它们在匹配特定类型的字符时非常有用。以下是一些常见的转义字符及其描述:
| 字符 | 描述 |
| ---- | ---- |
| \n | 换行符 |
| \t | 制表符 |
| \d | 任何数字 |
| \D | 除数字以外的任何字符 |
| \s | 任何空白字符,如空格、制表符或换行符 |
| \w | 任何字母数字字符 |
| \W | 任何非字母数字字符 |
如果要匹配特殊字符(如 \、.、* 或 +),需要使用 \ 进行转义。例如,\w 匹配 \w,而 \w 匹配任何字母数字字符。在Python中输入字符串时,斜杠也需要转义。示例如下:
>>> print("\\")
\
>>> print("\\\\")
\\
需要注意的是,如果在Python中创建用于正则表达式匹配的字符串,要记得将正则表达式中使用的斜杠数量加倍。
2. 正则表达式练习
为了检验对正则表达式的掌握程度,可以尝试以下练习。假设有一个文件包含以下内容:
aaa
a10
10
Hello
Helllo
Helloo
尝试找出以下正则表达式分别匹配哪些行:
-
.
-
\d
-
\D\d
-
l{3,4}
-
e*
-
e+
-
[Ha]
-
\d{2,3}
-
1?
可以通过运行以下命令来验证:
python3 chapter10-regex.py -f chapter10-regex-test -r"."
请记住,该程序使用的是
re.search()
而不是
re.match()
。
3. 使用网络进行脚本编写
在脚本编写中,经常需要在两台计算机之间复制文件。虽然有一个名为 Fabric 的优秀模块可以完成这个任务,但在编写本文时,它还不支持Python 3,且短期内可能不会改变。
可以使用Linux命令行程序
scp
来复制文件。不过,正常运行
scp
时,它会要求输入密码,这在Python脚本中会带来问题。不过,
scp
允许使用证书进行设置,这样在一台机器上以授权用户身份登录后,就可以在另一台机器上无需密码登录。
以下是设置步骤:
1. 登录到要传输信息的机器,在Linux命令行(如LXTerminal)中运行以下命令:
ssh-keygen -t rsa
这将在主目录的 .ssh 文件夹中创建两个文件:
id_rsa
和
id_rsa.pub
,分别包含私钥和公钥。
2. 将
id_rsa.pub
文件复制到要登录的计算机。可以使用USB闪存驱动器、云存储(如Dropbox或Google Drive),甚至电子邮件,也可以使用
scp
命令:
scp location1 location2
例如,如果要将
id_rsa.pub
文件复制到IP地址为 192.168.0.10 的机器上,使用用户
pi
,命令如下:
scp /home/pi/.ssh/id_rsa.pub pi@192.168.0.10:/home/pi
如果在单台机器上测试,可以使用
localhost
:
scp /home/pi/.ssh/id_rsa.pub pi@localhost:/home/pi
-
登录到刚刚复制文件的机器,将
id_rsa.pub文件的内容复制到authorized_keys文件中:
cat /home/pi/id_rsa.pub >> /home/pi/.ssh/authorized_keys
设置完成后,就可以使用
subprocess.call()
函数在机器之间复制文件。例如:
import subprocess
subprocess.call(["scp", "file1.py", "pi@localhost:/home/pi"])
4. 创建文件备份程序
接下来,我们将创建一个Python程序,用于备份最有用的文件,以防SD卡损坏等灾难发生时能够恢复数据。该程序将使用本章前面介绍的大部分内容,以及
os
模块。以下是代码:
import os
import tarfile
from optparse import OptionParser
from time import localtime
import datetime
import subprocess
import re
parser = OptionParser()
parser.add_option("-f", "--file", dest="filename",
help="filename to write backup to (if no option is give, backup will be used)", metavar="FILE")
parser.add_option("-p", "--path", dest="path",
help="path to backup (if no option is give, ~ will be used)")
parser.add_option("-v", "--verbose", action="store_true",
dest="verbose", default=False,
help="print status messages to stdout")
parser.add_option("-i", "--images", action="store_true",
dest="images", default=False,
help="backup image files")
parser.add_option("-c", "--code", action="store_true", dest="code",
default=False,
help="backup code files")
parser.add_option("-d", "--documents", action="store_true",
dest="documents", default=False,
help="backup document files")
parser.add_option("-a", "--all", action="store_true", dest="all",
default=False,
help="backup all filetypes (this overrides c, d & i)")
parser.add_option("-m", "--mtime", dest="mtime", default=False,
help="backup files modified less than this many days ago")
parser.add_option("-r", "--regex", dest="regex",
help="only back up filenames that match this regex")
parser.add_option("-s", "--server", dest="server", default=False,
help="copy backup file to this remote point (should be an scp location)")
options, arguments = parser.parse_args()
if options.filename:
backup_file_name = options.filename + '.tar.gz'
else:
backup_file_name = "backup.tar.gz"
backup_tar = tarfile.open(backup_file_name, "w:gz")
file_types = {"code":[".py"],
"image":[".jpeg", ".jpg", ".png", ".gif"],
"document":[".doc", "docx", ".odt", ".rtf"]}
backup_types = []
all_types = False
if options.images:
backup_types.extend(file_types["image"])
if options.code:
backup_types.extend(file_types["code"])
if options.documents:
backup_types.extend(file_types["document"])
if len(backup_types) == 0 or options.all:
all_types = True
if options.mtime:
try:
mtime_option = int(options.mtime)
except ValueError:
print("mtime option is not a valid integer.", "Ignoring option")
mtime_option = -1
else:
mtime_option = -1
if options.path:
if os.path.isdir(options.path):
directory = options.path
else:
print("Directory not found. Using ~")
directory = os.getenv("HOME")
else:
directory = os.getenv("HOME")
for root, dirs, files in os.walk(directory):
for file_name in files:
if not options.regex or re.match(options.regex, file_name):
name, extension = os.path.splitext(os.path.join(root, file_name))
if (extension in backup_types) or all_types:
modified_days = (datetime.datetime.now() -
datetime.datetime.fromtimestamp(
os.path.getmtime(
os.path.join(root, file_name)))).days
if mtime_option < 0 or modified_days < mtime_option:
if options.verbose:
print("Adding ", os.path.join(root, file_name), "last modified", modified_days, "days ago")
backup_tar.add(os.path.join(root, file_name))
if options.server:
subprocess.call(["scp", backup_file_name, options.server])
该程序的基本功能是将文件复制到一个 tar.gz 文件中,这是一种在Linux系统中流行的压缩存档类型。然后可以将该文件自动复制到远程服务器的安全位置。
程序的命令行选项如下:
| 选项 | 描述 |
| ---- | ---- |
| -h, –help | 显示帮助信息并退出 |
| -f FILE, –file=FILE | 备份文件的名称(如果未提供选项,将使用 backup) |
| -p PATH, –path=PATH | 要备份的路径(如果未提供选项,将使用 ~) |
| -v, –verbose | 将状态消息打印到标准输出 |
| -i, –images | 备份图像文件 |
| -c, –code | 备份代码文件 |
| -d, –documents | 备份文档文件 |
| -a, –all | 备份所有文件类型(此选项将覆盖 c、d 和 i) |
| -m MTIME, –mtime=MTIME | 备份最近修改时间少于指定天数的文件 |
| -r REGEX, –regex=REGEX | 仅备份文件名匹配指定正则表达式的文件 |
| -s SERVER, –server=SERVER | 将备份文件复制到远程位置(应为 scp 位置) |
基本用法示例:
python3 chapter10-backup.py -f backup.tar.gz -p /home/pi -s pi@192.168.0.10:/home/pi/backups/
该命令告诉程序遍历
/home/pi
及其所有子目录,查找符合条件的文件。程序使用
os.walk()
函数实现这一点,它会自动遍历所有子目录。
5. 使用 crontab 自动运行备份程序
虽然该程序使创建备份变得简单,但仍需要手动运行。可以使用Linux的
crontab
功能来定期自动运行程序。
crontab
有两个主要选项:
-
-l
:显示当前设置要运行的程序列表。
-
-e
:打开一个文本编辑器,用于编辑程序的运行时间。
每个要运行的任务位于单独的一行,由五个数字或星号(用空格分隔)后跟命令组成。这五个数字分别表示命令应运行的分钟、小时、日期、月份和星期几,星号表示任意值。
例如,以下命令将在每月1日午夜对主目录进行备份:
0 0 1 * * python3 /home/pi/chapter10-backup.py -s pi@192.168.0.10:/home/pi/backups
以下命令将每天中午运行备份程序:
12 0 * * * python3 /home/pi/chapter10-backup.py -s pi@192.168.0.10:/home/pi/backups
通过以上步骤,你可以利用Python进行正则表达式匹配、文件复制和备份,并实现备份任务的自动化。
利用Python进行正则表达式匹配、文件复制与备份(续)
6. 备份程序的详细解析
在前面我们已经给出了备份程序的代码,接下来对其进行详细解析,帮助大家更好地理解程序的工作原理。
6.1 模块导入与参数解析
import os
import tarfile
from optparse import OptionParser
from time import localtime
import datetime
import subprocess
import re
parser = OptionParser()
parser.add_option("-f", "--file", dest="filename",
help="filename to write backup to (if no option is give, backup will be used)", metavar="FILE")
parser.add_option("-p", "--path", dest="path",
help="path to backup (if no option is give, ~ will be used)")
parser.add_option("-v", "--verbose", action="store_true",
dest="verbose", default=False,
help="print status messages to stdout")
parser.add_option("-i", "--images", action="store_true",
dest="images", default=False,
help="backup image files")
parser.add_option("-c", "--code", action="store_true", dest="code",
default=False,
help="backup code files")
parser.add_option("-d", "--documents", action="store_true",
dest="documents", default=False,
help="backup document files")
parser.add_option("-a", "--all", action="store_true", dest="all",
default=False,
help="backup all filetypes (this overrides c, d & i)")
parser.add_option("-m", "--mtime", dest="mtime", default=False,
help="backup files modified less than this many days ago")
parser.add_option("-r", "--regex", dest="regex",
help="only back up filenames that match this regex")
parser.add_option("-s", "--server", dest="server", default=False,
help="copy backup file to this remote point (should be an scp location)")
options, arguments = parser.parse_args()
这里导入了多个模块,其中
os
模块用于访问操作系统的功能,
tarfile
用于处理压缩存档,
OptionParser
用于解析命令行参数。通过
parser.add_option
方法添加了多个命令行选项,最后使用
parser.parse_args()
解析命令行参数。
6.2 备份文件名与文件类型设置
if options.filename:
backup_file_name = options.filename + '.tar.gz'
else:
backup_file_name = "backup.tar.gz"
backup_tar = tarfile.open(backup_file_name, "w:gz")
file_types = {"code":[".py"],
"image":[".jpeg", ".jpg", ".png", ".gif"],
"document":[".doc", "docx", ".odt", ".rtf"]}
backup_types = []
all_types = False
if options.images:
backup_types.extend(file_types["image"])
if options.code:
backup_types.extend(file_types["code"])
if options.documents:
backup_types.extend(file_types["document"])
if len(backup_types) == 0 or options.all:
all_types = True
根据命令行选项确定备份文件的名称,并使用
tarfile.open
打开一个用于写入的压缩存档文件。定义了一个文件类型字典
file_types
,根据命令行选项将需要备份的文件类型添加到
backup_types
列表中。如果没有指定具体的文件类型或者使用了
-a
选项,则将
all_types
设置为
True
。
6.3 修改时间选项处理
if options.mtime:
try:
mtime_option = int(options.mtime)
except ValueError:
print("mtime option is not a valid integer.", "Ignoring option")
mtime_option = -1
else:
mtime_option = -1
如果用户提供了
-m
选项,尝试将其转换为整数。如果转换失败,打印错误信息并将
mtime_option
设置为
-1
,表示忽略该选项。
6.4 备份路径处理
if options.path:
if os.path.isdir(options.path):
directory = options.path
else:
print("Directory not found. Using ~")
directory = os.getenv("HOME")
else:
directory = os.getenv("HOME")
如果用户提供了
-p
选项,检查该路径是否为有效的目录。如果不是,打印错误信息并使用用户的主目录作为备份路径。如果没有提供
-p
选项,直接使用主目录。
6.5 文件遍历与备份
for root, dirs, files in os.walk(directory):
for file_name in files:
if not options.regex or re.match(options.regex, file_name):
name, extension = os.path.splitext(os.path.join(root, file_name))
if (extension in backup_types) or all_types:
modified_days = (datetime.datetime.now() -
datetime.datetime.fromtimestamp(
os.path.getmtime(
os.path.join(root, file_name)))).days
if mtime_option < 0 or modified_days < mtime_option:
if options.verbose:
print("Adding ", os.path.join(root, file_name), "last modified", modified_days, "days ago")
backup_tar.add(os.path.join(root, file_name))
使用
os.walk
函数遍历指定路径下的所有文件和目录。对于每个文件,首先检查是否使用了
-r
选项,如果使用了,则检查文件名是否匹配指定的正则表达式。然后获取文件的扩展名,检查该扩展名是否在
backup_types
列表中或者
all_types
是否为
True
。接着计算文件的修改时间,并根据
mtime_option
判断是否需要备份该文件。如果需要备份且使用了
-v
选项,则打印备份信息。最后使用
backup_tar.add
方法将文件添加到备份存档中。
6.6 远程复制备份文件
if options.server:
subprocess.call(["scp", backup_file_name, options.server])
如果用户提供了
-s
选项,使用
subprocess.call
调用
scp
命令将备份文件复制到远程服务器。
7. 总结
通过本文,我们学习了如何使用Python进行正则表达式匹配、文件复制和备份。正则表达式中的转义字符可以帮助我们匹配特定类型的字符,在Python中使用正则表达式时需要注意斜杠的转义。使用
scp
命令可以在两台计算机之间复制文件,通过设置证书可以实现无密码登录。创建的备份程序可以根据用户的需求备份指定路径下的文件,并将备份文件复制到远程服务器。最后,使用
crontab
可以实现备份任务的自动化。
整个流程可以用以下 mermaid 流程图表示:
graph TD;
A[开始] --> B[解析命令行参数];
B --> C{是否指定备份文件名};
C -- 是 --> D[设置备份文件名];
C -- 否 --> E[使用默认备份文件名];
D --> F[打开备份存档文件];
E --> F;
F --> G{是否指定备份路径};
G -- 是 --> H{路径是否有效};
H -- 是 --> I[使用指定路径];
H -- 否 --> J[使用主目录];
G -- 否 --> J;
I --> K[遍历文件];
J --> K;
K --> L{是否指定正则表达式};
L -- 是 --> M{文件名是否匹配};
M -- 是 --> N{是否指定文件类型};
M -- 否 --> K;
L -- 否 --> N;
N -- 是 --> O{文件类型是否匹配};
O -- 是 --> P{是否指定修改时间};
O -- 否 --> K;
N -- 否 --> P;
P -- 是 --> Q{修改时间是否符合};
Q -- 是 --> R[添加文件到备份存档];
Q -- 否 --> K;
P -- 否 --> R;
R --> K;
K --> S{是否指定远程服务器};
S -- 是 --> T[复制备份文件到远程服务器];
S -- 否 --> U[结束];
T --> U;
通过这些技术,我们可以更高效地管理和保护我们的文件,确保数据的安全性和可用性。希望本文对你有所帮助,让你在Python编程和文件管理方面有更多的收获。
超级会员免费看
462

被折叠的 条评论
为什么被折叠?



