I was going over an example batch file that was able to display a variable outside of a loop:
#echo off
setlocal EnableDelayedExpansion
:: count to 5 storing the results in a variable
set _tst=0
FOR /l %%G in (1,1,5) Do (echo [!_tst!] & set /a _tst+=1)
echo Total = %_tst%
It's able to echo %_tst% because it's declared at the top before the loop.
I tried it with a batch file that I'm currently using:
#echo off
cls
setlocal EnableDelayedExpansion
set drive=R:
set counter=0
FOR /F "tokens=*" %%c IN ('dir %USERPROFILE%\Backup /B') DO (set /A counter+=1)
if %counter% GTR 0 (
echo Total # of folders: %counter%
) else (
echo No folders to move
)
It works, but, when I try to check if a drive is available before executing the loop, I have the use !counter! to access the variable, like so:
If I don't, it just says "Please press any key to continue." because of the pause.
#echo off
cls
setlocal EnableDelayedExpansion
set drive=R:
set counter=0
if exist %drive% (
FOR /F "tokens=*" %%c IN ('dir %USERPROFILE%\Backup /B') DO (set /A counter+=1)
if !counter! GTR 0 (
echo You have !counter! folder(s)
) else (
echo No folders to move
)
)
pause
exit /b
Why is it that when I have the if statement checking if my drive is available I have to use !counter!?
You have a problem with the ) in the text file(s) - this closes the inner if !counter! GTR 0 block. Then it sees another ) which closes the outer if exist %drive% block.
To fix this, escape the ) in the echo:
if exist %drive% (
FOR /F "tokens=*" %%c IN ('dir %USERPROFILE%\Backup /B') DO (set /A counter+=1)
if !counter! GTR 0 (
echo You have !counter! folder^(s^)
) else (
echo No folders to move
)
)
Related
How can we split string using windows bat script?
for below .bat code snippet
#echo off & setlocal EnableDelayedExpansion
set j=0
for /f "delims=""" %%i in (config.ini) do (
set /a j+=1
set con!j!=%%i
call set a=%%con!j!%%
echo !a!
(echo !a!|findstr "^#">nul 2>nul && (
rem mkdir !a!
) || (
echo +)
rem for /f "tokens=2" %%k in(config.ini) do echo %%k
)
)
pause
below config file
Q
What's wrong when I del rem at the begin of rem for /f "tokens=2" %%k in(config.ini) do echo %%k
How can I get the /path/to/case and value as a pair?
for /f xxxx in (testconfig.ini) do (set a=/path/to/case1 set b=vaule1)
#ECHO OFF
SETLOCAL ENABLEDELAYEDEXPANSION
SET "sourcedir=U:\sourcedir"
SET "filename1=%sourcedir%\q43407067.txt"
set j=0
for /f "delims=""" %%i in (%filename1%) do (
set /a j+=1
set con!j!=%%i
call set a=%%con!j!%%
echo !a! SHOULD BE EQUAL TO %%i
(echo !a!|findstr "^#">nul 2>nul && (
echo mkdir !a!
) || (
echo +)
for /f "tokens=2" %%k IN ("%%i") do echo "%%k"
for /f "tokens=1,2" %%j IN ("%%i") do echo "%%j" and "%%k"
)
)
ECHO ----------------------------
SET con
GOTO :EOF
You would need to change the setting of sourcedir to suit your circumstances.
I used a file named q43407067.txt containing your data for my testing.
(These are setting that suit my system)
SO - to address your problems:
because the ) on that line closes the ( on the previous. The ) on that line closes the ( on the one prior. (I changed the rem to an echo so that the code would produce something visible) The first ( on the (echo !a! line is closed by the ) on the line following the (now) two for /f commands. and the ( on the for..%%i..do( is closed by the final ) before the echo -----
You can't delete that ) because it's participating in a parenthesis-pair.
You need a space between the in and the (.
I've shown a way. See for /?|more from the prompt for documentation (or many articles here on SO)
In your code, !a! is the same as %%i - so I've no idea why you are conducting all the gymnastics - doubtless to present a minimal example showing the problem.
Note that since the default delimiters include Space then if any line contains a space in the /path/to/case or value then you'll have to re-engineer the approach.
I' not sure if I understand what exactly it is you need, so what follows may not suit your needs:
#Echo Off
SetLocal EnableDelayedExpansion
Set "n=0"
For /F "Delims=" %%A In (testConfig.ini) Do (Set "_=%%A"
If "!_:~,1!"=="#" (Set/A "n+=1", "i=0"
Echo=MD %%A
Set "con[!n!]!i!=%%A") Else (For /F "Tokens=1-2" %%B In ('Echo=%%A'
) Do (Set/A "i+=1"
Set "con[!n!]!i!=%%B"&&Set/A "i+=1"&&Set "con[!n!]!i!=%%C")))
Set con[
Timeout -1
GoTo :EOF
remove Echo= on line 6 if you are happy with the output and really want to create those directories
test_title.bat
:GET_DOWNLOADS
set Counter=-1
for /f "DELIMS=" %%i in ('type version.txt') do (
set /a Counter+=2
set "Line_!Counter!=%%i"
)
if exist version.txt del version.txt
exit /b
:list_files
call :GET_DOWNLOADS
For /L %%C in (1,2,%Counter%) Do (
:: removing this part makes it work fine
set line=%%C
set /a line+=1
set /a line/=2
:: alternate way doesnt work either
REM set /a line=%line% / 2
:: this part without the math part would be %%C instead of %Line%
echo %line%. !Line_%%C!
)
pause
(made an edit)
the second part isnt working for some reason
it just crashes
if i remove the line that does the math it works fine but instead display 1. 3. 5. 7.
version.txt
everything
0
minecraft
0
steam
0
obs
0
fixed test_list.bat :D
#echo off
setlocal enabledelayedexpansion
set "num=1"
set "counter=0"
for /f "DELIMS=" %%i in (version.txt) do (
set /a num+=1
if "!num!"=="2" (set /a counter+=1&set "line_!counter!=%%i"&set num=0)
)
echo.
For /L %%C in (1,1,%Counter%) Do (echo %%C. !Line_%%C!)
pause
#echo off
setlocal enabledelayedexpansion
set "num=1"
set "counter=0"
for /f "DELIMS=" %%i in (version.txt) do (
set /a num+=1
if "!num!"=="2" (set /a counter+=1&set "line_!counter!=%%i"&echo %%i&set num=0)
)
echo.
set line_1
set line_2
set line_3
pause
Would output:
everything
minecraft
steam
obs
line_1=everything
line_2=minecraft
line_3=steam
I am trying to write a .bat file that allows me to traverse through directories (up or down) and let me select a file from the current directory, passing that filename out at the end of the routine. Ideally, it would handle if it is at the root of a drive (i.e. C:) or that there are no more sub directories.
(If there are more elegant ways of doing what I am asking, please feel free to suggest them!)
#echo off
setlocal enabledelayedexpansion
set FVAR=
:start
::-------------------------------------------------------
:: LIST - Lists all files in the current folder
::-------------------------------------------------------
:LIST
echo.
if exist . echo ^<DIR^> .
if exist .. echo ^<DIR^> ..
for /f "tokens=* delims=" %%a in ('dir /b /ad') do (
echo ^<DIR^> %%a
)
for /f "tokens=* delims=" %%a in ('dir /b /a-d') do (
echo %%a
)
::-------------------------------------------------------
:: INPUT - Requests filename as input from user
::-------------------------------------------------------
:INPUT
echo.
set /p FVAR="Choose your file [HINT: hit <TAB> to cycle the current folder contents]: "
echo.
echo %FVAR%
if not defined FVAR (goto TRYAGAIN)
set FVARFLAG1=0
set FVARFLAG2=0
set FVARFLAG=%FVARFLAG1%%FVARFLAG2%
echo %FVARFLAG%
if exist %FVAR%\ set "%FVARFLAG1%"=="1"
if exist %FVAR% set "%FVARFLAG2%"=="1"
set FVARFLAG=%FVARFLAG1%%FVARFLAG2%
echo %FVARFLAG%
if "%FVARFLAG%"=="00" goto TRYAGAIN
if "%FVARFLAG%"=="01" goto FILE
if "%FVARFLAG%"=="10" goto DIR
if "%FVARFLAG%"=="11" goto TRYAGAIN
goto TRYAGAIN
:DIR
if exist %FVAR%\ (
echo Successfully set dir name!
goto END
)
goto TRYAGAIN
:FILE
if exist %FVAR% (
echo Successfully set file name!
goto END
)
goto TRYAGAIN
rem if /i "%option:"=%"=="Y" goto YES //This line left in for future use
rem if /i "%option:"=%"=="N" goto NO //This line left in for future use
goto END
::-------------------------------------------------------
:: TRYAGAIN - Returns user to input menu on invalid entry
::-------------------------------------------------------
:TRYAGAIN
echo ------------------------------
echo Invalid selection...try again
echo ------------------------------
goto INPUT
:END
goto :EOF
I like this application! The use of arrays allows you to write simpler and more powerful code. This is my version:
#echo off
setlocal EnableDelayedExpansion
rem Select a file browsing a directory tree
rem Antonio Perez Ayala
set pageSize=30
rem Load current directory contents
:ProcessThisDir
for /F "delims==" %%a in ('set name[ 2^>NUL') do set "%%a="
set numNames=0
for /D %%a in (*) do (
set /A numNames+=1
set "name[!numNames!]=<DIR> %%a"
)
for %%a in (*.*) do (
set /A numNames+=1
set "name[!numNames!]= %%a"
)
rem Show directory contents, one page at a time
set start=1
:ShowPage
if %start% equ 1 (
set "less="
) else (
set "less=-=Previous page, "
)
set /A end=start+pageSize-1
if %end% gtr %numNames% (
set end=%numNames%
set "more="
) else (
set "more=+=Next page, "
)
cls
echo Directory: %CD%
echo/
for /L %%i in (%start%,1,%end%) do echo %%i- !name[%%i]!
echo/
:GetOption
set "option="
set /P "option=Enter desired item (%less%%more%Nothing=..): "
if not defined option (
cd ..
goto ProcessThisDir
) else if "%option%" equ "-" (
set /A start-=pageSize
if !start! lss 1 set start=1
goto ShowPage
) else if "%option%" equ "+" (
if defined more set /A start+=pageSize
goto ShowPage
) else if not defined name[%option%] (
goto GetOption
) else if "!name[%option%]:~0,5!" equ "<DIR>" (
cd "!name[%option%]:~8!"
goto ProcessThisDir
)
rem Return selected file
cls
for %%a in ("!name[%option%]:~8!") do set "result=%%~Fa"
echo Result="%result%"
I have a few directories, named "A", "B", "C", and so on. Each has some files in it. I like to rename files in each directory using directory name plus an index number starting with 1 in each directory, with left-zero padded to the width of 3. For example:
Sub directory A has 3 files, and they'll be renamed as:
A_001.dat
A_002.dat
A_003.dat
Sub directory B has 2 files, and they should be renamed as:
B_001.dat
B_002.dat
and so on. These files will be moved to the main directory. I have the following batch file, but I can't seem to increment the number. Please help.
#echo off
set HomeFolder=%CD%
set OldExt=TXT
set NewExt=DAT
setlocal ENABLEDELAYEDEXPANSION
for /f "delims=" %%a in ('dir *.%OldExt% /b /s') do (
set i=1
for /f "delims=" %%b in ("%%~dpa\.") do (
set pad=00!i!
set str=!pad:~-3!
echo move /b "%%a" "%HomeFolder%\%%~nxb_!str!.%NewExt%"
set /A i=!i!+1
)
)
endlocal
pause
And the correct answer is:
#echo off
set HomeFolder=%CD%
set OldExt=TXT
set NewExt=TIF
set i=1
set Folder=
set LastFolder=
setlocal ENABLEDELAYEDEXPANSION
for /f "delims=" %%a in ('dir *.%OldExt% /b /s') do (
for /f "delims=" %%b in ("%%~dpa\.") do (
set Folder=%%~nxb
if NOT !Folder!==!LastFolder! (set /A i=1)
set LastFolder=!Folder!
set pad=00!i!
set str=!pad:~-3!
copy /b "%%a" "%HomeFolder%\%%~nxb_!str!.%NewExt%"
Set /A i+=1
)
)
endlocal
In a loop or parenthetical expression you need to use a delayed expansion
set /a variable=!variable!+1
But you need to activate this feature with setlocal ENABLEDELAYEDEXPANSION and reset it with a matching endlocal
Try the following:
#echo off
set HomeFolder=%CD%
set OldExt=TXT
set NewExt=DAT
setlocal ENABLEDELAYEDEXPANSION
for /f "delims=" %%a in ('dir *.%OldExt% /b /s') do (
set i=1
for /f "delims=" %%b in ("%%~dpa\.") do (
set pad=00%i%
set str=%pad:~-3%
echo move /b "%%a" "%HomeFolder%\%%~nxb_%str%.%NewExt%"
set /A i+=1
)
)
endlocal
pause
#echo off
:: By Elektro H#cker
Setlocal enabledelayedexpansion
set "OldExt=TXT"
set "NewExt=DAT"
FOR /R %%# in (*%OldExt%) DO (
REM Sets the directory of the file
Set "Directory=%%~dp#"
REM Cuts the directory name to obtain the last folder name
Set "Directory=!Directory:~0,-1!"
For /L %%X in (0,1,50) DO (Call Set "Directory=!Directory:*\=!")
REM Check if this directory is the same of the last accesed directory to reset the counter or not
Echo "!Directory!"|FINDSTR "^\"!LastDirectory!\"$" >NUL && (Set /A "Count+=1") || (Set /A "Count=1")
REM Check if the number incrementation have 1-3 digits and copies the file
Call Echo !COUNT!|FINDSTR "^[0-9]$" >NUL && (Call Copy "%%#" ".\!Directory!_00!COUNT!.%NewExt%")
Call Echo !COUNT!|FINDSTR "^[0-9].$" >NUL && (Call Copy "%%#" ".\!Directory!_0!COUNT!.%NewExt%" )
Call Echo !COUNT!|FINDSTR "^[0-9]..+$" >NUL && (Call Copy "%%#" ".\!Directory!_!COUNT!.%NewExt%" )
REM Sets the last accesed directory
Call Set "LastDirectory=!Directory!"
)
Pause&exit
3 subdirs named "A" "B" and "C", 3 files inside of each subdir, the output result is:
a_001.DAT
a_002.DAT
a_003.DAT
b_001.DAT
b_002.DAT
b_003.DAT
c_001.DAT
c_002.DAT
c_003.DAT
Here is the working script for whoever wants to do the same thing:
#echo off
set HomeFolder=%CD%
set OldExt=TXT
set NewExt=DAT
set i=1
set Folder=
set LastFolder=
setlocal ENABLEDELAYEDEXPANSION
for /f "delims=" %%a in ('dir *.%OldExt% /b /s') do (
for /f "delims=" %%b in ("%%~dpa\.") do (
set Folder=%%~nxb
if NOT !Folder!==!LastFolder! (set /A i=1)
set LastFolder=!Folder!
set pad=00!i!
set str=!pad:~-3!
copy /b "%%a" "%HomeFolder%\%%~nxb_!str!.%NewExt%"
Set /A i+=1
)
)
endlocal
In a DOS script that I wrote, I am unable to figure out what causes this error that I get:
The system cannot find the file specified.
Error occurred while processing: .exe.
Here is the script. Any help would be greatly appreciated. I tried to ask for help on the DosTips forum but I am getting no answer. :
#echo off
:: script to edit property files
CALL :PROPEDIT # Key4 Value446 test.properties
GOTO :END
:PROPEDIT [#] PropKey PropVal File
IF "%~1"=="#" (
:: Passing a first argument of "#" will disable the line while editing
SET "_PREFIX=#"
SHIFT
)
IF NOT "%~4"=="" (
ECHO Too many arguments.
EXIT /B 1
)
IF "%~3"=="" (
ECHO PROPEDIT: Function requires 3 args: [#] PropKey PropVal File
EXIT /B 1
) ELSE (
SET "_PROPKEY=%~1"
SET "_PROPVAL=%~2"
SET "_FILE=%~3"
)
MOVE /Y "%_FILE%" "%_FILE%.bak">nul
FOR /F "USEBACKQ tokens=*" %%A IN (`TYPE "%_FILE%.bak" ^|FINDSTR /N /I "%_PROPKEY%="`) DO (
SET LINE=%%A
)
FOR /F "tokens=1,2* delims=:" %%S IN ("%LINE%") DO SET LINE=%%S
SET /A COUNT=1
FOR /F "USEBACKQ delims=" %%A IN (`TYPE "%_FILE%.bak" ^|FIND /V /N ""`) DO (
SET "LN=%%A"
SETLOCAL ENABLEDELAYEDEXPANSION
SET "LN=!LN:*]=!"
IF "!COUNT!" NEQ "%LINE%" (
ECHO(!LN!>>%_FILE%
) ELSE (
ECHO %_PREFIX%%_PROPKEY%=%_PROPVAL%>>%_FILE%
ECHO Updated '%_FILE%' with value '%_PREFIX%%_PROPKEY%=%_PROPVAL%'.
)
ENDLOCAL
SET /A COUNT+=1
)
EXIT /B 0
:END
ECHO --- Finished Test ---
pause
Remove the .EXE of FIND and TYPE
You don't need TYPE. You can do just this:
FOR /F "tokens=*" %%A IN (`FIND /N /I "%_PROPKEY%=" "%_FILE%.bak"`) DO (
If FIND spoils your results (by not using TYPE) then consider using FINDSTR instead and use 'DELIMS=:' instead of 'DELIMS=]'
If I'm right my assumption that the following is helpful, take a look at the 'MORE +nnn' command (note the '+nnn' which outputs lines from a specific location in the file).
Why not just place your 'SETLOCAL ENABLE.. etc' at the top of your code?
If you explain what it is you're trying to attempt, then I might be in a better position to help.
Just a few thoughts :)
Here is the working code after getting some help from Paul Tomasi:
#echo off
SETLOCAL DISABLEDELAYEDEXPANSION
CALL :PROPEDIT # Key4 Value446 test.properties
GOTO :END
:PROPEDIT [#] PropKey PropVal File
IF "%~1"=="#" (
:: Passing a first argument of "#" will disable the line while editing
SET "_PREFIX=#"
SHIFT
)
IF NOT "%~4"=="" (
ECHO Too many arguments.
EXIT /B 1
)
IF "%~3"=="" (
ECHO PROPEDIT: Function requires 3 args: [#] PropKey PropVal File
EXIT /B 1
) ELSE (
SET "_PROPKEY=%~1"
SET "_PROPVAL=%~2"
SET "_FILE=%~3"
)
MOVE /Y "%_FILE%" "%_FILE%.bak">nul
FOR /F "USEBACKQ tokens=*" %%A IN (`TYPE "%_FILE%.bak" ^|FINDSTR /N /I "%_PROPKEY%="`) DO (
SET LINE=%%A
)
FOR /F "tokens=1,2* delims=:" %%S IN ("%LINE%") DO SET LINE=%%S
SET /A COUNT=1
FOR /F "USEBACKQ delims=" %%A IN (`TYPE "%_FILE%.bak" ^|FIND /V /N ""`) DO (
SET "LN=%%A"
SETLOCAL ENABLEDELAYEDEXPANSION
SET "LN=!LN:*]=!"
IF "!COUNT!" NEQ "%LINE%" (
ECHO(!LN!>>%_FILE%
) ELSE (
ECHO %_PREFIX%%_PROPKEY%=%_PROPVAL%>>%_FILE%
ECHO Updated '%_FILE%' with value '%_PREFIX%%_PROPKEY%=%_PROPVAL%'.
)
SETLOCAL DISABLEDELAYEDEXPANSION
SET /A COUNT+=1
)
EXIT /B 0
:END
ECHO --- Finished Test ---
pause