首页 > batch-file > 如何通过子目录循环批处理文件

如何通过子目录循环批处理文件 (How to make a batch file loop through sub-directories)

2017-06-22 batch-file

问题

一些上下文:我从大约100张以AFSM-DDMMYY_doe-john.jpg格式命名的jpg图像开始,然后根据它们的名称将其分类到文件夹中,只使用以下脚本:

foldercreator.bat

@echo off &setlocal
for /f "delims=" %%i in ('dir /b /a-d *.jpg') do (
    set "filename1=%%~i"
    setlocal enabledelayedexpansion
    set "folder1=!filename1:~12,-4!"
    mkdir "!folder1!" 2>nul
    move "!filename1!" "!folder1!" >nul
)

然后我删除文件名的_last-first部分,使图像以AFSM-DDMMYY.jpg的格式结束。这是使用下面的脚本完成的:

nameremover.bat

@echo off &setlocal
for /f "delims=" %%i in ('dir /b /a *.jpg') do (
    set "filename1=%%~i"
    setlocal enabledelayedexpansion
    set "name1=!filename1:~0,11!"
    ren "!filename1!" "!name1!.jpg"
)

生成的文件夹最终被命名为doe-john,其中包含AFSM-DDMMYY.jpg图像。为此,这些文件夹都在一个公共文件夹中。这很好但我希望能够从公共文件夹中运行nameremover.bat,以便它在所有doe-john文件夹中运行,而不是我必须将它移动到每个文件夹,然后在那里单独运行它。先感谢您。

解决方法

简单的方法是创建一个包含批处理文件的目录 - 通用名称是batch或者belfrypath变量中包含该目录名。这样,无论当前目录如何,都可以执行目录中的任何批处理文件。

哦 - 顺便说一下:你为什么不用它

move "!filename1!" "!folder1!\!filename1:~0,11!!filename1:~-4!" >nul

在你的第一批?


当您指定可执行文件的路径(例如c:\some\directory\executable.exe)时,那将是将要执行的文件。但是,如果省略该目录并只是执行,executable.exe则尝试在当前目录中找到该文件。如果此操作失败,则path检查环境变量并path运行将在其上找到的第一个匹配的可执行文件。

因此,如果您修改path了包含目录,c:\batch那么任何运行可执行文件的尝试executablename.exe都将在c:\batch目录中运行它。

可执行文件有许多种,其中最重要的是.bat.cmd.exe及可以通过使用他们的调用基地的名称,因此执行fred将定位fred.batfred.cmdfred.exe在每个.(当前目录)和%path%(含有分号分隔的列表的环境变量目录名称)

可以使用Windows 更改路径,但像path editor(Google it)这样的第三方实用程序可以轻松实现。

所以 - 您需要做的就是建立一个包含批处理文件的目录(您已经使用该mkdir命令在已发布的批处理中执行此操作(尽管使用md哪个是更常见的同义词mkdir))然后将批处理移动到该目录,并且您可以使用其基本名称运行批处理,无论您当前的目录位于何处。

实际上,我在那里存储的不仅仅是批次 - 我也将它用于我的所有实用程序.exe- sed比如说。

分析你的代码,

@echo off&setlocal

&级联的两个命令。@echo off转动命令回显offsetlocal建立一个本地环境,确保在批处理结束时将对环境的任何更改(创建或删除的变量等)恢复到其原始状态。请注意,这不会恢复添加/删除/更改/移动的文件 - 只是环境变量。

for / f“delims =”%% i in('dir / b / ad * .jpg')do(

执行dir命令查找所有.jpg文件; 仅限名称,没有目录名称。将此列表放入内存,就像它是一个文件一样。逐行“读取”列表并%%i依次分配每行的内容。

设置“filename1 = %% ~i”

将环境变量设置filename1%%i=行内容的内容dir

setlocal enabledelayedexpansion

NEST新的本地环境,但是这一次已经delayedexpansion调用,使!var!指“的电流值var,而%var%手段”的价值var ,因为它是当 for遇到**

设置“folder1 =!filename1:~12,-4!”

设置folder1当前filename1,从第13个字符(从“字符0”开始计数)到结束的第4个字符。

mkdir“!folder1!” 2> NUL

制作该目录,抑制和错误消息(如'它已经存在')

移动“!filename1!” ! “文件夹1”!> NUL

将文件移动到新目录。自从"folder1!" is a directory, the file will be moved into that directory. If it didn't exist, the移动would move the file to a **file** named“!folder1!”`

)

