Windows bat: how to process files for each subdirectories - windows

I need to use a bat named here.bat to process files in the same directories. Here is an example:
mydir
|----mybat.bat
|----here.bat
|----subdir
|-----subdir2
|-----subdir3
|-----subdir31
| |-----a.jpg
|
|-----subdir32
|-----b.jpg
I need to use here.bat to process a.jpg and b.jpg. So I write a bat file named mybat.bat as below:
#Echo off&SetLocal EnableExtensions EnableDelayedExpansion
For /d %%A in (.\subdir\*) Do (
Set "Files="
For /F "delims=" %%B in ('dir /S /B "%%~fA\*.jpg"') Do Set Files=!Files! "%%~fB"
If defined Files echo call here.bat !Files!
)
pause
When I execute mybat.bat, I get the result as below:
call here.bat "C:\Users\me\mydir\subdir\subdir2\subdir3\subdire31\a.jpg" "C:\Users\me\mydir\subdir\subdir2\subdir3\sudbir32\b.jpg"
But this is not what I need. I need to process jpg files which are in the same directory with here.bat, if they are not in the same directory, they should be processed separately. Meaning that I need the result as below:
call here.bat "C:\Users\me\mydir\subdir\subdir2\subdir3\subdire31\a.jpg"
call here.bat "C:\Users\me\mydir\subdir\subdir2\subdir3\sudbir32\b.jpg"

Your changing requirements make it difficult to provide a solution in the first run. This version should do:
#Echo off&SetLocal EnableExtensions EnableDelayedExpansion
for /R ".\subdir" %%A in (.) do (
Set "Files="
If Exist "%%~fA\*.jpg" For /F "delims=" %%B in (
'dir /B "%%~fA\*.jpg"') Do Set Files=!Files! "%%~fB"
If defined Files echo call here.bat !Files!
)
pause

Related

Write a script to recursively list directories and files within it in Batch script

I am trying to write a batch script that recursively lists all directories and their files with *.js type in the below format:
For example, if I start with the C:\project directory
c:\project
project.js
project_time.js
c:\project\core
core.js
core_render.js
core_application.js
I tried to implement the above logic in code as follows:
#echo off
for /r %%f in (*.js) do (
echo %%f >> names.txt
)
pause
I was not able to print the directory under which the files are listed.
#echo off
setlocal disabledelayedexpansion
set "lastdir="
( for /r %%A in (*.js) do (
set "nextdir=%%~dpA"
setlocal enabledelayedexpansion
if /i not "!lastdir!" == "!nextdir!" (
rem Empty line and directory path.
if defined lastdir #echo(
#echo !nextdir!
)
endlocal
rem Filename.
#echo %%~nxA
set "lastdir=%%~dpA"
)
) > "names.txt"
The lastdir variable is to record the last directory path so it is echoed only once.
If lastdir is different to %%~dpA:
If lastdir is defined, then an empty line will be echoed.
Directory path of found file is echoed.
Filename is always echoed.
for modifiers dp is the drive and path. nx is the name and extension.
setlocal enabledelayedexpansion is used only where needed so paths with ! are not vulnerable.
I am not going to suggest a command line solution as it would be very long. Instead suggest use of tree command if the output format is suitable.
Here's an untested example, (I'm not expecting it to be quick if your base directory is large):
#Echo Off
(
For /F "Delims=" %%G In ('Dir /B /S /A:D "C:\Project" 2^> NUL') Do (
%__AppDir__%where.exe /Q "%%G":*.js 1> NUL 2> NUL
If Not ErrorLevel 1 (
Echo/
Echo %%G
For /F "EOL=| Delims=" %%H In ('%__AppDir__%where.exe "%%G":*.js')Do (
Echo %%~nxH
)
)
)
) 1> "names.txt"
Pause
If you prefer to run something from the Command Prompt, then try this version:
(For /F "Delims=" %G In ('Dir /B/S/AD "C:\Project" 2^>NUL')Do #(%__AppDir__%where.exe /Q "%G":*.js >NUL 2>&1&&(Echo/&Echo %G&For /F "EOL=|Delims=" %H In ('%__AppDir__%where.exe "%G":*.js')Do #Echo %~nxH)))>"names.txt"
Two simple ways to do this:
dir /S *.js
You get the answers, just as you requested.
FORFILES /S /M *.js /C "cmd /c echo #path"
You get complete path for every file.

Windows batch file: converting all files in subfolders

I need to write a batch file to convert every file in every subfolder. I came up to the following solution:
set INDIR=<some path>
set OUTDIR=<some path>
mkdir "%OUTDIR%"
for /f "tokens=1*delims=." %%f in ('dir %INDIR% /b /a-d') do (
rem %%f is file name
rem %%g is extension
call convert_one . %%f %%g
)
)
for /f "delims==" %%d in ('dir %INDIR% /ad /b') do (
rem %%d is relative path
mkdir %OUTDIR%\%%d
for /f "tokens=1*delims=." %%f in ('dir %INDIR%\%%d /b /a-d') do (
rem %%f is file name
rem %%g is extension
call convert_one %%d %%f %%g
)
)
The problem is that it iterates through the first level subfolders only. When I add /s key to the dir command it returns full pathes instead of relative.
How can I improve the script to process all levels subfolders?
PS: I need separate values for relative path, file name and extension.
You don't show us convert_one - but here's a few clues...
for /f "delims=" %%f in ('dir %INDIR% /b /s /a-d') do (
rem %%~dpnf is file name and path
rem %%~dpf is file absolute path
rem %%~nf is file name-part
rem %%~xf is extension
call convert_one "%%~dpf" "%%nf" %%~xf
)
)
See for /?|more from the prompt for more...
(within your subroutine, %~n for n=1..9 strips quotes if needed - applying quotes means that "strings containing spaces" are regarded as a single string.
- maybe make your destination directory there...?)
#echo off
setlocal enableextensions disabledelayedexpansion
set "INDIR=%cd%"
set "OUTDIR=..\out"
subst :: /d >nul 2>&1 & subst :: "%INDIR%"
for /r "::\." %%a in (*) do (
if not exist "%OUTDIR%%%~pa" md "%OUTDIR%%%~pa"
call convert_one ".%%~pa" "%%~na" "%%~xa"
)
subst :: /d
This operates creating a subst drive, so the root of the drive point to the in folder. Then iterates over the folder structure recreating the structure in the output folder and calling the subroutine with the indicated parameters

