如何遍历指定的每个目录并在文件上运行命令(Python)
我一直在编写一个脚本,该脚本将检查目录中的每个子目录,并使用regex匹配文件,然后根据文件的类型使用不同的命令 所以我已经完成了基于正则表达式匹配的不同命令的使用。现在它检查.zip文件、.rar文件或.r00文件,并对每个匹配使用不同的命令。但是,我需要帮助遍历每个目录,首先检查其中是否有.mkv文件,然后它应该只传递该目录并跳转到下一个目录,但是如果有匹配项,它应该运行命令,然后在完成后继续到下一个目录如何遍历指定的每个目录并在文件上运行命令(Python),python,loops,Python,Loops,我一直在编写一个脚本,该脚本将检查目录中的每个子目录,并使用regex匹配文件,然后根据文件的类型使用不同的命令 所以我已经完成了基于正则表达式匹配的不同命令的使用。现在它检查.zip文件、.rar文件或.r00文件,并对每个匹配使用不同的命令。但是,我需要帮助遍历每个目录,首先检查其中是否有.mkv文件,然后它应该只传递该目录并跳转到下一个目录,但是如果有匹配项,它应该运行命令,然后在完成后继续到下一个目录 import os import re rx = '(.*zip$)|(.*rar$
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)
编辑:
以下是我现在掌握的代码:
import os
import re
from subprocess import check_call
from os.path import join
rx = '(.*zip$)|(.*rar$)|(.*r00$)'
path = "/mnt/externa/Torrents/completed/test"
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)
try:
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","-o-", pth, root,])
found_r = True
break
except ValueError:
print ("Oops! That did not work")
该脚本基本上工作正常,但有时当文件夹中有sub时,我似乎会遇到问题,以下是我运行脚本时收到的错误消息:
$python unrascript.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
UNRAR 5.30 beta 2免费软件版权(c)1993-2015 Alexander Roshal
从/mnt/externa/Torrents/completed/test/The.Conjuring.2013.1080p.BluRay.x264-ALLiANCE/Subs/The.Conjuring.2013.1080p.BluRay.x264-ALLiANCE.Subs.rar中提取
没有要提取的文件
回溯(最近一次呼叫最后一次):
文件“unrarscript.py”,第19行,在
检查调用([“unrr”、“e”、“-o-”、pth、root])
文件“/usr/lib/python2.7/subprocess.py”,第541行,在check_调用中
引发被调用的进程错误(retcode,cmd)
subprocess.CalledProcessError:Command'['unrr','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']返回非零退出状态10
我无法真正理解代码的错误,所以我希望你们中的一些人愿意帮助我。下面的示例将直接起作用!正如@Padraic所建议的,我用更合适的子进程替换了os.system 将所有文件合并到一个字符串中并在该字符串中查找*.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])
只需使用any查看是否有任何文件以.mkv
结尾,然后再进一步,您还可以简化为if/else,就像对最后两个匹配执行相同的操作一样。此外,使用以下方法将是更好的方法:
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])
您也可以忘记rex,只使用if/elif和str.endswith:
for root, dirs, files in os.walk(path):
if not any(f.endswith(".mkv") for f in files):
for file in files:
pth = join(root, file)
if file.endswith("zip"):
print("Unzipping ",file, "...")
check_call(["unzip" , pth, "-d", root])
elif file.endswith((".rar",".r00")):
check_call(["unrar","e", pth, root])
如果您真正关心的是不重复步骤和速度,则可以在迭代时进行过滤。您可以在检查.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
或.r00
的任何匹配进行迭代,但除非您真正关心效率,否则我将使用第二个逻辑
为了避免覆盖,您可以使用计数器将每个目录解压/解压到新的子目录,以帮助创建新的目录名:
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\u path/sub\u 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,您可以设置两个标志,并将循环保留在这两个标志都设置的位置。
re
对于这样的东西来说太过分了。有一个用于提取文件扩展名的库函数,os.path.splitext
。在下面的示例中,我们构建了一个文件名映射扩展名,并使用它在固定时间内检查.mkv
文件的存在,以及将每个文件名映射到相应的命令
请注意,您可以使用(标准库)和第三方软件包解压缩文件
Python是缩进敏感的,所以您的代码不会像您发布的那样工作。我已经为您固定了间距。很抱歉,我不明白,我意识到这会让我找到.mkv文件,但我如何同时取消.zip和rar文件的存档?也许我不太明白您想要什么。。。我建议的代码片段将包含至少一个以“.mkv”结尾的文件的目录。这不是你想要的?@Padraic Cunningham尽管更简单,但使用any的解决方案要求列表中的每个元素都有一个“if”。与780个名称的列表相比,您的方法比使用正则表达式慢约3倍。无论如何,用子进程替换os.system是非常有用的!我将在此基础上编辑我的评论。你是否先计时加入?另外,您的正则表达式是错误的,当最后一个文件以.mkv结尾时会发生什么?它看起来不像
foo.mkv,
,因此您需要添加更多的逻辑来捕捉它。@padraiccanningham是的,我在计时时考虑了连接。我更正代码以解释您发现的错误。。。谢谢构建dict是O(n),因此您没有减少搜索时间。dict唯一有意义的方法是使用dict.get在最后一个循环中查找扩展名。您必须迭代一次以检查.mkv,并迭代两次以解压缩归档文件。由于字典是在检查.mkv时生成的,您无论如何都必须这样做,因此它不会增加复杂性。不过,为每次迭代进行正则表达式匹配可能会使其具有二次性。我尝试了这个方法,它似乎效果很好,但是当同时存在一个.rar文件和几个.r00文件时,会出现一个问题,脚本将成功地取消对.r00文件的限制,然后在完成后开始提取.rar文件,但问题是它们包含相同的内容,所以它只想替换刚刚解包的文件。有没有办法跳过这个?@nillenilsson,是的,为每个人使用单独的目录不知道,目录中的文件结构如下:file1.r00 file.r01 file.r02。。。file.r99 file.rarI我理解,创建一个对每个文件都唯一的目录,并指定为untar
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
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))