Batch/Powershell:如果文件与文件夹的复合词相同,则将它们移动到具有相同字符串的文件夹

Batch/Powershell: if files have the same compound words of folders, move them to the folder that have the same string

我有一些文件夹,例如

Computer Idea
confidenze fatali
Casa Naturale sette

和类似

的文件
2021-09-01 computer idea.rar
into confidenze fatali.pdf
casa naturale sette 454.jpg

我尝试这样移动

Computer Idea
     |
     |---> 2021-09-01 computer idea.rar

confidenze fatali
     |
     |---> into confidenze fatali.pdf

Casa Naturale sette
     |
     |---> casa naturale sette 454.jpg

例如,在 2021-09-01 computer idea.rar 文件和 Computer Idea 文件夹中找到组合词 computer idea(在这种情况下,我们有相同的 2 个相邻词)。
分隔符因为组合词只是一个空 space。
我尝试使用此批处理脚本但不起作用,我还要求提供 powershell 解决方案,因此我添加了有问题的标签。

@Echo off
Pushd %1
For /d %%A in (*) do For /f "delims=" %%B in (
  'Dir /B "*%%~nxA*" 2^>Nul '
) do If "%%~nxA" NEQ "%%~nxB" Move "%%~fB" "%%~fA\" 2>&1>>Nul
Popd
For /d %%A in (*) do Move "*%%A*" "%%A\" 2>&1>>Nul

应该可以 - 首先在测试目录中尝试。


根据进一步的信息,某些目标目录名称可能是其他目录名称的子字符串...

@ECHO OFF
SETLOCAL ENABLEDELAYEDEXPANSION 
rem The following setting for the source directory is a name
rem that I use for testing and deliberately include names which include spaces to make sure
rem that the process works using such names. These will need to be changed to suit your situation.

SET "sourcedir=u:\your files"

PUSHD "%sourcedir%"
:: remove variables starting #
FOR  /F "delims==" %%b In ('set # 2^>Nul') DO SET "%%b="

FOR /f "tokens=1*delims=:" %%b IN ('dir /b /ad ^|findstr /n .') DO SET "#%%b=%%c"&SET /a count=%%b
:: find a directory that is not a substring of another & process it
:reselect
FOR /L %%b IN (1,1,%count%) DO IF DEFINED #%%b (
 SET "targetstring=!#%%b!"
 FOR /L %%c IN (%%b,1,%count%) DO IF %%b neq %%c IF DEFINED #%%c (FOR %%e IN ("!#%%b!") DO IF /i "!#%%c:%%~e=!" neq "!#%%c!" SET "targetstring=")
 IF DEFINED targetstring (
  SET "#%%b="
  FOR /f "delims=" %%c IN ('dir /b /a-d "*!targetstring!*" 2^>nul') do Move "%%c" "!targetstring!\" 
  GOTO reselect
 )
)

POPD

首先,找到目录名称并将它们存储在变量 #1..#whatever 中,方法是将它们提交给 findstr /n,每个目录名称都带有 serial:

前缀

接下来,重复扫描 #n 个变量的数组,使用 targetstring 作为被检查字符串的存储。将它与数组中的每个其他字符串进行比较,如果它是另一个字符串的子字符串,则清除 targetstring 因此如果 targetstring 存活,清除具有此值的 #variable,处理该值并重新开始.

重复直到处理完所有#variables - 这意味着它们都已从环境中删除。

使用 PowerShell,您可以:

$rootFolder = 'D:\Test'
# get a list of folders inside the root folder
$subFolders = Get-ChildItem -Path $rootFolder -Directory
# next loop through the folders and find files that match their names
foreach ($folder in $subFolders) {
    # use the foldername as filter, surrounded with wildcard characters (*)
    Get-ChildItem -Path $rootFolder -Filter "*$($folder.Name)*" -File | Move-Item -Destination $folder.FullName -WhatIf
}

-WhatIf 开关是一个安全开关,它只会在屏幕上显示哪些文件将被移动而不会实际移动任何事物。如果您发现信息正确,请从代码中删除 -WhatIf 开关并再次 运行。

我 99.9% 确定有更好的方法,但这是我的看法:

Get-ChildItem -Path "C:\Path" | Sort-Object -Property "Mode" |
    ForEach-Object -Begin {
        $files = @{}
    } -Process {
        if (-not $_.PSIsContainer) {
            $files.Add($_.Name,$_.FullName) | Out-Null
        }
        else {
            $folder = $_
            $files.GetEnumerator() | ForEach-Object -Process {
                if ($_.Key -match $folder.Name) {
                    Move-Item -Path $_.Value -Destination $folder.FullName -WhatIf
                }
            }
        }
    }

由于它们都位于同一个目录中,您可以先将文件发送到哈希表来过滤出哪个是文件,哪个是文件夹; 这就是我们使用 Sort-Object 在顶部按文件类型列出文件的原因。在我们的 if 语句中首先处理文件,我们知道我们的 else 块(真的不需要)将只包含文件夹。最后,我们可以枚举我们的哈希表,以便将文件名与文件夹名相匹配。剩下要做的就是将文件移动到相应的文件夹。

  • 当您确定显示的结果是您执行实际移动所需要的结果时,请删除 -WhatIf 通用参数。