Batch remove parenthesis from file name

After successfully removing a bunch of Google Drive Folder duplicates, some files retain a "filename(2)"name.
Is there a way to batch rename every file so the parenthesis and the number inside the parenthesis is gone?
That includes folders and sub-folders.
Try like this :
Create a file test.bat with the code below in it and replace the path to test in the var $path
#echo off
set $path="C:\Users\CN Micros\Desktop\PROGRAMMATION\test"
for /f "tokens=1-3 delims=^(^)" %%a in ('dir /b/a-d %$path%') do (
if exist %$path%\"%%a(%%b)%%c" echo ren %$path%\"%%a(%%b)%%c" "%%a%%c"
)
pause
Then run it in the CMD or by double clicking.
If the output is ok for you remove the echo
The program create 3 tokens : %%a = what's before the (), %%b What's inside the () and %%c what's after the ().
Then we arrange this 3 tokens to rename the files without the ().
If you have some file who have the same final name ie : "file(1)name", "file(2)name" --> "filename"
It will work only with the first one. If you have this case you have to add a counter at the end of file to be sure that they will be renamed.
This will create renfiles.bat.txt for you to examine in Notepad and then rename to .bat and execute if you are happy with it.
#echo off
dir /b /a-d *(*).* |find /i /v "%~nx0" |find /i /v "repl.bat" |repl "(.*)\(.*\)(\..*)" "ren \q$&\q \q$1$2\q" xa >"renfiles.bat.txt"
This uses a helper batch file called repl.bat - download from: https://www.dropbox.com/s/qidqwztmetbvklt/repl.bat
Place repl.bat in the same folder as the batch file or in a folder that is on the path.
Edit: This version will recurse through subdirectories:
#echo off
dir /b /s /a-d *(*).* |find /i /v "%~nx0" |find /i /v "repl.bat" |repl ".*\\(.*)\(.*\)(\..*)" "ren \q$&\q \q$1$2\q" xa >"renfiles.bat.txt"
#ECHO OFF
SETLOCAL
SET "sourcedir=U:\sourcedir"
FOR /f "delims=" %%a IN (
'dir /b /s /a-d "%sourcedir%\*" '
) DO (
SET "name=%%~na"
SETLOCAL ENABLEDELAYEDEXPANSION
SET "newname=!name:)=!"
SET "newname=!newname:(=!"
IF "!name!" neq "!newname!" (
IF EXIST "%%~dpa!newname!%%~xa" (ECHO cannot RENAME %%a
) ELSE (ECHO(REN "%%a" "!newname!%%~xa")
)
endlocal
)
GOTO :EOF
You'd need to set your required directory into sourcedir. I used u:\sourcedir which suits my testing.
The required REN commands are merely ECHOed for testing purposes. After you've verified that the commands are correct, change ECHO(REN to REN to actually rename the files.

Modifying variable in a for loop batch file

Hi I'm trying to make a batch file that digs thru a directory and checks if all the files in its sub-directories are the same as in another directory (with the same name and same sub-directory names)
ex:
C:/Users/Administrator/desktop/directory1/global/config/project.config
C:/directory2/global/config/project.config
I'm able to fetch all the files that need to be compared with a for loop
The echo %%f gives me a path like:
C:/Users/Administrator/directory1/global/config/project.config
But I want to remove the beginning and store it in a new variable so I can easily compare files with an FC command. I don't know how to correctly do a string substitution when in a for loop. I want to get just this:
/global/config/project.config
my code for now
set b="c:\Users\Administrator\desktop\"
set j=""
for /f %%f in ('dir /a:-d /s /b /r c:\Users\Administrator\desktop\global') do (
set c=%%f
%c:b=j%
echo %%c
)
#echo off
set "dir1=c:\smth"
set "dir2=c:\dir\smth2"
setlocal enableDelyaedExpansion
for /f %%F in ('dir /a:-d /s /b /r "%dir1%"') do (
set "file_path=%%F"
if not exist "!file_path:%dir1%=%dir2%!" (
echo file %%F does not exists in %dir2%
)
)
endlocal
The better way to use a call function
setlocal enableDelyaedExpansion
for /f %%F in ('dir /a:-d /s /b /r "%dir1%"') do call :foo %%F
:foo
set "file_path=%1"
if not exist "!file_path:%dir1%=%dir2%!" (
echo file %1 does not exists in %dir2%
)

Renaming files by folder hierarchy

I have many files with the following structure:
1969/ar/1.jpg
1969/ar/2.jpg
1969/he/1.jpg
1969/he/2.jpg
1969/en/1.jpg
1969/en/2.jpg
1970/ar/1.jpg
etc...
I want to rename all of them, with one command, to one directory, while their names reflect their original folder location.
1969_ar_1.jpg
1969_ar_2.jpg
1969_he_1.jpg
1969_he_2.jpg
1969_en_1.jpg
1969_en_2.jpg
1970_ar_1.jpg
etc...
Is it possible to do so with one command or a batch file?
Thanks!
You may do that to move the files to the base folder with this command-line:
for /R %a in (*) do #set f=%a& set f=!f:%cd%\=!& move "%a" !f:\=_!
Execute it from the folder that contain the 1969, 1970... folders. IMPORTANT!: Delayed Expansion must be active in order for this line to work, so you must previously activate it executing cmd.exe with /V switch this way: cmd /V.
For example:
>xcopy test backup /s
test\1969\ar\1.jpg
test\1969\ar\2.jpg
test\1969\en\1.jpg
test\1969\en\2.jpg
test\1969\he\1.jpg
test\1969\he\2.jpg
test\1970\ar\1.jpg
7 File(s) copied
>cd test
>dir /B
1969
1970
>for /R %a in (*) do #set f=%a& set f=!f:%cd%\=!& move "%a" !f:\=_!
>dir /B
1969
1969_ar_1.jpg
1969_ar_2.jpg
1969_en_1.jpg
1969_en_2.jpg
1969_he_1.jpg
1969_he_2.jpg
1970
1970_ar_1.jpg
Modify the line this way to move the files to another folder:
for /R %a in (*) do #set f=%a& set f=!f:%cd%\=!& move "%a" "\other\folder\!f:\=_!"
Or via this Batch file:
#echo off
setlocal EnableDelayedExpansion
for /R %%a in (*) do set f=%%a& set f=!f:%cd%\=!& move "%%a" "\other\folder\!f:\=_!"
Run this from the base of the tree that contains all *.jpg files.
Change the target folder to where you want the files to go:
Test it on some samples first.
#echo off
for /f "delims=" %%z in ('dir "*.jpg" /b /s /a-d ') do (
for %%a in ("%%~dpz%\.") do (
for %%b in ("%%~dpa\.") do (
ren "%%z" "%%~nxb_%%~nxa_%%~nxz"
move "%%~dpz\%%~nxb_%%~nxa_%%~nxz" "c:\target\folder"
)
)
)
pause
try this (look at the output and remove the word echo before move, if it is OK):
#echo off &setlocal
for /d %%i in (19* 20*) do (
cmd /c "for /r "%%i" %%j in (*.jpg) do #for %%k in ("%%~dpj.") do #echo move "%%~j" "%%i_%%~nk_%%~nxj""
)

Resources