Why is an exclamation mark not passed when calling other script? - batch-file

This is the output of my two scripts. The first one calls the other and delivers a filename as %1
D:\VIDEOS\SHORTS>for %v in (*) do call namer "%v"
D:\VIDEOS\SHORTS>call namer "10 Products You’ll Never Buy Again Knowing How They Are Made!.mp4"
D:\VIDEOS\SHORTS>echo "10 Products You’ll Never Buy Again Knowing How They Are Made.mp4" | find /i ".tmp" 1>nul && exit /b
The echo uses "%~nx1".
My question is: Why does the exclamation mark disappear?
This started happening yesterday, but I'm not sure what I could've done to cause this. It's part of a massive batch script cluster, all of which I can't post here due to size limits so ask for additional details or generalize.
edit: requested file namer.cmd
set "full=" & set "file=" & set "name=" & set "type=" & set "year=" & set "episode=" & set "strict=" & set "loose="
echo "%~nx1" | find /i ".tmp" >nul && exit /b
set "file=%~n1"
:: =============================================================================================================================
:: 1. file VALIDATOR
:: =============================================================================================================================
set "original=%file%"
set "file=%file:!=%"
set "file=%file:#=%"
set "file=%file: _ = - %"
set "file=%file:’='%"
set "file=%file:“='%"
set "file=%file:”='%"
set "file=%file:[=(%"
set "file=%file:]=)%"
set "file=%file:_= %"
set "file=%file:—=-%"
set "file=%file: = %"
set "file=%file: = %"
set "file=%file:&=and%"
:: exclamation point has to be removed before we enable delayed expansion
if not "%file%"=="%original%" ren "%~1" "%file%%~x1" 2>nul && echo validated "%file%%~x1"
if not "%file%"=="%original%" if exist "%original%" ren "%~1" "%file% - copy%~x1" && echo validated "%file% - copy%~x1"
if not "%file%"=="%original%" if exist "%original%" ren "%~1" "%file% - copy 2%~x1" && echo validated "%file% - copy 2%~x1"
setlocal enabledelayedexpansion
set "original=!file!"
set "file=!file:%%=_percent!"
if not "%file%"=="%original%" ren "%~dp1%original%%~x1" "for /f "delims=" %%v in ('where /r "d:\videos" "%strict%*" 2^>nul') do" && echo validated "%original%"
set "original=!file!"
:: this needs to separated in order to add s01 tag if no season tag present
for /l %%s in (0,1,9) do set "file=!file:series.%%s.=S0%%s!"
for /l %%e in (0,1,9) do set "file=!file:%%eof2=E0%%e!"
for /l %%e in (0,1,9) do set "file=!file:%%eof3=E0%%e!"
for /l %%e in (0,1,9) do set "file=!file:%%eof4=E0%%e!"
for /l %%e in (0,1,9) do set "file=!file:%%eof5=E0%%e!"
for /l %%e in (0,1,9) do set "file=!file:%%eof6=E0%%e!"
for /l %%e in (0,1,9) do set "file=!file:%%eof7=E0%%e!"
for /l %%e in (0,1,9) do set "file=!file:%%eof8=E0%%e!"
for /l %%e in (0,1,9) do set "file=!file:%%eof9=E0%%e!"
:: if file has changed but no season tag present add s01
if not "%file%"=="%original%" echo "%file%" | find /i "s0" >nul || set "file=!file:E0=S01E0!"
if not "%file%"=="%original%" ren "%~dp1%original%%~x1" "%file%%~x1" && echo validated "%original%"
:: =============================================================================================================================
:: 2. EXTRAPOLATOR
:: =============================================================================================================================
:extrapolate
set "type=" & set "year=" & set "ss=" & set "ep=" & set "episode="
set "name=%file%"
echo "%name%"| find " " >nul || set "name=%name:.= %" & rem if no spaces then then safer to replace dots
:: if short do complete skip of movie/series extrapolator breakdown
echo "%~n1" | find /i "trailer" >nul && set "type=misc" && goto skipyear
echo "%~p1" | find /i "\shorts\" >nul && set "type=misc" && goto skipyear
echo "%~p1" | find /i "\movies\" >nul && set "type=film" && goto skipss
echo "%~p1" | find /i "\series\" >nul && set "type=show"
:: episode number: last tag first
FOR /L %%e IN (100,1,199) DO (
SET "modname=!name:E%%e=!"
IF "!modname!" neq "%name%" (
SET "setcmd=set name=!name:E%%e=& set ep=E%%e& set type=show& rem !"
GOTO gotep
)
)
FOR /L %%e IN (10,1,99) DO (
SET "modname=!name:E%%e=!"
IF "!modname!" neq "%name%" (
SET "setcmd=set name=!name:E%%e=& set ep=E%%e& set type=show& rem !"
GOTO gotep
)
SET "modname=!name:E0%%e=!"
IF "!modname!" neq "%name%" (
SET "setcmd=set name=!name:E0%%e=& set ep=E0%%e& set type=show& rem !"
GOTO gotep
)
)
FOR /L %%e IN (0,1,9) DO (
SET "modname=!name:E0%%e=!"
IF "!modname!" neq "%name%" (
SET "setcmd=set name=!name:E0%%e=& set ep=E0%%e& set type=show& rem !"
GOTO gotep
)
SET "modname=!name:E00%%e=!"
IF "!modname!" neq "%name%" (
SET "setcmd=set name=!name:E00%%e=& set ep=E00%%e& set type=show& rem !"
GOTO gotep
)
SET "modname=!name:%%eof=!"
IF "!modname!" neq "%name%" (
SET "setcmd=set name=!name:%%eof=& set ep=E0%%e& set type=show& rem !"
GOTO gotep
)
SET "modname=!name:x0%%e=!"
IF "!modname!" neq "%name%" (
SET "setcmd=set name=!name:x0%%e=& set ep=E0%%e& set type=show& rem !"
GOTO gotep
)
)
GOTO skipep
:gotep
%setcmd%
:skipep
:: season number: second to last tag second
FOR /L %%e IN (0,1,9) DO (
SET "modname=!name:S0%%e=!"
IF "!modname!" neq "%name%" (
SET "setcmd=set name=!name:S0%%e=& set ss=S0%%e& set type=show& rem !"
GOTO gotss
)
)
FOR /L %%e IN (10,1,99) DO (
SET "modname=!name:S%%e=!"
IF "!modname!" neq "%name%" (
SET "setcmd=set name=!name:S%%e=& set ss=S%%e& set type=show& rem !"
GOTO gotss
)
)
FOR /L %%e IN (0,1,9) DO (
SET "modname=!name:series.%%e=!"
IF "!modname!" neq "%name%" (
SET "setcmd=set name=!name:series.%%e=& set ss=S0%%e& set type=show& rem !"
GOTO gotss
)
)
GOTO skipss
:gotss
%setcmd%
:skipss
if defined ep if not defined ss set ss=S01
set "episode=%ss%%ep%"
:: year number: first tag last (first with brackets so not to confuse with imdb tag)
FOR /L %%e IN (1960,1,2020) DO (
SET "modname=!name:(%%e)=!"
IF "!modname!" neq "%name%" (
SET "setcmd=set name=!name:(%%e)=& set year=%%e& if not defined type set type=film& rem !"
GOTO gotyear
)
)
FOR /L %%e IN (1960,1,2020) DO (
SET "modname=!name:%%e=!"
IF "!modname!" neq "%name%" (
SET "setcmd=set name=!name:%%e=& set year=%%e& if not defined type set type=film& rem !"
GOTO gotyear
)
)
GOTO skipyear
:gotyear
%setcmd%
:skipyear
if not defined type set type=misc
:: other trimming for misc etc
set name=%name: - copy=&rem %
set name=%name: (1)=&rem %
set name=%name: (2)=&rem %
set name=%name: (3)=&rem %
set name=%name: [1]=&rem %
set name=%name: [2]=&rem %
set name=%name:360p=&rem %
set name=%name:480p=&rem %
set name=%name:720p=&rem %
set name=%name:1080p=&rem %
set name=%name:2160p=&rem %
:: changes for general use
set "name=%name: - = %"
set "name=%name: = %"
:: trim last useless letter from name
set "name=%name%endtrimmer"
set "name=%name:(endtrimmer=endtrimmer%"
set "name=%name:[endtrimmer=endtrimmer%"
set "name=%name:.endtrimmer=endtrimmer%"
set "name=%name:-endtrimmer=endtrimmer%"
set "name=%name: endtrimmer=endtrimmer%"
set "name=%name: endtrimmer=%"
set "name=%name:_endtrimmer=%"
set "name=%name:endtrimmer=%"
:: set strings
if "%type%"=="misc" set "strict=%name: =?%"
if "%type%"=="film" if defined year set "strict=%name: =?%?(%year%)"
:: caution: this allows movie to be renamed without year tag
:: if "%type%"=="film" if not defined year set "strict=%name: =?%"
if "%type%"=="show" if defined year set "strict=%name: =?%?(%year%)?%episode%"
if "%type%"=="show" if not defined year set "strict=%name: =?%?%episode%"
if "%type%"=="show" if defined year set "loose=%name: =?%?(%year%)?s"
if "%type%"=="show" if not defined year set "loose=%name: =?%?s"
FOR %%a IN (A B C D E F G H I J K L M N O P Q R S T U V W X Y Z) DO SET "name=!name:%%a=%%a!"
endlocal & set "full=%~dp1%file%%~x1" & set "file=%file%%~x1" & set "name=%name%" & set "type=%type%" & set "year=%year%" & set "episode=%ss%%ep%" & set "strict=%strict%" & set "loose=%loose%"
:: declare (disable never delete)
echo extrapolated %type% "%strict:?= %"
:: =============================================================================================================================
:: 3. FILEBOT MODERATOR
:: =============================================================================================================================
:: if rename not needed exit
if "%type%"=="misc" exit /b
if "%~2"=="-norename" exit /b
:: if already renamed we are done here
echo "%file%" | find /i " tt" >nul && exit /b
:: prep fake temp file
set tempdir=%temp%\%date:~3,2%%date:~6,2%%date:~11,2%%time:~1,1%%time:~3,2%%time:~6,2%%time:~9,2%
mkdir "%tempdir%" && copy /y nul "%tempdir%\%file%" >nul
:: variables (to shorten lines)
if "%type%"=="film" set cf=--db TheMovieDb --format "{n} ({y}) {director} {genres} r{rating} {vf} {vc} {ac} {imdbid}"
if "%type%"=="show" set cf=--db TheTVDb --format "{n} {s00e00} {t} {vf} {vc} {ac}-mallSanta"
:: rename fake temp file
filebot -rename "%tempdir%\%file%" --q "%name% %year%" %cf% >nul 2>nul
:: new name into variable
for /r "%tempdir%" %%i in (*) do set "new=%%~nxi"
:: declare failure
if "%file%"=="%new%" echo failed, reason: && filebot -rename "%tempdir%\%file%" --log warning --q "%name% %year%" %cf% & exit /b
:: check all strings against renamed orphan fake file and if successful rename 4real
for /f "delims=" %%v in ('where "%tempdir%:%strict%*" 2^>nul') do goto 4real
for /f "delims=" %%v in ('where "%tempdir%:%strict:s?='s?%*" 2^>nul') do goto 4real
for /f "delims=" %%v in ('where "%tempdir%:%strict:?-?=?%*" 2^>nul') do goto 4real
:: declare failure and confirm override
echo.
echo file "%file%" was renamed
echo to a "%new%", which was unexpected,
:: try the interactive command prompt mode in filebot?
choice /t 20 /c yn /n /d n /m "override and approve this rename? [Y]es or [N]o: "
if "%errorlevel%"=="1" goto 4real
exit /b
:4real
filebot -rename "%~dp1%file%" --q "%name% %year%" %cf% >nul 2>nul
if not exist "%~dp1%file%" echo successfully renamed "%file%"
:: validate the new file (maybe just send to validate with a -norename? takes longer but clearer code
set "original=%file%"
set "file=%file:!=%"
set "file=%file:#=%"
set "file=%file: _ = - %"
set "file=%file:’='%"
set "file=%file:“='%"
set "file=%file:”='%"
set "file=%file:_= %"
set "file=%file:—=-%"
set "file=%file: = %"
set "file=%file: = %"
set "file=%file:&=and%"
if not "%file%"=="%original%" ren "%~1" "%file%" && echo validated "%original%"
setlocal enabledelayedexpansion
set "original=!file!"
set "file=!file:%%= percent!"
if not "%file%"=="%original%" ren "%~dp1%original%%~x1" "%file%" && echo validated "%original%"
endlocal
exit /b
it (1.) removes problematic characters from the filename (2.) from filename extrapolates video name, year, other variables, then (3.) does a supervised filebot rename. the setlocal and endlocal bits look good. could it be the problem is inherited from yet another script?

You have enabled delay environment variable expansion with setlocal EnableDelayedExpansion somewhere above the ECHO line in batch script namer.
Therefore the exclamation mark is not further interpreted as literal character, but as begin/end of a variable reference expanded delayed.
We would need the batch code of namer batch file to help you solving this issue.
It looks like the line is for checking if the file contains .tmp, i.e. has the file extension .tmp and if this is the case, ignore the file.
I suggest to change in your first batch file
for %%v in (*) do call namer "%%v"
to
for %%I in (*) do if /I not "%%~xI" == ".tmp" call "%~dp0namer.cmd" "%%I"
Then files with file extension .tmp are not processed at all by namer batch file.
Run in a command prompt window set /? for more information about delayed expansion and for /? for help on %~xI (file extension of file) as well as if /? for help on command IF and call /? for help on %~dp0.
It is also possible to use in namer.cmd:
if /I "%~x1" == ".tmp" goto :EOF
This exits processing of the batch file namer.cmd if the file extension of first argument is .tmp (compared case-insensitive). For this comparison it does not matter if delayed expansion is enabled or not. See also answer on Where does GOTO :EOF return to?
If .tmp is not the file extension of the file, but is just somewhere within file name, it is possible to use an IF with string substitution.
Example for batch file namer.cmd.
set "FileName=%~nx1"
if not "%FileName:.tmp=%" == "%FileName%" goto :EOF
The first line assigns file name with extension but without path to environment variable FileName.
The second line compares case-sensitive the file name string in which all occurrences of .tmp are replaced case-insensitive with an empty string with the file name string not modified at all. The two compared strings are not equal if the file name string really contains .tmp 1 or more times resulting in exiting processing of the batch file.
In other words the IF condition checks if a string assigned to an environment variable contains case-insensitive the string specified between : and =.
That is similar to using in C:
#include <string.h>
int main(int argc, char *argv[])
{
if(argc > 1)
{
/* Does first argument contain the string ".tmp"? */
if(strstr(argv[1],".tmp") != NULL) return 1;
}
return 0;
}
Function strstr is case-sensitive.

here is a method where you can use delayedexpansion without the use of escape characters.
#echo off
setlocal disabledelayedexpansion
set myfile="10 Products You’ll Never Buy Again Knowing How They Are Made!.mp4"
echo %DB_password%
setlocal enabledelayedexpansion
echo !myfile!

Related

The code is remove the empty lines from the file from .c files and .ini files

This code is used to replace a string within the file:
#echo off
Set _PathtoFile=D:\headercpp\revs.ini
Set _OldLine=subminor=5
Set _NewLine=subminor=6
:: End of Search parameters
Call :_Parse "%_PathtoFile%"
Set _Len=0
Set _Str=%_OldLine%
Set _Str=%_Str:"=.%987654321
:_Loop
If NOT "%_Str:~18%"=="" Set _Str=%_Str:~9%& Set /A _Len+=9& Goto _Loop
Set _Num=%_Str:~9,1%
Set /A _Len=_Len+_Num
PushD %_FilePath%
If Exist %_FileName%.new Del %_FileName%.new
If Exist %_FileName%.old Del %_FileName%.old
Set _LineNo=0
For /F "Tokens=* Eol=" %%I In (%_FileName%%_FileExt%) Do (
Set _tmp=%%I
Set /A _LineNo+=1
If /I "!_tmp:~0,%_Len%!"=="%_OldLine%" (
>>%_FileName%.new Echo %_NewLine%
) Else (
If !_LineNo! GTR 1 If "!_tmp:~0,1!"=="[" Echo.>>%_FileName%.new
SetLocal DisableDelayedExpansion
>>%_FileName%.new Echo %%I
EndLocal
))
Ren %_FileName%%_FileExt% %_FileName%.old
Ren %_FileName%.new %_FileName%.ini
::call :_check
if /i exist "%~1\" (set "Folder=%~1") else (exit)
PopD
Goto :EOF
:_Parse
Set _FilePath=%~dp1
Set _FileName=%~n1
Set `_FileExt`=%~x1
::Set _UpdatedFileName=Newtextupdated
Goto :EOF
However, the resulting output does not preserve empty lines.
How do I leave the empty lines in place?

How to store function with variable in a batch Script?

I have a Batch Script where I am trying to encode a string. I have successfully encoded the string with the help of Xor a string in a bat file
But now I want to store the value %show% !val! in a variable so that it can be used any where in the script. Below is my code. Any suggestion would be greatly appreciated.
#echo off
setlocal enableDelayedExpansion
call :init
:: Curly braces are used to denote text that should be encrypted.
:: Encryption can span multiple lines
:: {
:::password
:: }
:: Here I use a FOR loop to show all encrypted lines within this script
:: that begin with :::
for /f "delims=: tokens=*" %%A in ('findstr /b ":::" "%~f0"') do (
set val=%%A
set pwd = %show% !val!
)
echo %pwd%
exit /b
:show Str
::{
:: Nccyvrf gur fvzcyr "ebgngr nycunorg 13 cynprf" pvcure gb fgevat Fge
:: naq jevgrf gur erfhyg gb fgqbhg. Pbafrphgvir dhbgrf ("") ner pbairegrq
:: vagb n fvatyr dhbgr (").
::}
setlocal disableDelayedExpansion
set "str=%~1"
setlocal enableDelayedExpansion
set "str=!str:""="!^"
if defined {boshfpngrq} (
set "len=0"
set "str2=.!str!"
for /L %%A in (12,-1,0) do (
set /a "len|=1<<%%A"
for %%B in (!len!) do if "!str2:~%%B,1!"=="" set /a "len&=~1<<%%A"
)
set /a len-=1
set rtn=
for /l %%n in (0,1,!len!) do (
set "c=!str:~%%n,1!"
if defined {hccre}!c! for /f %%c in ("!c!") do (
if "!{hccre}:%%c=%%c!" equ "!{hccre}!" (
set "c=!{hccre}%%c!"
) else (
set "c=!{ybjre}%%c!"
)
)
set "rtn=!rtn!!c!"
)
) else set "rtn=!str!"
echo(!rtn!
exit /b 0
:init
set "}="
set "{="}
set "{hccre}=ABCDEFGHIJKLMNOPQRSTUVWXYZ"
set "{ybjre}=abcdefghijklmnopqrstuvwxyz"
for /l %%A in (0 1 25) do (
set /a "B=(%%A+13)%%26"
for /f %%B in ("!B!") do (
set "{hccre}!{hccre}:~%%A,1!=!{hccre}:~%%B,1!"
set "{ybjre}!{ybjre}:~%%A,1!=!{ybjre}:~%%B,1!"
)
)
set "{boshfpngrq}="
set "{boshfpngvbaGrfg}={N}"
if "!{boshfpngvbaGrfg}:A=!" equ "!{boshfpngvbaGrfg}!" set {boshfpngrq}=1
set "show=call :show"
exit /b
One method for accomplishing something like return values (CMD doesn't actually having them) is to pass a variable name to the function and have it assign a value to the name (outside a setlocal).
CALL :MYFUNC RETVAL 5 7 11
#ECHO Return Value: %RETVAL%
EXIT /B
:MYFUNC
SETLOCAL
SET DESTVAR=%~1
REM Do some other stuff.
SET /A TEMPVAR=%2 * %3 * %4
REM Now for the magic...
EXIT /B && SET "%DESTVAR%=%TEMPVAR%"
The crucial line is the combination of EXIT /B (or you could use ENDLOCAL, then EXIT /B) and an assignment where the substitution happens before it's executed (not delayed expansion).

this character remover can't handle percent sign

I have this script that removes troublesome characters from filenames (along with some esthetic changes):
set "fullpath=%~dp1"
set "file=%~n1"
set "ext=%~x1"
echo "%~nx1" | find /i ".tmp" >nul && exit /b
:: replace problem characters (add additional dash replacements via perl)
set "original=%file%"
set "file=%file:!=%"
set "file=%file:#=%"
set "file=%file:’='%"
set "file=%file:“=%"
set "file=%file:”=%"
set "file=%file:at&t=ATT%"
set "file=%file:&=and%"
:: additional requirements
set "file=%file: _ = - %"
set "file=%file: = %"
set "file=%file: = %"
:: replace underscores and dots only if used as spaces
echo "%file%"| find " " >nul || set "file=%file:_= %"
echo "%file%"| find " " >nul || set "file=%file:.= %"
:: exclamation point has to be removed before we enable delayed expansion
if not "%file%"=="%original%" ren "%fullpath%%original%%ext%" "%file%%ext%" 2>nul && echo validated "%original%%~x1"
:: remove percent sign
setlocal enabledelayedexpansion
set "original=!file!"
:: this percent replacement produces an error (because was not removed)
set "file=!file:%%=_percent!"
if not "%file%"=="%original%" ren "%fullpath%%original%%ext%" "%file%%ext%" 2>nul && echo validated "%original%%ext%"
set "original=!file!"
:: this needs to remain separated in order to add s01 tag if no season tag present
#for /l %%s in (0,1,9) do set "file=!file:series.%%s.=S0%%s!"
#for /l %%e in (0,1,9) do set "file=!file:%%eof2=E0%%e!"
#for /l %%e in (0,1,9) do set "file=!file:%%eof3=E0%%e!"
#for /l %%e in (0,1,9) do set "file=!file:%%eof4=E0%%e!"
#for /l %%e in (0,1,9) do set "file=!file:%%eof5=E0%%e!"
#for /l %%e in (0,1,9) do set "file=!file:%%eof6=E0%%e!"
#for /l %%e in (0,1,9) do set "file=!file:%%eof7=E0%%e!"
#for /l %%e in (0,1,9) do set "file=!file:%%eof8=E0%%e!"
#for /l %%e in (0,1,9) do set "file=!file:%%eof9=E0%%e!"
:: if file has changed but no season tag present add s01
if not "%file%"=="%original%" echo "%file%" | find /i "s0" >nul || set "file=!file:E0=S01E0!"
if not "%file%"=="%original%" ren "%fullpath%%original%%ext%" "%file%%ext%" && echo validated "%original%"
endlocal & set "file=%file%" & set "ext=%ext%" & set "fullpath=%fullpath%" & set "full=%fullpath%%file%%ext%"
this is the log for the first file. looks like the original filename doesn't have all the characters originally...
d:\VIDEOS\SHORTS\MEDIA RELATED>setlocal enabledelayedexpansion
d:\VIDEOS\SHORTS\MEDIA RELATED>set "original=!file!"
d:\VIDEOS\SHORTS\MEDIA RELATED>set "file=!file:%=_percent!"
d:\VIDEOS\SHORTS\MEDIA RELATED>if not "SUPERCUT_ Where's The F#ing Money__" == "SUPERCUT_ Where's The F#ing Money__" ren "d:\VIDEOS\SHORTS\MEDIA RELATED\SUPERCUT_ Where's The F#ing Money__.mp4" "SUPERCUT_ Where's The F#ing Money__.mp4" 2>nul && echo validated "SUPERCUT_ Where's The F#ing Money__.mp4"
...because these are the full filenames
SUPERCUT_ Where's The F##%ing Money_!_!.mp4
Through The Fire And Flames 100% Expert Guitar Hero 3.mp4
Top 10 F_#% Ups in Video Game History.mp4
any suggestions, improvements welcomed.
The problem is the way you call your batch.
call has some nasty side effects, as it runs the parser a second time and it has also a special rule for carets to double them.
But you can avoid it by using a variable instead.
for /f "delims=" %%v in ('dir /b /a-d 2^>nul') do (
set "myFile=%cd%\%%v"
call retype
)
And in retype.bat
#echo off
for /f "tokens=*" %%f in ("%myFile%") do (
set "fullpath=%%~dpf"
set "file=%%~nf"
set "ext=%%~xf"
echo "%~nxf" | find /i ".tmp" >nul && exit /b
)

variables not carried over from this script

this script takes a video file as input and after preliminary renaming extrapolates values such as title and year or episode along with a search strings strict for finding duplicate videos and loose for finding all episodes of a series. it then does a controlled filebot rename for the file.
set "filename=%~n1"
set "parentdir=%~2"
:: =============================================================================================================================
:: 1. FILENAME VALIDATOR
:: =============================================================================================================================
set "original=%filename%"
set "filename=%filename:!=%"
set "filename=%filename:&=and%"
setlocal enabledelayedexpansion
set "filename=!filename:%%=_percent!"
for /l %%s in (0,1,9) do set "filename=!filename:series.%%s=S0%%s!"
for /l %%e in (0,1,9) do set "filename=!filename:%%eof2=E0%%e!"
for /l %%e in (0,1,9) do set "filename=!filename:%%eof3=E0%%e!"
for /l %%e in (0,1,9) do set "filename=!filename:%%eof4=E0%%e!"
for /l %%e in (0,1,9) do set "filename=!filename:%%eof5=E0%%e!"
for /l %%e in (0,1,9) do set "filename=!filename:%%eof6=E0%%e!"
for /l %%e in (0,1,9) do set "filename=!filename:%%eof7=E0%%e!"
for /l %%e in (0,1,9) do set "filename=!filename:%%eof8=E0%%e!"
for /l %%e in (0,1,9) do set "filename=!filename:%%eof9=E0%%e!"
setlocal disabledelayedexpansion
if not "%filename%"=="%original%" ren "%~1" "%filename%%~x1" && echo validated "%original%"
:: =============================================================================================================================
:: 2. EXTRAS RENAMER
:: =============================================================================================================================
echo "%~p1" | find /i "extras" >nul || goto skip_extras
echo "%~p1" | find /i "featurettes" >nul || goto skip_extras
if not defined parentdir echo detected featurette but parentdir was not delivered && exit /b
call :extrapolate "%parentdir%"
ren "%filename%%~x1" "%name% extras - %filename%%~x1" && echo renamed extra "%name% extras - %filename%%~x1" && exit /b
:skip_extras
:: =============================================================================================================================
:: 3. EXTRAPOLATOR
:: =============================================================================================================================
:extrapolate
set "type=" & set "year=" & set "ss=" & set "ep=" & set "episode="
set "name=%filename%"
echo "%name%"| find " " >nul || set "name=%name:.= %" & rem if no spaces then then safer to replace dots
:: episode number: last tag first
SETLOCAL enabledelayedexpansion
FOR /L %%e IN (100,1,199) DO (
SET "modname=!name:E%%e=!"
IF "!modname!" neq "%name%" (
SET "setcmd=set name=!name:E%%e=& set ep=E%%e& set type=show& rem !"
GOTO gotep
)
)
FOR /L %%e IN (10,1,99) DO (
SET "modname=!name:E%%e=!"
IF "!modname!" neq "%name%" (
SET "setcmd=set name=!name:E%%e=& set ep=E%%e& set type=show& rem !"
GOTO gotep
)
SET "modname=!name:E0%%e=!"
IF "!modname!" neq "%name%" (
SET "setcmd=set name=!name:E0%%e=& set ep=E0%%e& set type=show& rem !"
GOTO gotep
)
)
FOR /L %%e IN (0,1,9) DO (
SET "modname=!name:E0%%e=!"
IF "!modname!" neq "%name%" (
SET "setcmd=set name=!name:E0%%e=& set ep=E0%%e& set type=show& rem !"
GOTO gotep
)
SET "modname=!name:E00%%e=!"
IF "!modname!" neq "%name%" (
SET "setcmd=set name=!name:E00%%e=& set ep=E00%%e& set type=show& rem !"
GOTO gotep
)
SET "modname=!name:%%eof=!"
IF "!modname!" neq "%name%" (
SET "setcmd=set name=!name:%%eof=& set ep=E0%%e& set type=show& rem !"
GOTO gotep
)
SET "modname=!name:x0%%e=!"
IF "!modname!" neq "%name%" (
SET "setcmd=set name=!name:x0%%e=& set ep=E0%%e& set type=show& rem !"
GOTO gotep
)
)
ENDLOCAL
GOTO skipep
:gotep
%setcmd%
ENDLOCAL & SET "type=%type%" & SET "ep=%ep%" & SET name=%name%
:skipep
:: season number: second to last tag second
SETLOCAL enabledelayedexpansion
FOR /L %%e IN (0,1,9) DO (
SET "modname=!name:S0%%e=!"
IF "!modname!" neq "%name%" (
SET "setcmd=set name=!name:S0%%e=& set ss=S0%%e& set type=show& rem !"
GOTO gotss
)
)
FOR /L %%e IN (10,1,99) DO (
SET "modname=!name:S%%e=!"
IF "!modname!" neq "%name%" (
SET "setcmd=set name=!name:S%%e=& set ss=S%%e& set type=show& rem !"
GOTO gotss
)
)
FOR /L %%e IN (0,1,9) DO (
SET "modname=!name:series.%%e=!"
IF "!modname!" neq "%name%" (
SET "setcmd=set name=!name:series.%%e=& set ss=S0%%e& set type=show& rem !"
GOTO gotss
)
)
ENDLOCAL
GOTO skipss
:gotss
%setcmd%
ENDLOCAL & SET "type=%type%" & SET "ss=%ss%" & SET name=%name%
:skipss
if defined ep if not defined ss set ss=S01
SET "episode=%ss%%ep%"
:: year number: first tag last
SETLOCAL enabledelayedexpansion
FOR /L %%e IN (1957,1,2057) DO (
SET "modname=!name:%%e=!"
IF "!modname!" neq "%name%" (
SET "setcmd=set name=!name:%%e=& set year=%%e& if not defined type set type=film& rem !"
GOTO gotyear
)
)
ENDLOCAL
GOTO skipyear
:gotyear
%setcmd%
ENDLOCAL & SET "year=%year%" & SET "type=%type%" & SET name=%name%
:skipyear
:: finalize
:: changes for general use
set name=%name: - = %
:: trim last useless letter from name
set "name=%name%endtrimmer"
set "name=%name:(endtrimmer=endtrimmer%"
set "name=%name:[endtrimmer=endtrimmer%"
set "name=%name: endtrimmer=endtrimmer%"
set "name=%name: endtrimmer=%"
set "name=%name:_endtrimmer=%"
set "name=%name:endtrimmer=%"
:: set strings
if "%type%"=="film" set "strict=%name: =?%?(%year%)"
if "%type%"=="show" if defined year set "strict=%name: =?%?(%year%)?%episode%"
if "%type%"=="show" if not defined year set "strict=%name: =?%?%episode%"
if "%type%"=="show" if defined year set "loose=%name: =?%?(%year%)?s"
if "%type%"=="show" if not defined year set "loose=%name: =?%?s"
SETLOCAL enabledelayedexpansion
FOR %%a IN (A B C D E F G H I J K L M N O P Q R S T U V W X Y Z) DO SET "name=!name:%%a=%%a!"
endlocal & SET "name=%name%"
:: declare (disable never delete)
if "%type%"=="film" echo extrapolated film %strict:?= %
if "%type%"=="show" echo extrapolated episode %strict:?= %
:: =============================================================================================================================
:: 4. FILEBOT MODERATOR
:: =============================================================================================================================
if not defined type exit /b
:: prep fake temp file
set tempdir=%temp%\%date:~3,2%%date:~6,2%%date:~11,2%%time:~1,1%%time:~3,2%%time:~6,2%%time:~9,2%
mkdir "%tempdir%" && copy /y nul "%tempdir%\%filename%.mkv" >nul
:: variables (to shorten lines)
if "%type%"=="film" set cf=--db TheMovieDb --format "{n} ({y}) {director} {genres} r{rating} {vf} {vc} {ac} {imdbid}"
if "%type%"=="show" set cf=--db TheTVDb --format "{n} {s00e00} {t} {vf} {vc} {ac} {imdbid}"
:: rename fake temp file
filebot -rename "%tempdir%\%filename%%~x1" --q "%name% %year%" %cf% >nul 2>nul
:: new name into variable
for /r "%tempdir%" %%i in (*) do set "new=%%~ni"
:: declare failure
if "%filename%"=="%new%" echo filebot refused to rename "%~n1" && exit /b
:: if what expected rename 4real
echo %%new:^&=^^^&%% | findstr /i /b /c:"%strict:?= %" >nul && goto 4real
:: if not reformat and try again
set "new=%new:'=%"
set "new=%new:,=%"
echo %%new:^&=^^^&%% | findstr /i /b /c:"%strict:?= %" >nul && goto 4real
:: declare failure and confirm override
echo "%new%" does not match "%string%"
choice /t 20 /c yn /n /d n /m "override and approve rename? [Y]es or [N]o: "
if "%errorlevel%"=="1" goto 4real
exit /b
:4real
filebot -rename "%~dp1%filename%%~x1" --q "%name% %year%" %cf% >nul 2>nul
if not exist "%filename%" echo successfully renamed "%filename%"
exit /b
none of the variables are carried over to the script that called for them. I can't for the life of me figure out why except it must have something to do with endlocal or disabledelayedexpansion, which look fine to me as far as I can tell.

Windows batch: How to remove last part of folders names

In a batch file I get a folder with a list of subfolders with an unknown number of underscores e.g.:
a_b_10
c_d_e_2
f_17
I need to remove the last token of the names i.e.
a_b
c_d_e
f
Thanks
You could try to get the last part with an underscore and then remove this from your string, but this only works when the last part is unique.
In your sample the last part seems to be always a number in spite of the other parts.
This uses the trick to parse parts of a string by replace the delimiter by a linefeed character.
#echo off
setlocal EnableDelayedExpansion
set LF=^
for /F "delims=" %%X in ('dir /b /AD') do (
call :removeLastPart "%%~X"
)
exit /b
:removeLastPart
set "str=%~1"
for %%L in ("!LF!") DO (
for /F "delims=" %%P in ("!str:_=%%~L!") do set "last=%%P"
)
echo The last part is '!last!'
REM ** now remove the last part by replacing with nothing **
set "str=!str:_%last%=!"
echo !str!
exit /b
#echo off
set "root_dir=C:\scriptests"
setlocal enableDelayedExpansion
for /f %%d in ('dir /b /a:d *_*') do (
call :lastindexof "%%d" _ lio
set "f_name=%%~d"
echo renaming !f_name!
for %%S in (!lio!) do ren !f_name! !f_name:~0,%%S!
)
endlocal
exit /b 0
:lastindexof [%1 - string ; %2 - find last index of ; %3 - if defined will store the result in variable with same name]
#echo off
setlocal disableDelayedExpansion
set "str=%~1"
set "splitter=%~2"
set LF=^
rem ** Two empty lines are required
setlocal enableDelayedExpansion
for %%L in ("!LF!") DO (
for /f "delims=" %%R in ("!splitter!") do (
set "var=!str:%%R=%%L!"
)
)
for /f delims^=^" %%P in ("!var!") DO (
set "last_part=%%~P"
)
if "!last_part!" equ "" if "%~3" NEQ "" (
echo "not contained" >2
endlocal
set %~3=-1
exit
) else (
echo "not contained" >2
endlocal
echo -1
)
call :strlen0.3 str strlen
call :strlen0.3 last_part plen
call :strlen0.3 splitter slen
set /a lio=strlen-plen-slen
endlocal & set lio=%lio%
endlocal & if "%~3" NEQ "" (set %~3=%lio%) else echo %lio%
exit /b 0
:strlen0.3 StrVar [RtnVar]
setlocal EnableDelayedExpansion
set "s=#!%~1!"
set "len=0"
for %%A in (2187 729 243 81 27 9 3 1) do (
set /A mod=2*%%A
for %%Z in (!mod!) do (
if "!s:~%%Z,1!" neq "" (
set /a "len+=%%Z"
set "s=!s:~%%Z!"
) else (
if "!s:~%%A,1!" neq "" (
set /a "len+=%%A"
set "s=!s:~%%A!"
)
)
)
)
endlocal & if "%~2" neq "" (set %~2=%len%) else echo **%len%**
exit /b
This solution will create the "renfolders.bat.txt" file for you to check in notepad, and run it as a batch file if you are happy with it.
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.
dir *_* /b /s /ad |repl ".*\\(.*)_.*" "ren \q$&\q \q$1\q" xa >"renfolders.bat.txt"
I just figured out this solution:
for /f %%f in ('dir /b /AD c:\MainFolder\') do (
set var=%%f
set var=!var:_= !
set /a count=0
for %%i in (!var!) do (set /a count+=1)
set /a count2=0
for %%i in (!var!) do (
set /a count2+=1
if /I !count2! equ 1 (set var2=%%i) else if not !count2! equ !count! (set var2=!var2!_%%i)
)
echo !var2!
)
Here is a novel approach
For each folder containing at least one _ in name:
create a temporary empty file with the same name
rename the temporary file, stripping off everything after the final _
read the new name into a variable
strip off the final _ from the name
For an explanation of how the rename works, see How does the Windows RENAME command interpret wildcards?
#echo off
setlocal enableDelayedExpansion
set "loc=%temp%\removeToken"
md "%loc%"
for /d %%F in (*_*) do (
copy nul "%loc%\%%F" >nul
ren "%loc%\*" "*_"
for %%A in ("%loc%\*") do set "new=%%~nxA"
del /q "%loc%\*"
echo old=%%F
echo new=!new:~0,-1!
echo(
)
rd "%loc%"
EDITED - Wrong copy of the code posted
It separates the elements of the directory name and iterates over them discarting the last element
#echo off
setlocal enabledelayedexpansion
for /d %%a in (*_*) do (
set "old=%%~na" & set "new=" & set "previous="
for %%b in ("!old:_=" "!") do (
if not defined previous (
set "previous=%%~b"
) else if not defined new (
set "new=!previous!"
) else set "new=!new!_!previous!"
set "previous=%%~b"
)
echo ren "%%~fa" "!new!"
)
endlocal

Resources