17、利用Python进行正则表达式匹配、文件复制与备份

利用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
  1. 登录到刚刚复制文件的机器,将 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编程和文件管理方面有更多的收获。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值