...并且在几行之前code block开始结束。(do

警告

setlocal建立嵌套的本地环境。这些是有限的。您应该在endlocal命令之后放置一个命令move来结束本地环境,因此您的代码应该为每个处理的文件创建和删除本地环境。

因此,movemoveI倡导者取代,更改将意味着移动的目的地是[目标目录中的folder1\前12个字符filename1+最后4个字符来自filename1]

这将消除这一nameremover过程。

IOW,

@echo off &setlocal
for /f "delims=" %%i in ('dir /b /a-d *.jpg') do (
    set "filename1=%%~i"
    setlocal enabledelayedexpansion
    set "folder1=!filename1:~12,-4!"
    mkdir "!folder1!" 2>nul
    move "!filename1!" "!folder1!\!filename1:~0,11!!filename1:~-4!" >nul
    ENDLOCAL
)

应该进行处理,而无需执行'nameremover'步骤。\batch在进行path更改后将其放在您的目录中,您应该能够直接从系统中的提示符运行代码,包括您登录到其他驱动器。


要建立菜单,传统方法是:

:again
cls
echo 1. do thing 1
echo 2. do thing 2
echo 3. do thing 3
echo q  quit
choice /c 123q /m please choose...
if errorlevel 4 goto :eof
if errorlevel 3 call batch3&goto again
if errorlevel 2 call batch2&goto again
if errorlevel 1 call batch1&goto again
goto again

choice /?在提示符下将提供有关如何choice工作的指南。

errorlevel根据/c激活的键的字符串内的字符位置设置 。

因为if errorlevel n如果是真的errorlevel为n 或大于n的 代码必须以相反的值的顺序来构成。

要执行的代码可能会改变它的值errorlevel。因此,goto在执行附属批次之后需要a 来确保从batch3其余的if errorlevel陈述中解释,而不是由其余陈述解释。

问题

Some context: I start off with around 100 jpg images named in the format of AFSM-DDMMYY_doe-john.jpg which are then sorted into folders based on their names only with the following script:

foldercreator.bat

@echo off &setlocal
for /f "delims=" %%i in ('dir /b /a-d *.jpg') do (
    set "filename1=%%~i"
    setlocal enabledelayedexpansion
    set "folder1=!filename1:~12,-4!"
    mkdir "!folder1!" 2>nul
    move "!filename1!" "!folder1!" >nul
)

I then remove the _last-first part of the filename so the images end up in the format of AFSM-DDMMYY.jpg This is done using the script below:

nameremover.bat

@echo off &setlocal
for /f "delims=" %%i in ('dir /b /a *.jpg') do (
    set "filename1=%%~i"
    setlocal enabledelayedexpansion
    set "name1=!filename1:~0,11!"
    ren "!filename1!" "!name1!.jpg"
)

The resulting folders end up being named doe-john with AFSM-DDMMYY.jpg images in them. These folders are all within a common folder for this purpose. This works great but I would like to be able to run nameremover.bat from within the common folder so that it runs itself throughout all of the doe-john folders instead of me having to move it to each folder and then run it in there individually. Thank you in advance.

解决方法

The easy way is to create a directory to contain your batch files - common names are batch or belfry and include that directoryname in your path variable. That way, any batch files in the directory may be executed regardless of your current directory.

Oh - btw : why don't you just use

move "!filename1!" "!folder1!\!filename1:~0,11!!filename1:~-4!" >nul

in your first batch?


When you specify a path to an executable (eg c:\some\directory\executable.exe) then that will be the file that will be executed. If however you omit the directory and simply execute executable.exe then an attempt is made to locate the file in the current directory. If this fails, then the environment variable path is examined and the first matching executable found on the path will be run.

Hence, if you modify your path to include a directory such as c:\batch then any attempt to run an executable will run it if executablename.exe is present in the c:\batch directory.

Executable files come in many flavours, the most important of which are .bat, .cmd and .exe and may be invoked by using their basename, so executing fred will locate fred.bat, fred.cmd, fred.exe in each of . (the current directory) and %path% (an environment variable containing a semicolon-separated list of directorynames)

You can alter path using windows, but a 3rd-party utility like path editor (Google it) makes it easy.

So - all you need do is establish a directory to contain your batchfiles (you're already doing this in your posted batch with the mkdir command (although it's more common to use md which is a synonym of mkdir)) Then move your batches to that directory, and you can run the batch using its basename, regardless of where your current directory happens to be.

