I'm trying to edit this code to show a spinner, the file name and total files moved updated for every hundred files moved. I have the spinner part worked out but I'm stuck getting the filenames and an accurate count. In this case I have 3,554 files but it stops at 3,500. I want to integrate it into another set of code that actually does the moving of the files. That code from Magoo is listed at the end of the post. Any help very much appreciated.
Spinner Code
#ECHO OFF
SETLOCAL
SET "sourcedir=C:\temp\xmls"
SET "spinChars=\|/-"
for /f %%a in ('"prompt $H&for %%b in (1) do rem"') do set "BS=%%a"
SET "filesmoved=0"
PUSHD "%sourcedir%"
For %%A in (*.xml) do set /a cnt+=1
Echo %cnt% files.
For /L %%I in (1,1,%cnt%) do (
set /a filesmoved += 1, hundred = filesmoved %% 100
setlocal enabledelayedexpansion
if !hundred! equ 0 call :spinner
endlocal
)
goto :EOF
:spinner
set "moved=%filesmoved%"
:spinner2
if %filesmoved% geq 400 set /a filesmoved -= 400 & goto :spinner2
set /a spinpos = filesmoved / 100
for /L %%I in (1,1,50) do set /P "=%BS%"<NUL
set /P "=Moving XML Files !spinChars:~%spinPos%,1! %moved% Files moved"<NUL
goto :EOF
Batch move XML Files
#ECHO OFF
SETLOCAL
SET "sourcedir=U:\sourcedir\t w o"
PUSHD "%sourcedir%"
FOR /f "tokens=1*delims=" %%a IN (
'dir /b /a-d "%sourcedir%\*_*_*.xml" '
) DO SET "filename=%%a"&CALL :process
POPD
GOTO :EOF
:process
FOR /f "tokens=2,3,6delims=_" %%m IN ("%filename%") DO SET "date1=%%m"&SET "date2=%%n"&SET "whichdate=%%o"
IF DEFINED whichdate SET "date1=%date2%"
IF NOT DEFINED date2 GOTO :eof
ECHO(MD .\%date1:~0,4%\%date1:~4,2%
ECHO(MOVE "%filename%" .\%date1:~0,4%\%date1:~4,2%\
GOTO :EOF
Latest Code
#ECHO OFF
SETLOCAL
Title Reorganizing XMLs - DO NOT CLOSE THIS WINDOW!
mode con: cols=100 lines=6
set "sourcedir=C:\Temp\XMLs"
pushd %sourcedir%
SET "spinChars=\|/-"
for /f %%a in ('"prompt $H&for %%b in (1) do rem"') do set "BS=%%a"
set "spaces= "
SET /a filesMoved = 0, spinPos = 0, prev = 0
echo Moving XML Files...
setlocal enabledelayedexpansion
for /L %%I in (1,1,7) do set "BS=!BS!!BS!"
for /L %%I in (1,1,3) do set "spaces=!spaces!!spaces!"
For %%A in (*.xml) do set /a cnt+=1
echo.
Echo %cnt% files.
echo.
FOR /f "tokens=1*delims=" %%a IN ('dir /b /a-d "%sourcedir%\*.xml" ' ) DO (
set /a filesmoved += 1
call :spinner !filesmoved! "%%~nxa"
)
call :spinner %filesMoved% Done.
endlocal & echo;
exit /b 0
:spinner <filecount> <filename>
set /a spinPos += 1, spinPos %%= 4, ten = %~1 / 10 * 10
if "%~2"=="Done." set ten=%~1
set "str=[!spinChars:~%spinPos%,1!] %ten% files moved... [%~2]"
set "str=%str:~0,79%"
call :length len "%str%"
set /a diff = 79 - len
if %diff% gtr 0 set "str=%str%!spaces:~-%diff%!"
set /P "=!BS:~-79!%str%"<NUL
if "%~2" NEQ "Done." call :process %~2
exit /b 0
:length <return_var> <string>
setlocal enabledelayedexpansion
if "%~2"=="" (set ret=0) else set ret=1
set "tmpstr=%~2"
for %%I in (4096 2048 1024 512 256 128 64 32 16 8 4 2 1) do (
if not "!tmpstr:~%%I,1!"=="" (
set /a ret += %%I
set "tmpstr=!tmpstr:~%%I!"
)
)
endlocal & set "%~1=%ret%"
exit /b 0
:process
FOR /f "tokens=2,3,6delims=_" %%m IN ("%~1") DO SET "date1=%%m"&SET "date2=%%n"&SET "whichdate=%%o"
IF DEFINED whichdate SET "date1=%date2%"
IF NOT DEFINED date2 exit /b 1
If not exist .\%date1:~0,4%\%date1:~4,2% MD .\%date1:~0,4%\%date1:~4,2%
MOVE %~1 .\%date1:~0,4%\%date1:~4,2%\
Well, a promise is a promise I guess. :)
OK. Part of the difficulty you'll encounter, whether you realize it or not, is that capturing a Backspace to a variable and set /Ping it to the console merely moves the cursor back one column. It doesn't replace the characters with blank spaces. So if you're going to be echoing out filenames, backspacing then set /P "=filename.ext" will leave some unpleasantness displayed if filename.ext is shorter than a previous filename.ext.
You could set /P "= %BS%%BS%" to overwrite each character with a space, but doing this with afor /L` loop will cause the line to flicker, also unpleasantly.
So my solution is to capture 128 backspaces to a variable, then use numeric substring extraction to set /P "=%BS:~-num%" to eliminate the flickering. I also space fill then re-backspace at the end of the line if the current line is shorter than the previous line. And finally, I limit the length of the line to 80 characters to avoid line wrapping (from which no amount of programmatic backspacing can recover).
For my testing, I just used the contents of my C: drive for the list of files to loop through. If you need help integrating Magoo's :process code, leave a comment and I'll help you out when I get a chance. I've gotta jet for tonight, though. For now, save this and run it as a proof of concept. It's only a laser light show. It doesn't actually move anything in its current state.
#ECHO OFF
SETLOCAL
SET "spinChars=\|/-"
for /f %%a in ('"prompt $H&for %%b in (1) do rem"') do set "BS=%%a"
set "spaces= "
SET /a filesMoved = 0, spinPos = 0, prev = 0
echo Moving XML Files...
setlocal enabledelayedexpansion
for /L %%I in (1,1,7) do set "BS=!BS!!BS!"
for /L %%I in (1,1,3) do set "spaces=!spaces!!spaces!"
for /R "C:\" %%I in (*) do (
set /a filesMoved += 1
call :spinner !filesMoved! "%%~nxI"
)
call :spinner %filesMoved% Done.
endlocal & echo;
goto :EOF
:spinner <filecount> <filename>
set /a spinPos += 1, spinPos %%= 4, hundred = %~1 / 100 * 100
if "%~2"=="Done." set hundred=%~1
set "str=[!spinChars:~%spinPos%,1!] %hundred% files moved... (%~2)"
set "str=%str:~0,79%"
call :length len "%str%"
set /a diff = 79 - len
if %diff% gtr 0 set "str=%str%!spaces:~-%diff%!"
set /P "=!BS:~-79!%str%"<NUL
goto :EOF
:length <return_var> <string>
setlocal enabledelayedexpansion
if "%~2"=="" (set ret=0) else set ret=1
set "tmpstr=%~2"
for %%I in (4096 2048 1024 512 256 128 64 32 16 8 4 2 1) do (
if not "!tmpstr:~%%I,1!"=="" (
set /a ret += %%I
set "tmpstr=!tmpstr:~%%I!"
)
)
endlocal & set "%~1=%ret%"
goto :EOF
Related
I know that there must be some syntax issue on my end with this, but I can't for the life of me figure this out right now. This is a script I put together a few months back to automatically download some files for me as they release every month. It was working fine, however this month I noticed that nothing was downloading. After some troubleshooting and investigation, I found that the month variable was setting itself to "-1" instead of subtracting "1" from it's current value. As a result of this I'm unable to get the proper file name to attempt the download. It's the same match that I'm using on days, revision number, and year number, but for some reason the month variable just isn't cooperating with me and I can't figure out why.
:MASTER
#echo off
mode con:cols=100 lines=5
::Setup First Download
for /f "tokens=2*" %%a in ('REG Query "HKLM\SOFTWARE\Wow6432Node\ExampleRegistryKey" /v ExampleString 2^>nul') do set "ExampleDir=%%~b"
pushd "%ExampleDir%"
for /f "tokens=2 delims==" %%a in ('findstr SQLiteHome Example.ini') do set SQLiteHome=%%a
::Revision Number
set num=17
set /a "num=num-1"
::Begin set date
for /f "tokens=1-4 delims=/-. " %%i in ('date /t') do (call :set_date %%i %%j %%k %%l)
goto :end_set_date
:set_date
if "%1:~0,1%" gtr "9" shift
for /f "skip=1 tokens=2-4 delims=(-)" %%m in ('echo,^|date') do (set %%m=%1&set %%n=%2&set %%o=%3)
goto :eof
:end_set_date
set dd=31
This section here is where the month starts to equal -1 instead of current one subtracted from the current month.
set /a "mm=mm-1"
if %mm%==9 set mm=09
if %mm%==8 set mm=08
if %mm%==7 set mm=07
if %mm%==6 set mm=06
if %mm%==5 set mm=05
if %mm%==4 set mm=04
if %mm%==3 set mm=03
if %mm%==2 set mm=02
if %mm%==1 set mm=01
if %mm%==0 set /a "yy=yy-1"
if %mm%==0 set mm=12
Set EarlyEntry=early_up_sqlite_r
Set FullEntry=update_sqlite_r
Set MstarEntry=mstar_ext_sqlite_r
Set PSNEntry=psn_ext_sqlite_r
set CurrentEntry=%EarlyEntry%
set ThisFile=%CurrentEntry%%num%_%yy%%mm%%dd%.exe
ECHO %ThisFile%
set INIentry=EarlyLast
::Create %WorkingDirectory%\Dates.txt and Downloads.ini
set INIfile=C:\ProgramData\SA_Updater\Downloads.ini
set WorkingDirectory=C:\ProgramData\SA_Updater\
set OldDownloads=C:\ProgramData\SA_Updater\Downloads\
set PSNini=PSNLast
set MSTARini=MSTARLast
set Fullini=FullLast
set Earlyini=EarlyLast
echo %PSNini%
echo Dates > %WorkingDirectory%\Dates.txt
if not exist "%WorkingDirectory%" mkdir "%WorkingDirectory%"
if not exist "%OldDownloads%" mkdir "%OldDownloads%"
pusd %WorkingDirectory%
if not exist "%INIfile%" (
ECHO %PSNini%= > %INIfile%
ECHO %MSTARini%= >> %INIfile%
ECHO %Fullini%= >> %INIfile%
ECHO %Earlyini%= >> %INIfile%
)
:ObtainVariables
::Find the Last version downloaded
This is where I've kept a log for the download attempts
echo Dates > %WorkingDirectory%\Dates.txt
The output is looking like this:
Dates
http://Example.com/updates/early_up_sqlite_r16_2018-131.exe
http://Example.com/updates/early_up_sqlite_r15_2018-131.exe
http://Example.com/updates/early_up_sqlite_r14_2018-131.exe
Instead of:
Dates
http://Example.com/updates/early_up_sqlite_r16_20180731.exe
http://Example.com/updates/early_up_sqlite_r15_20180731.exe
http://Example.com/updates/early_up_sqlite_r14_20180731.exe
The rest of the script:
for /f "tokens=2 delims==" %%a in ('findstr %INIentry% %INIfile%') do set LastINIfile=%%a
ECHO %LastINIfile%
::Revision Number
set num=17
set /a "num=num-1"
::Begin set date
for /f "tokens=1-4 delims=/-. " %%i in ('date /t') do (call :set_date %%i %%j %%k %%l)
goto :end_set_date
:set_date
if "%1:~0,1%" gtr "9" shift
for /f "skip=1 tokens=2-4 delims=(-)" %%m in ('echo,^|date') do (set %%m=%1&set %%n=%2&set %%o=%3)
goto :eof
:end_set_date
set dd=31
set /a "mm=mm-1"
if %mm%==9 set mm=09
if %mm%==8 set mm=08
if %mm%==7 set mm=07
if %mm%==6 set mm=06
if %mm%==5 set mm=05
if %mm%==4 set mm=04
if %mm%==3 set mm=03
if %mm%==2 set mm=02
if %mm%==1 set mm=01
if %mm%==0 set /a "yy=yy-1"
if %mm%==0 set mm=12
set ThisFile=%CurrentEntry%%num%_%yy%%mm%%dd%.exe
goto Download
:Download
::Setup Download Variables
cls
set Download=http://Example.com/updates/%ThisFile%
GOTO TryDownload
:TryDownload
::Add Download Attempt to %WorkingDirectory%\Dates.txt
echo %Download% >> %WorkingDirectory%\Dates.txt
::Is the file download? If so, start the install
cls
mode con:cols=100 lines=10
powershell "Import-Module BitsTransfer; Start-BitsTransfer '%Download%' '%DownloadDir%'"
mode con:cols=100 lines=5
cls
::ping localhost -n 3 >nul
if exist C:\ProgramData\SA_Updater\%ThisFile% (
GOTO StartInstall
) else (
::Try Downloading
GOTO TryAgain
)
cls
:TryAgain
set /a "num=num-1"
if %mm%==9 set mm=09
if %mm%==8 set mm=08
if %mm%==7 set mm=07
if %mm%==6 set mm=06
if %mm%==5 set mm=05
if %mm%==4 set mm=04
if %mm%==3 set mm=03
if %mm%==2 set mm=02
if %mm%==1 set mm=01
if %num%==0 set /a "dd=dd-1"
if %dd%==27 set /a "mm=mm-1"
if %mm%==0 set /a "yy=yy-1"
if %mm%==0 set mm=12
if %dd%==27 set dd=33
if %num%==0 set num=17
set ThisFile=%CurrentEntry%%num%_%yy%%mm%%dd%.exe
set Download=http://Example.com/updates/%ThisFile%
set DownloadDir=%WorkingDirectory%%ThisFile%
if %ThisFile% EQU %LastINIfile% GOTO CheckEarly
GOTO TryDownload
)
:StartInstall
%WorkingDirectory%%ThisFile% /w /v"INSTALLPREREQUISITES=0"
robocopy %WorkingDirectory% %OldDownloads% %ThisFile%
pushd %WorkingDirectory%
del %ThisFile%
del /Q /A H *.tmp
GOTO DoINIstuff
::Update ThisFile
:CheckEarly
if %CurrentEntry% EQU %EarlyEntry% GOTO SetupFull
GOTO CheckFull
:CheckFull
if %CurrentEntry% EQU %FullEntry% GOTO SetupMstar
GOTO CheckMstar
:CheckMstar
if %CurrentEntry% EQU %MstarEntry% GOTO SetupPSN
GOTO CheckPSN
:CheckPSN
if %CurrentEntry% EQU %PSNEntry% GOTO SetupEarly
GOTO CheckEarly
::Setups
:SetupFull
set CurrentEntry=%FullEntry%
set INIentry=%Fullini%
GOTO ObtainVariables
:SetupMstar
set CurrentEntry=%MstarEntry%
set INIentry=%MSTARini%
GOTO ObtainVariables
:SetupPSN
set CurrentEntry=%PSNEntry%
set INIentry=%PSNini%
GOTO ObtainVariables
:SetupEarly
set CurrentEntry=%EarlyEntry%
set INIentry=%Earlyini%
GOTO ObtainVariables
:DoINIstuff
SetLocal EnableDelayedExpansion
Set _PathtoFile=%INIfile%
Set _OldLine=%INIentry%=
Set _NewLine=%INIentry%=%ThisFile%
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
PopD
Goto :CheckEarly
:_Parse
Set _FilePath=%~dp1
Set _FileName=%~n1
Set _FileExt=%~x1
Goto :EOF
I hope I haven't omitted too much to figure this out. Basically, I can see that the revision number and the day are acting like they should, but the month just reverts to "-1" instead of actually performing the subtraction, and I'm basically pulling my hair out trying to figure out what I'm doing wrong.
The reason is quite simple. A number string with a leading 0 is interpreted as octal number by C function strtol used by cmd.exe to convert a number string to an integer.
08 and 09 are invalid numbers in octal numeral system and for that reason function strtol returns 0 which is subtracted next by 1 resulting in -1.
The simple solution is using set /a "mm=1%mm%-101" instead of set /a "mm=mm-1". Then first the month value is concatenated as string with the character 1 building the strings 101 to 112 and so the number string has no leading 0 anymore and from this number 101 is subtracted to get 0 to 11 assigned as string to environment variable mm.
By the way: Use the following two command lines to get back the leading zero after subtraction:
set "mm=0%mm%"
set "mm=%mm:~-2%"
The first line concatenates 0-11 to 00-011 and the second line takes just the last two characters of this string resulting in 00-11 assigned finally to environment variable mm.
The next two lines should be replaced by: if %mm% == 00 set "mm=12" & set /a "yy-=1"
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).
Good Afternoon!
Long time reader, first time poster! I have been having a lovely time trying to modify a working batch file to account for variability. The situation is that I have a variable-size text document that normally would be able to be split into sections of 252 lines. The code below worked like a champ:
#echo off & setlocal EnableDelayedExpansion
set param=%*
if not defined param (
echo.
echo. Usage: batchsplit [device:][pathname]filename
goto :EOF
)
set param=%param:"=%
if not exist "%param%" (
echo.
echo. File "%param%" not found
goto :EOF
)
for %%j in ("%param%") do (
set name=%%~dpnj
set ext=%%~xj
)
for /F %%j in ('type "%param%" ^| find /V /C ""') do set Full=%%j
set /A Split=%Full%/252
for /L %%G in (1,1,%Split%) do type nul > "%name%_%%G%.new"
set X=1
set N=1
set Q=1
set limit = 252
for /F "tokens=1* delims=]" %%j in ('type "%param%" ^| find /V /N ""') do (
set /A N+=1
set /A Q+=1
echo.%%k>> "%name%_!X!%.new"
if !Q! gtr 252 (
set /A X+=1
set /A Q=1
) else if !N! gtr Full (goto theend
)
)
:theend
echo split into %split% files with 252 lines each
rem pause
However, there were some changes to the formatting of the text, and now instead of four pages of 63 lines per split file, it can be completely variable. The only constant is this final line, which precedes the remaining space for a 63 line page:
ON THIS FORM IS COMPLETE AND CORRECT AS NOTED:___________________
Note that there is a single space in front of it, as well as multiple spaces, a colon, and underscore characters. Being the meathead that I am, I thought I could insert an if-then statement into the for loop to trigger the batch to split to the next page. However, I could be further from that right now. This is the code I have been smashing my head with:
rem #echo off & setlocal EnableDelayedExpansion
setlocal EnableDelayedExpansion
set param=%*
if not defined param (
echo.
echo. Usage: textsplit [device:][pathname]filename
goto :EOF
)
set param=%param:"=%
if not exist "%param%" (
echo.
echo. File "%param%" not found
goto :EOF
)
for %%j in ("%param%") do (
set Name=%%~dpnj
set ext=%%~xj
)
for /F %%j in ('type "%param%" ^| find /V /C ""') do set Full=%%j
set stopvar= ON THIS FORM IS COMPLETE AND CORRECT AS NOTED:___________________
set Split=1
echo %stopvar%
set X=1
type nul > "%name%_!X!%.new"
set N=1
set Q=1
set S=0
set L=63
for /F "tokens=1* delims=]" %%j in ('type "%param%" ^| find /V /N ""') do (
set /A N+=1
echo %N%
set /A Q+=1
echo %Q%
echo.%%k>> "%name%_!X!%.new"
if ["%%k%" == "!stopvar!"] (
set /A S+=1
)
if !Q! gtr !L! (
if !S! == 1 (
set /A X+=1
set /A Q=1
type nul > "%name%_!X!%.new"
set /A Split+=1
set S=0
)
else set /A L+=63
else if !N! gtr Full goto theend
)
:theend
echo Split into %split% files!
pause
The premise is that every 63 lines, the stop variable (S) is checked. If it is off (0) then the batch will continue to write for another 63 lines (one page). If the stopvar matches the line that is being read by the for loop, S becomes 1. When the program checks again, it will create a new file and begin writing to that new file. Right now, based on turning off #echo off the hangup is at the for loop. See below:
C:\Users\theangryasiancp\Desktop\TEXT_Split_Test>rrtextsplit texttest.txt
C:\Users\theangryasiancp\Desktop\TEXT_Split_Test>rem #echo off & setlocal Enabl
eDelayedExpansion
C:\Users\theangryasiancp\Desktop\TEXT_Split_Test>setlocal EnableDelayedExpansio
n
C:\Users\theangryasiancp\Desktop\TEXT_Split_Test>set param=texttest.txt
C:\Users\theangryasiancp\Desktop\TEXT_Split_Test>if not defined param (
echo.
echo. Usage: rrtextsplit [device:][pathname]filename
goto :EOF
)
C:\Users\theangryasiancp\Desktop\TEXT_Split_Test>set param=texttest.txt
C:\Users\theangryasiancp\Desktop\TEXT_Split_Test>if not exist "texttest.txt" (
echo.
echo. File "texttest.txt" not found
goto :EOF
)
C:\Users\theangryasiancp\Desktop\TEXT_Split_Test>for %j in ("texttest.txt") do
(
set Name=%~dpnj
set ext=%~xj
)
C:\Users\theangryasiancp\Desktop\TEXT_Split_Test>(
set Name=C:\Users\theangryasiancp\Desktop\TEXT_Split_Test\texttest
set ext=.txt
)
C:\Users\theangryasiancp\Desktop\TEXT_Split_Test>for /F %j in ('type "texttest.
txt" | find /V /C ""') do set Full=%j
C:\Users\theangryasiancp\Desktop\TEXT_Split_Test>set Full=567
C:\Users\theangryasiancp\Desktop\TEXT_Split_Test>set stopvar= ON THIS FORM IS C
OMPLETE AND CORRECT AS NOTED:___________________
C:\Users\theangryasiancp\Desktop\TEXT_Split_Test>set Split=1
C:\Users\theangryasiancp\Desktop\TEXT_Split_Test>echo ON THIS FORM IS COMPLETE
AND CORRECT AS NOTED:___________________
ON THIS FORM IS COMPLETE AND CORRECT AS NOTED:___________________
C:\Users\theangryasiancp\Desktop\TEXT_Split_Test>set X=1
C:\Users\theangryasiancp\Desktop\TEXT_Split_Test>type nul 1>"C:\Users\theangry
asiancp\Desktop\RRRR_Split_Test\texttest_!X!.new"
C:\Users\theangryasiancp\Desktop\TEXT_Split_Test>set N=1
C:\Users\theangryasiancp\Desktop\TEXT_Split_Test>set Q=1
C:\Users\theangryasiancp\Desktop\TEXT_Split_Test>set S=0
C:\Users\theangryasiancp\Desktop\TEXT_Split_Test>set L=63
C:\Users\theangryasiancp\Desktop\TEXT_Split_Test>
What are your thoughts? Where am I going wrong with the batch? I wish I could use something different, but alas I cannot, for internal company reasons. Thanks for your help!
#ECHO OFF
SETLOCAL ENABLEDELAYEDEXPANSION
SET "name=q23396663"
SET "ext=.txt"
SET /a pagelength=10
SET "targetstring= ON THIS FORM IS COMPLETE AND CORRECT AS NOTED:___________________"
SET /a filenum=0
SET /a linecount=pagelength + 1
FOR /f "tokens=1*delims=]" %%a IN (
'find /v /n "" "%name%%ext%"') DO (
IF !linecount! GEQ %pagelength% (
SET /a linecount=0
SET /a filenum+=1
)
>>U:\%name%_!filenum!.new ECHO(%%b
IF "%%b"=="%targetstring%" SET /a linecount=pagelength
SET /a linecount+=1
)
GOTO :EOF
For testing purposes, I set up a file q23396663.txt containing your trigger data. I've left the destination directory as U:\ which suits me, and the pagelength at 10 which makes my testing easier.
#echo off
setlocal EnableDelayedExpansion
REM ------------------THIS SECTION SPECIFIES THE FILE-------------------------
set param=%*
if not defined param (
echo.
echo. Usage: filesplit [device:][pathname]filename
goto :EOF
)
set param=%param:"=%
if not exist "%param%" (
echo.
echo. File "%param%" not found
GOTO :EOF
)
for %%j in ("%param%") do (
set name=%%~dpnj
set ext=%%~xj
)
ECHO SPLITTING %name%.%ext% .................
REM ----------------THIS SECTION SETS THE VARIABLES---------------------------
set "trigger= ON THIS FORM IS COMPLETE AND CORRECT AS NOTED:___________________"
set /a pagelength=63
set /a filenum=0
set split=1
set /a linecount=pagelength
set stopvar=0
REM ------------------THIS SECTION IS THE FOR LOOP----------------------------
FOR /f "skip=2 tokens=1* delims=]" %%a IN (
'find /v /n "" "%name%%ext%"') DO (
SET /a linecount-=1
IF !linecount! LEQ 0 (
IF !stopvar! EQU 1 (
SET /a "linecount=pagelength"
SET /a filenum+=1
SET /a split+=1
SET /a stopvar-=1
) else set /a "linecount=pagelength"
)
echo.%%b>> "%name%_!filenum!.new"
IF "%%b"=="%trigger%" (
set /a "stopvar+=1"
REM THIS TRIGGERS TO CHANGE OUTPUT
set /a linecount+=1
REM THIS WILL ADJUST THE OUTPUT EOF
)
)
REM ----------------THIS SECTION ENDS THE FOR LOOP----------------------------
ECHO Split into %split% files!
ping 1.1.1.1 -n 1 -w 2500 > nul
REM THIS PAUSES THE BATCH FOR A SEC
As I posted in the comment above, this is just a variation of the first answer that accounts for blank spaces if they are needed to keep the output files from having unnecessary whitespace on top. This is especially helpful when a print manager is just spitting out whitespace until the end of the page before starting the next part instead of going straight to the next portion.
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
I need to get file name with out the file extension, folder name out putted to a csv file. I am able to get file name and folder name using:
#ECHO OFF
SETLOCAL
PUSHD "%~1"
FOR /f "delims=" %%i IN ("%cd%") DO SET directory=%%~nxi
(
FOR /f "delims=" %%i IN ('dir /b /a-d /on') DO (
SETLOCAL enabledelayedexpansion
ECHO "%%i","!directory!"
endlocal
)
)>filelist.csv
How can I rewrite this so the file extension is removed and if there are subfolders it will grab the subfolder name too?
#echo off
setlocal enableextensions disabledelayedexpansion
if not "%~1"=="" (
(for /f "tokens=*" %%i in ('dir /s /b /on "%~1\*"') do (
set "file=%%~dpni"
setlocal enabledelayedexpansion
echo(!file:%~dp1=!
endlocal
)) > filelist.csv
) else (
call "%~f0" "%cd%"
)
endlocal
Not sure about the final format. Try and comment.
EDITED - to handle case exposed by Andriy M
#echo off
setLocal
pushd "%~1"
set "cur_path=%cd:~2%"
setLocal enableDelayedExpansion
FOR /f "delims=" %%i IN ('dir /b /s /a-d /on') DO (
SET "file_path=%%~dpni"
SET "file_path=!file_path:~2!"
SET "file_path=!file_path:%cur_path%=!"
ECHO "!file_path!","%%~di%cur_path%"
)
endLocal
endLocal
EDIT
with additional ~ replacing (comparatively slow - could be optimized with macros... ):
#echo off
pushd .
set "cur_path=%cd:~2%"
call :wavereplacer "%cur_path%" "-" nw_cur_path
setlocal enableDelayedExpansion
FOR /f "delims=" %%i IN ('dir /b /s /a-d /on') DO (
SET "file_path=%%~dpni"
SET "file_path=!file_path:~2!"
SET "file_path=!file_path:%cur_path%=!"
CALL :wavereplacer "!file_path!" "-" file_path
ECHO "!file_path!","%%~di%nw_cur_path%"
)
endlocal
endlocal
goto :eof
:wavereplacer String Replacer [RtnVar]
setlocal
rem the result of the operation will be stored here
set "result=#%~1#"
set "replacer=%~2"
call :strlen0.3 result wl
call :strlen0.3 replacer rl
:start
set "part1="
set "part2="
rem splitting the string on two parts
for /f "tokens=1* delims=~" %%w in ("%result%") do (
set "part1=%%w"
set "part2=%%x"
)
rem calculating the count replace strings we should use
call :strlen0.3 part1 p1l
call :strlen0.3 part2 p2l
set /a iteration_end=wl-p1l-p2l
rem creating a sequence with replaced strings
setlocal enableDelayedExpansion
set "sequence="
for /l %%i in (1,1,%iteration_end%) do (
set sequence=!sequence!%replacer%
)
endlocal & set "sequence=%sequence%"
rem adjust the string length
set /a wl=wl+iteration_end*(rl-1)
rem replacing for the current iteration
set result=%part1%%sequence%%part2%
rem if the second part is empty the task is over
if "%part2%" equ "" (
set result=%result:~1,-1%
goto :endloop
)
goto :start
:endloop
endlocal & if "%~3" neq "" (set %~3=%result%) else echo %result%
exit /b
: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