如何批量重命名目录、子目录和文件?

Posted

技术标签:

【中文标题】如何批量重命名目录、子目录和文件?【英文标题】:How to batch rename directories, subdirectories, and files? 【发布时间】:2022-01-15 03:33:12 【问题描述】:

我有一个 MRI 图像数据集,包含在目录(每个受试者一个;超过 200 个受试者)和多个子目录(用于结构、功能和 RS 数据,每个包含更多子目录)中,其中包含来自扫描的文件.其中一些目录和文件包含主题编号 (sub-001 > structural > sub-001_T1_structural > sub-001_T1_structural.nii.gz)。

由于这些预先存在的数据取自 3 项独立的研究,因此某些参与者人数存在重叠。我需要将所有包含主题编号的文件夹和文件重命名为从 500 开始的数字序列(以避免与原始数据集重叠)。所以我想要的 sub-001 的输出是sub-501 > structural > sub-501_T1_structural > sub-501_T1_structural.nii.gz。本质上,我需要将每个参与者的主题编号更改为从 501 开始的序列。我不能简单地将每个主题编号添加 500,因为某些主题已被排除在外,因此数字字符串中存在间隙(例如,从 sub- 011 到子 013)。

目前我已经尝试了这个短脚本,它适用于每个单独的主题,但我无法找到一种方法将它同时应用于所有主题:

find . -depth -name "*sub-001*" | \
while IFS= read -r ent; do mv $ent $ent%sub-001*sub-501$ent##*sub-001; done

对于任何错误、误解或基本错误,我深表歉意——我对脚本完全陌生,所以必须自己弄清楚才能完成我的分析。

编辑:代码更改为最近的编辑

编辑:为清晰起见添加了上下文

我尝试将此命令应用于包含原始主题编号的每个目录(加上子目录和文件),并使用正确的重命名主题编号(例如 sub-001 > sub-501、sub-002 > sub-502、sub -003 > sub-503等):

    for a in 001 002 003 004 005 006 007 008 009 010 011 013 014 015
 016 017 018 019 020 021 022 023 024 026 027 028 029 030 031 032 034
 036 037 038 039 045 046 047 049 050 051 052 053 054 055 056 057 058
 059 060 061 062 063 064 065 066 067 068 069 070 071 072 073 074 075
 076 077 078 079 080 081 082 083 084 085 086 087 088 089 090 091 092
 093 094 095 096 097 098 099 100 101 102 104 105 106 107 109 110 111
 112 113 114 115 116 117 118 119 120
    
    for b in 501 502 503 504 505 506 507 508 509 510 511 512 513 514
 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531
 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548
 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565
 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582
 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599
 600 601 602 603 604 605 606 607 608
    
    find . -depth -name "*sub-$a*" | \
    while IFS= read -r ent; do mv $ent $ent%sub-$a*sub-$b$ent##*sub-$a; done

但我遇到了错误:line 7: syntax error near unexpected token 'for'。有没有办法按顺序将命令应用于每个主题,并确保重命名的文件夹和文件从 501 向上依次跟随?

【问题讨论】:

确实不清楚您要问什么,但标题似乎太模糊了。你的意思是你想find -name "*-sub001" -o -name "*-sub002" 等(在这种情况下,就这样做,或者概括为find -name *-sub[0-9][0-9][0-9]")或者你到底卡在哪里? 缺少引用令人不快,但如果您没有任何包含空格或 shell 元字符的文件名,该命令将起作用。不过,请参阅When to wrap quotes around a shell variable 嗨@triplee,感谢您的cmets。我在我的问题中编辑了代码,因为我粘贴了错误的版本。我的问题是,虽然我的问题中包含的命令适用于一个主题(即 sub-001),但我需要一种方法来对每个主题执行相同的命令,而无需简单地为每个主题编写一个命令(即从 sub-001 到 sub- 239,从 sub-501 重命名为 sub-739,包括所有包含主题号的子目录和文件)。空格和元字符应该不是问题,所有文件和文件夹都使用标准字符命名且没有空格。 还不清楚。也许您可以edit 将尝试包含在您声称失败的第二个循环中,并可能更详细地解释您希望它应该做什么。 添加了我尝试将命令应用于遇到语法错误的每个目录。 【参考方案1】:

你需要一个dofor 之后但在循环体之前,但你也可能只需要一个循环,而不是两个嵌套循环。像这样?

i=501
for a in sub-[0-9][0-9][0-9]; do
    ((i++))
    b=sub-$i
    find . -depth -name "*sub-$a*" | \
    while IFS= read -r ent; do
        dest="$ent%sub-$a*sub-$b$ent##*sub-$a"
        mkdir -p "$dest%/*"
        mv "$ent" "$dest"
    done
done

(( ... )) 表达式是一个数学整数表达式求值;我们只需将i 的前一个值加一,然后通过在结果前面加上sub- 来创建b 的新值。

这会循环当前目录中的 sub-[0-9][0-9][0-9] 值,根据您的规范,它应该得到您想要的,而无需显式枚举所有这些值。

如果目标目录不存在,这将负责创建目标目录,但会将空的源目录留在后面。如果要重命名目录,则需要一种稍微复杂的方法(首先在目录中执行文件,然后重命名目录树中向上移动的目录),但目前这可能足够简单明了。如果您需要重复执行此操作,则完全自动化可能是有意义的。

while read 显然不适用于包含换行符的文件名。使用find ... -exec sh -c '...' _ + 会更优雅和更强大的解决方案,但这可能是在您更熟悉基础知识的时候。

【讨论】:

非常感谢您的帮助——这真的很有帮助。一些修补程序,一些阅读和一些反复试验,我让它适用于主目录中的每个主题。我最终使用的评论太长了,所以我将编辑我的问题以包含它。再次感谢!

以上是关于如何批量重命名目录、子目录和文件?的主要内容,如果未能解决你的问题,请参考以下文章

DOS按规则批量重命名所有(子)目录下文件

DOS按规则批量重命名所有(子)目录下文件

如何以照片的拍摄时间批量重命名文件

批量重命名文件

批量重命名目录中的文件

如何在 Linux 中批量移动复制追加和重命名文件