Actually, I store more than batches there - I use it for all my utility .exes as well - like sed for instance.

Analysing your code,

@echo off &setlocal

The & cascades the two commands. @echo off turns command-echoing off and setlocal establishes a local environment which ensures that any changes to the environment (variables created or deleted, etc.) are restored to their original condition at the end of the batch. Note this doesn't restore added/deleted/changed/moved files - just the environment variables.

for /f "delims=" %%i in ('dir /b /a-d *.jpg') do (

Perform a dir command to find all the .jpg files; name only and no directory names. Put this list into memory as if it was a file. "Read" the list, line by line and assign each line's content to %%i in turn.

set "filename1=%%~i"

set the environment variable filename1 to the content of %%i=the content of the dir line.

setlocal enabledelayedexpansion

NEST a new local environment, but this one has delayedexpansion invoked so that !var! means "the current value of var whereas %var% means "the value of var as it was when the for** was encountered**

set "folder1=!filename1:~12,-4!"

set folder1 to the current value of filename1, from the 13th character (counting starts from "character 0") to the 4th character from the end.

mkdir "!folder1!" 2>nul

make that directory, suppressing and error messages (like 'it already exists')

move "!filename1!" "!folder1!" >nul

move the file to the new directory. Since "folder1!" is a directory, the file will be moved into that directory. If it didn't exist, themovewould move the file to a **file** named"!folder1!"`

)

...and end of the code block started by the ( after the do a few lines ago.

Caution

setlocal establishes a nested local environment. These are limited. You should place an endlocal command after the move command to end the local environment, so your code should be creating and deleting a local environment for each file processed.

So, with the move replaced by the move I advocate, the change would mean that the destination for the move is [ the target directory in folder1 \ the first 12 characters of filename1 + the last 4 characters from filename1 ]

which would obviate the nameremover process.

IOW,

@echo off &setlocal
for /f "delims=" %%i in ('dir /b /a-d *.jpg') do (
    set "filename1=%%~i"
    setlocal enabledelayedexpansion
    set "folder1=!filename1:~12,-4!"
    mkdir "!folder1!" 2>nul
    move "!filename1!" "!folder1!\!filename1:~0,11!!filename1:~-4!" >nul
    ENDLOCAL
)

should do your processing without the need to do the 'nameremover' step. Put this in your \batch directory after making the path change, and you should be able to run the code directly from the prompt wherever you are on your system, including if you are logged into a different drive.


To establish a menu, the conventional approach is:

:again
cls
echo 1. do thing 1
echo 2. do thing 2
echo 3. do thing 3
echo q  quit
choice /c 123q /m please choose...
if errorlevel 4 goto :eof
if errorlevel 3 call batch3&goto again
if errorlevel 2 call batch2&goto again
if errorlevel 1 call batch1&goto again
goto again

choice /? at the prompt will yield a guide on how choice works.

errorlevel is set according to the character-position within the /c string of the key activated.

Since if errorlevel n is true if errorlevel is n or greater than n the code must be constructed in reverse-value order.

The code to be executed will probably alter the value of errorlevel. consequently, a goto is required after having executed the subsidiary batch to ensure that the return from batch3, say isn't interpreted by the remaining if errorlevel statements.

相似信息