如何遍历指定的每个目录并对文件运行命令(Python)

2024-04-29 03:40:16 发布

您现在位置:Python中文网/ 问答频道 /正文

我一直在研究一个脚本,它将检查目录中的每个子目录并使用regex匹配文件,然后根据文件的类型使用不同的命令。在

所以我所完成的是基于正则表达式匹配的不同命令的使用。现在它会检查.zip文件、.rar文件或.r00文件,并对每个匹配项使用不同的命令。不过,我需要帮助遍历每个目录,首先检查其中是否有.mkv文件,然后它应该只传递该目录并跳转到下一个目录,但是如果有匹配的,它应该运行命令,然后当它完成后继续到下一个目录。在

import os
import re

rx = '(.*zip$)|(.*rar$)|(.*r00$)'
path = "/mnt/externa/folder"

for root, dirs, files in os.walk(path):

    for file in files:
        res = re.match(rx, file)
        if res:
            if res.group(1):
                print("Unzipping ",file, "...")
                os.system("unzip " + root + "/" + file + " -d " + root)
            elif res.group(2):
                os.system("unrar e " + root + "/" + file + " " + root)
            if res.group(3):
                print("Unraring ",file, "...")
                os.system("unrar e " + root + "/" + file + " " + root)

编辑:

下面是我现在的代码:

^{pr2}$

这个脚本基本上运行得很好,但有时当文件夹中有sub时,我似乎遇到了问题,下面是我运行脚本时收到的一条错误消息:

$pythonunrarscript.py在

UNRAR 5.30 beta 2 freeware      Copyright (c) 1993-2015    Alexander Roshal


Extracting from /mnt/externa/Torrents/completed/test/The.Conjuring.2013.1080p.BluRay.x264-ALLiANCE/Subs/the.conjuring.2013.1080p.bluray.x264-alliance.subs.rar

No files to extract
Traceback (most recent call last):
  File "unrarscript.py", line 19, in <module>
    check_call(["unrar","e","-o-", pth, root])
  File "/usr/lib/python2.7/subprocess.py", line 541, in     check_call
    raise CalledProcessError(retcode, cmd)
subprocess.CalledProcessError: Command '['unrar', 'e', '-o-', '/mnt/externa/Torrents/completed/test/The.Conjuring.2013.1080p.BluRay.x264-ALLiANCE/Subs/the.conjuring.2013.1080p.bluray.x264-alliance.subs.rar', '/mnt/externa/Torrents/completed/test/The.Conjuring.2013.1080p.BluRay.x264-ALLiANCE/Subs']' returned non-zero exit status 10

我不能真正理解代码的错误之处,所以我希望你们中的一些人愿意帮助我。在


Tags: 文件in命令目录脚本osresroot
3条回答

re对这样的事情来说太过分了。有一个用于提取文件扩展名的库函数,os.path.splitext。在下面的示例中,我们构建了一个filenamesmap的扩展名,我们使用它来检查在恒定时间内.mkv文件的存在,并将每个文件名映射到相应的命令。在

请注意,您可以使用zipfile(标准库)和第三方软件包are available for ^{} files解压缩文件。在

import os

for root, dirs, files in os.walk(path):
    ext_map = {}
    for fn in files:
        ext_map.setdefault(os.path.splitext(fn)[1], []).append(fn)
    if '.mkv' not in ext_map:
        for ext, fnames in ext_map.iteritems():
            for fn in fnames:
                if ext == ".zip":
                    os.system("unzip %s -d %s" % (fn, root))
                elif ext == ".rar" or ext == ".r00":
                    os.system("unrar %s %s" % (fn, root))

只需使用any来查看是否有任何文件以.mkv结尾,在进一步操作之前,您还可以简化为if/else,就像对最后两个匹配项一样。同时使用subprocess.check_call将是一种更好的方法:

import os
import re
from subprocess import check_call
from os.path import join

rx = '(.*zip$)|(.*rar$)|(.*r00$)'
path = "/mnt/externa/folder"


for root, dirs, files in os.walk(path):
    if not any(f.endswith(".mkv") for f in files):
        for file in files:
            res = re.match(rx, file)
            if res:
                # use os.path.join 
                pth = join(root, file)
                # it can only be res.group(1) or  one of the other two so we only need if/else. 
                if res.group(1): 
                    print("Unzipping ",file, "...")
                    check_call(["unzip" , pth, "-d", root])
                else:
                    check_call(["unrar","e", pth,  root])

你也可以忘记雷克斯,只需使用if/elif和结构端部公司名称:

^{pr2}$

如果您真正关心的是不重复步骤和速度,那么可以在迭代时进行筛选,也可以在检查.mkv时通过切片进行扩展收集,并使用for/else逻辑:

good = {"rar", "zip", "r00"}
for root, dirs, files in os.walk(path):
    if not any(f.endswith(".mkv") for f in files):
        tmp = {"rar": [], "zip": []}
        for file in files:
            ext = file[-4:]
            if ext == ".mkv":
                break
            elif ext in good:
                tmp[ext].append(join(root, file))
        else:
            for p in tmp.get(".zip", []):
                print("Unzipping ", p, "...")
                check_call(["unzip", p, "-d", root])
            for p in tmp.get(".rar", []):
                check_call(["unrar", "e", p, root])

这将使.mkv的任何匹配短路,或者只迭代.rar或{}的任何匹配,但除非您真正关心效率,否则我将使用第二种逻辑。在

为了避免覆盖,可以使用计数器将每个目录解压缩到新的子目录中,以帮助创建新的目录名:

from itertools import count


for root, dirs, files in os.walk(path):
        if not any(f.endswith(".mkv") for f in files):
            counter = count()
            for file in files:
                pth = join(root, file)
                if file.endswith("zip"):
                    p = join(root, "sub_{}".format(next(counter)))
                    os.mkdir(p)
                    print("Unzipping ",file, "...")
                    check_call(["unzip" , pth, "-d", p])
                elif file.endswith((".rar",".r00")):
                    p = join(root, "sub_{}".format(next(counter)))
                    os.mkdir(p)
                    check_call(["unrar","e", pth,  p])

每个都将被解压到根目录下的一个新目录中,即root_path/sub_1等。。在

您最好在问题中添加一个示例,但如果真正的问题是您只需要.rar或.r00中的一个,则可以在找到.rar或.r00的任何匹配项时设置一个标志,并且只有在未设置标志时才可以解包:

for root, dirs, files in os.walk(path):
    if not any(f.endswith(".mkv") for f in files):
        found_r = False
        for file in files:
            pth = join(root, file)
            if file.endswith("zip"):
                print("Unzipping ",file, "...")
                check_call(["unzip", pth, "-d", root])
                found_zip = True
            elif not found_r and file.endswith((".rar",".r00"))
                check_call(["unrar","e", pth,  root])
                found_r = True     

如果也只有一个zip,则可以设置两个标志,并在设置了这两个标志的地方退出循环。在

下面的例子将直接起作用!按照@Padraic的建议,我替换了操作系统使用更合适的子流程。在

将所有文件合并到一个字符串中并在字符串中查找*.mkv怎么样?在

import os
import re
from subprocess import check_call
from os.path import join

rx = '(.*zip$)|(.*rar$)|(.*r00$)'
path = "/mnt/externa/folder"
regex_mkv = re.compile('.*\.mkv\,')
for root, dirs, files in os.walk(path):

    string_files = ','.join(files)+', '
    if regex_mkv.match(string_files): continue

    for file in files:
        res = re.match(rx, file)
        if res:
            # use os.path.join 
            pth = join(root, file)
            # it can only be res.group(1) or  one of the other two so we only need if/else. 
            if res.group(1): 
                print("Unzipping ",file, "...")
                check_call(["unzip" , pth, "-d", root])
            else:
                check_call(["unrar","e", pth,  root])

相关问题 更多 >