繁体   English   中英

将文件移动到子目录

[英]Move files to a subdirectory

使用一些很大的帮助( 在包含文件的每个目录下创建子目录)我在任何包含 .jpg 照片的目录中添加了一个 \pre 子目录。

我想将任何 .jpg 文件从其当前目录移动到 \pre 子目录中。 我试过的脚本是:

FOR /R c:\temp %G IN (*.JPG) DO pushd %~dpG && if exist *.jpg move *.jpg pre\ && popd

该脚本移动了 .jpg 文件。 问题是脚本移动文件然后跟随到 \pre 目录并尝试再次移动。

pre 目录是使用第一段中链接的脚本创建的。

例如,目录 A\B\C 被处理为 A\B\C\pre。 此脚本扫描 A/B/C 并将 .jpgs 移动到 \A\B\C\pre。 然后它沿着目录树进入 A\B\C\pre 并尝试再次移动 .jpg 文件

下面的脚本呢:

@echo off
rem // Enumerate the directory tree:
for /D /R "C:\TEMP" %%G in ("*") do (
    rem // Check whether current directory is not named `pre`:
    if /I not "%%~nxG" == "pre" (
        rem // Check whether there are files:
        if exist "%%~G\*.jpg" (
            rem // Create sub-directory called `pre`:
            md "%%~G\pre" 2> nul
            rem // Move files into the sub-directory:
            move "%%~G\*.jpg" "%%~G\pre"
        )
    )
)

或者直接在命令提示符下:

@for /D /R "C:\TEMP" %G in ("*") do @if /I not "%~nxG" == "pre" if exist "%~G\*.jpg" md "%~G\pre" 2> nul & move "%~G\*.jpg" "%~G\pre"

我建议将此批处理文件用于文件移动任务。

@echo off
setlocal EnableExtensions DisableDelayedExpansion
for /F "delims=" %%I in ('dir "C:\Temp\*.jpg" /A-D /B /S 2^>nul ^| %SystemRoot%\System32\findstr.exe /I /L /V /C:"\\pre\\" /C:"\\post\\"') do (
    if not exist "%%~dpIpre\" md "%%~dpIpre"
    move /Y "%%I" "%%~dpIpre\"
)
endlocal

FOR在后台启动另一个命令进程,其中%ComSpec% /c和指定的命令行作为附加参数附加。 因此,在后台将 Windows 安装到C:\Windows中执行:

C:\Windows\System32\cmd.exe /c dir "C:\Temp\*.jpg" /A-D /B /S 2>nul | %SystemRoot%\System32\findstr.exe /I /L /V /C:"\\pre\\" /C:"\\post\\"

后台命令进程执行的DIR搜索

  • 由于选项/S在目录C:\Temp及其所有子目录中
  • 由于选项/AD仅用于文件(属性不是目录)
  • 匹配通配符模式*.jpg
  • 并由于选项/B以裸格式输出
  • 由于选项/S ,只是具有完整路径的文件名。

此文件名列表使用重定向运算符|从后台命令进程的STDOUT (标准输出)重定向。 到查找的FINDSTRSTDIN (标准输入)

  • 由于选项/I而包含不区分大小写的行
  • 文字字符串\pre\或文字字符串\post\
  • 并由于选项/V输出反转结果,即包含\pre\\post\的行。

因此FINDSTR在这里用作过滤器,以从DIR输出的 *.jpg 文件名列表中获取完整路径,只是那些路径中没有\pre\\post\的文件名,以排除已经存在的 JPEG 文件在名称为prepost的两个子目录之一中。

2>nul在命令DIR的参数之后,如果在C:\Temp及其子目录中找不到任何 *.jpg 文件名,则通过将写入STDERR (标准错误)的错误消息重定向到设备NUL来抑制DIR输出的错误消息.

阅读有关使用命令重定向运算符的 Microsoft 文章,了解2>nul的说明。 重定向运算符>| 当 Windows 命令解释器在执行命令FOR之前使用findstr执行嵌入的dir命令行并使用在后台启动的单独命令进程时,必须在FOR命令行上使用插入字符^进行转义,以将其解释为文字字符。

带有选项/FFOR捕获由FINDSTR为处理已启动命令进程的STDOUT而编写的所有内容,并在启动的cmd.exe自行终止后逐行处理此输出。 在这里处理捕获的文件名列表非常重要,并且不要在文件系统返回的另一个文件名之后迭代一个文件名,因为通配符模式匹配的文件 *.jpg 在目录结构中的每次循环迭代期间都会移动. 因此,与 *.jpg 匹配的目录条目在每次循环迭代时都会发生变化,因此需要在移动文件之前将文件名列表加载到内存中。

带有选项/FFOR忽略此处未出现的空行。

带有选项/FFOR将使用普通空格和水平制表符作为字符串分隔符将每一行拆分为子字符串,并且如果不以默认行尾字符开头,则将仅将第一个空格/制表符分隔的字符串分配给指定的循环变量I ; 在这种情况下,该行将像空行一样被完全忽略。

具有完整路径的文件名不能以;开头 . 所以默认eol=; 此处不得修改。 但是行拆分行为会适得其反,因为完整的限定文件名可以包含一个或多个空格。 出于这个原因,选项delims=用于定义字符串分隔符的空列表,它完全禁用行拆分行为。

因此,由DIR输出的每个完整文件名在由FINDSTR过滤掉的路径中不包含\pre\\post\一个接一个地分配给循环变量I

接下来检查当前 JPEG 文件是否存在子文件夹pre ,如果不存在则创建该文件夹。 然后当前的 JPEG 文件被移动到子目录pre中,并用完全相同的文件名覆盖pre中的文件。

所以这个批处理文件可以在C:\Temp上执行多次,因为它会忽略所有子目录prepost中的所有 *.jpg 文件

要了解使用的命令及其工作原理,请打开命令提示符窗口,在其中执行以下命令,并仔细阅读每个命令显示的所有帮助页面。

  • dir /?
  • echo /?
  • endlocal /?
  • findstr /?
  • for /?
  • if /?
  • md /?
  • move /?
  • setlocal /?

通过在枚举目录之前获取目录列表来解决在新的“pre”目录中执行操作的问题。

使用单行命令执行此操作可能会很好,但这比单行命令中容易执行的操作要复杂一些。

这是一个可以执行此操作的 PowerShell 脚本。 如果您在受支持的 Windows 平台上,则可以使用 PowerShell。 此脚本需要 PowerShell 5.1 或更高版本。 如果您无法访问当前的 PowerShell,可以更改代码以使其正常工作。 如果您对移动正确的文件感到满意,请从mkdirMove-Item命令中删除-WhatIf

=== Move-JpegToPre.ps1

$dirs = Get-ChildItem -Directory -Path "C:/src/t"
$extent = 'jpg'

foreach ($dir in $dirs) {
    if (Test-Path -Path "$($dir.FullName)/*.$($extent)") {
        if (-not (Test-Path -Path "$($dir.FullName)/pre")) {
            mkdir "$($dir.FullName)/pre"
        }
        Move-Item -Path "$($dir.FullName)/*.$($extent)" -Destination "$($dir.FullName)/pre" -WhatIf
    }
}

在 cmd.exe shell 中,可以通过以下方式调用它:

powershell -NoLogo -NoProfile -File Move-JpegToPre.ps1

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM