如何通过根据文件夹名称中存在的关键字对文件夹进行分组来将文件夹移动到其他文件夹?

Posted

技术标签:

【中文标题】如何通过根据文件夹名称中存在的关键字对文件夹进行分组来将文件夹移动到其他文件夹?【英文标题】:How to move folders to other folders by grouping them according to a keyword present in the folder name? 【发布时间】:2021-06-22 20:07:15 【问题描述】:

文件移动到它们的相关文件夹中,按文件中的键字符串排序,如下所示

Example script

我用这个脚本

@echo off
setlocal EnableExtensions DisableDelayedExpansion

rem // Define constants here:
set "SPLITCHAR=-"  & rem // (a single character to split the file names)
set "SEARCHSTR=_"  & rem // (a certain string to be replaced by another)
set "REPLACSTR= "  & rem // (a string to replace all found search strings)
set "OVERWRITE="   & rem // (set to non-empty value to force overwriting)

rem // Get file location and pattern from command line arguments:
set "LOCATION=%~1" & rem // (directory to move the processed files into)
set "PATTERNS=%~2" & rem // (file pattern; match all files if empty)

rem /* Prepare overwrite flag (if defined, set to character forbidden
rem    in file names; this affects later check for file existence): */
if defined OVERWRITE set "OVERWRITE=|"
rem // Continue only if target location is given:
if defined LOCATION (
    rem // Create target location (surpress error if it already exists):
    2> nul md "%LOCATION%"
    rem /* Loop through all files matching the given pattern
    rem    in the current working directory: */
    for /F "eol=| delims=" %%F in ('dir /B "%PATTERNS%"') do (
        rem // Process each file in a sub-routine:
        call :PROCESS "%%F" "%LOCATION%" "%SPLITCHAR%" "%SEARCHSTR%" "%REPLACSTR%"
    )
)

endlocal
exit /B


:PROCESS
rem // Retrieve first argument of sub-routine:
set "FILE=%~1"
rem // Split name at (first) split character and get portion in front:
for /F "delims=%~3" %%E in ("%~1") do (
    rem // Append a split character to partial name:
    set "FOLDER=%%E%~3"
)
setlocal EnableDelayedExpansion
rem // Right-trim partial name:
if not "%~4"=="" set "FOLDER=!FOLDER:%~4%~3=!"
set "FOLDER=!FOLDER:%~3=!"
rem /* Check whether partial name is not empty
rem    (could happen if name began with split character): */
if defined FOLDER (
    rem // Replace every search string with another:
    if not "%~4"=="" set "FOLDER=!FOLDER:%~4=%~5!"
    rem // Create sub-directory (surpress error if it already exists):
    2> nul md "%~2\!FOLDER!"
    rem /* Check if target file already exists; if overwrite flag is
    rem    set (to an invalid character), the target cannot exist: */
    if not exist "%~2\!FOLDER!\!FILE!%OVERWRITE%" (
        rem // Move file finally (surpress `1 file(s) moved.` message):
        1> nul move /Y "!FILE!" "%~2\!FOLDER!"
    )
)
endlocal
exit /B

但我希望对文件夹而不是文件做类似的事情。 例如,我有这些 文件夹 列表

Absolute Moebius - Volume 2 - The Long Tomorrow
Absolute Moebius - Volume 3
Agenzia X - Volume 1 - La Recluta
Agenzia X - Volume 2 - Black Point
Agenzia X - Volume 3 - Soli
Akira - Volume 10
Akira - Volume 20
Akira - Volume 23
Alan Ford - Volume 11 - Il Numero Uno
Alan Ford - Volume 12 - La Triste Storia Di Un Giovane Ricco
Alan Ford - Volume 13 - Golf

我希望将它们移动到这样的文件夹结构中

Absolute Moebius [folder]
|
|---> Absolute Moebius - Volume 2 - The Long Tomorrow  
|---> Absolute Moebius - Volume 3 
|
|
Agenzia X  [folder]
|
|---> Agenzia X - Volume 1 - La Recluta 
|---> Agenzia X - Volume 2 - Black Point  
|---> Agenzia X - Volume 3 - Soli  
|
Akira [folder]
|
|---> Akira - Volume 10
|---> Akira - Volume 20
|---> Akira - Volume 23
|
.
.
:

通常许多文件夹名称包含 Volumevolume 或其他一些重复且可用作判别式的关键字

编辑:问题询问如何移动文件夹而不是文件。例如,当您移动 文件 将它们分组到文件夹中时,上面的脚本可以工作:您可以看到一个示例 HERE。但我希望移动 文件夹 而不是文件,以便使用例如关键字等标准将它们分组到其他文件夹中,例如 Volume word

我还添加了 Powershell 标签,因为对我来说,powershell 脚本也很好

【问题讨论】:

你的问题是什么? 问题询问如何移动文件夹而不是文件。例如,当您移动 文件 将它们分组到文件夹中时,上面的脚本可以工作:您可以看到一个示例 HERE。但我希望移动 folders 而不是文件,以便使用例如关键字等标准将它们分组到其他文件夹中,例如 Volume word 如果您想对文件夹进行分组,您需要一个不同的词来标识每个组。根据您的说法,所有文件夹都有Volume 这个词。首先,您需要确定可用于对它们进行分组的内容。 【参考方案1】:

这可以在 Powershell 中相当简单地完成。使用Get-ChildItem 枚举目录,我们可以过滤特定的关键字,然后将它们通过管道传递给另一个cmdlet。

#Filter for directories with the word "volume"  in it
#Then pipe to a Foreach-Object loop to have it perform the same action 
#over for the objects passed to it
Get-ChildItem -Path C:\some\path -Filter "*volume*" -Directory -Recurse | ForEach-Object -Process  Move-Item -Path $_.FullName -Destination C:\Some\OtherFolder 

也取决于您的 Posh 版本,您可以添加 -Directory 参数来仅列出目录并忽略文件。我还没有真正研究过Move-Item cmdlet,但这应该可以。

根据您的评论:

$Folder    = Get-ChildItem -Path C:\Some\Path -Filter "*volume*" -Directory -Recurse #| ForEach-Object -Process  Move-Item -Path $_.FullName -Destination C:\Some\OtherFolder 
$Folder1   = $Folder.FullName.split('\')[-1]
$newFolder =  "$($Folder1.Split(' ')[0])" + " $($Folder1.Split(' ')[1])"
If(-not (Test-Path -Path C:\Some\Path\$newFolder))
    New-Item -Path C:\some\path -Name $newFolder -ItemType Directory -OutVariable Location
    

    
Foreach($Directory in $Folder.FullName)
    Move-Item -Path $Directory -Destination $Location.FullName

【讨论】:

新目录不存在时忘记创建 没有回答没有被问到的问题(:但是,这同样简单。 我尝试使用您的脚本,但只是将文件夹从一个文件夹移动到另一个文件夹。当它不存在时,您还可以添加新目录吗?例如,如果名称是 Absolute Moebius - Volume 3 / Absolute Moebius - Volume 4,则创建什么名称?绝对的莫比乌斯? 更多的脚本,但它是可行的;见编辑。 请注意,这不是我的想法,还没有经过测试。应该工作(:【参考方案2】:

我看到您选择了一个答案。这是另一种方式。

# Setup test data
$Dirs = @(
    'Absolute Moebius - Volume 2 - The Long Tomorrow'
    ,'Absolute Moebius - Volume 3'
    ,'Agenzia X - Volume 1 - La Recluta'
    ,'Agenzia X - Volume 2 - Black Point'
    ,'Agenzia X - Volume 3 - Soli'
    ,'Akira - Volume 10'
    ,'Akira - Volume 20'
    ,'Akira - Volume 23'
    ,'Alan Ford - Volume 11 - Il Numero Uno'
    ,'Alan Ford - Volume 12 - La Triste Storia Di Un Giovane Ricco'
    ,'Alan Ford - Volume 13 - Golf'
)
foreach ($Dir in $Dirs) 
    if (-not (Test-Path -Path $Dir))  New-Item -ItemType Directory -Path $Dir | Out-Null 


# Code to move files starts here vvvvvvvvvvvvvvvvvvvv
(Get-ChildItem -Directory -Filter '* - Volume*').Name |
    ForEach-Object 
        $NewDirName = $_.Split(' - ')[0]
        if (-not (Test-Path -Path $NewDirName))  New-Item -ItemType Directory -Path $NewDirName | Out-Null 
        Move-Item -Path $_ -Destination $NewDirName
    
# Code to move files ends here ^^^^^^^^^^^^^^^^^^^

【讨论】:

您的代码很好,但它拆分了文件名,例如,如果我有一个像 Alan Ford - Volume 11 - Il Numero Uno 这样的文件夹名称,您的脚本会移动文件夹,将父文件夹名称创建为 Alan 而不是 Alan Ford。- 是否存在解决这个问题? @AlexDoc,这不是我机器上发生的事情。它创建了一个Alan Ford 目录。您使用的是哪个版本的 PowerShell? $PSVersionTable.PSVersion.ToString() 产生 7.1.0-preview.3。我确实在5.1.19041.868 上得到了失败的结果。您可以对更新的版本进行任何更改吗? 是的,现在可以了,我按照您的提示更新 Powershell 版本。真的谢谢!

以上是关于如何通过根据文件夹名称中存在的关键字对文件夹进行分组来将文件夹移动到其他文件夹?的主要内容,如果未能解决你的问题,请参考以下文章

SAS编程:如何批量读入某路径下外部文档数据?

系统分区2—设备的文件名称

Linux日志中如何查找关键字及其前后的信息

分部类和分部方法

按照文件名最后数字进行排序

Sqlserver的SQL语句实现分页查询