我在一次非常长时间的计算中犯了一个可怕的错误。
计算的一部分将结果文件存储在如下目录结构中:
path/to/first/[A,B,C,D]/[1,2,3,4,5]/outfiles
另一个是这样做的:
path/to/second/[1,2,3,4,5]/[A,B,C,D]/outfiles
也就是说,当脚本的第 1 部分存储文件时,它会为 A 创建一个目录,然后将迭代 1、2、3、4 和 5 存储为子目录。当第 2 部分进行计算时,它会为迭代 1 创建一个目录,然后将计算 A、B、C 和 D 的第一次迭代存储在子目录中。
我想“反转”第二个目录结构,使其与第一个目录结构类似,因为使用目录修复重新运行原始脚本将花费太长时间,并且我应该为第 2 部分工作的后处理代码已经处理了第 1 部分的结构。
也就是说,path/to/second/1/A
应该变成path/to/second/A/1
,包含以前的 的文件1/A
。有没有简单的方法可以实现这一点?
为了使创建临时目录的问题复杂化,虽然为了清楚起见,我在示例中使用了 [A,B,C,D] 和 [1,2,3,4,5],但两个层次结构的目录都只是数字,并且肯定会存在名称冲突(即10/10
存在类似情况)。
答案1
问题实际上是将所有用整数命名的目录重命名为大写字母和字母表中相应的索引(+1),反之亦然:
1 -> A
例如
C -> 3
假设每个级别的文件夹不超过 26 个(字母表中的字母数),问题就不在于那很复杂,但我们需要考虑以下几点:
- 我们需要重命名目录从下到上,因为同时移动目录并重命名目录将会失败。
- 由于您提到可能的名称冲突,我们需要进行重命名两次奔跑:
- 重命名目录,添加无意义的唯一字符串以防止名称冲突
- 重命名完成后删除字符串
下面的脚本正是这么做的:
剧本
#!/usr/bin/env python3
import string
import shutil
import os
import sys
reorg = sys.argv[1]
chars = list(string.ascii_uppercase)
nums = [str(i+1) for i, c in enumerate(chars)]
tempstring = "_temp1234"
# first step: rename from bottom to top
for root, dirs, files in os.walk(reorg, topdown = False):
for dr in dirs:
tempname = None
if dr in chars:
tempname = str(chars.index(dr)+1)+tempstring
elif dr in nums:
tempname = chars[nums.index(dr)]+tempstring
if tempname:
print(dr, tempname)
shutil.move(root+"/"+dr, root+"/"+tempname)
# second step: remove the temporary string
for root, dirs, files in os.walk(reorg, topdown = False):
for dr in dirs:
if tempstring in dr:
shutil.move(root+"/"+dr, root+"/"+dr.replace(tempstring, ""))
使用
- 将脚本复制到一个空文件中,另存为
reorg.py
使用目标目录作为参数运行它:
python3 /path/to/reorg.py /path/to/second
与往常一样,请先试用样品。
答案2
这应该可以在 bash 中完成您想要的操作:
#!/bin/bash
mkdir -p /path-to-second-new/{A,B,C,D}
for i in [1,2,3,4,5]
do
for j in [A,B,C,D]
do
cp -v /path-to-second/"$i"/"$j" /path-to-second-new/"$j"/"$i"
done
done
您的正常结构应该在 中/path-to-second-new/
,而您的初始结构保持不变/path-to-second/
。
答案3
我最近遇到了同样的问题,因为手动列出所有文件夹并不实际。我想使用 bash 脚本,于是我想出了以下内容:
for a in */; do
for b in $a/*/; do
dir=${b##*//}
mkdir -p $dir$a
mv $a$dir* $dir$a
done
rm -rf $a
done
这会动态获取文件夹名称、创建新的层次结构、移动所有文件并删除旧文件夹。
提取第二级文件夹需要一点技巧。所有目录名称都以(例如)$a
结尾。在第二个 for 循环中,我在(第一个中)后附加另一个斜杠,因此每个条目看起来都会像。Unix 会忽略这个双斜杠,因此我可以通过用 删除包括这个双斜杠在内的所有内容来过滤掉目录名称。/
folder1/
$a
/
$a/*/
$b
folder1//folder2/
dir=${b##*//}