Batch: How to scroll through files to read to a variable? - windows

I'm trying to have it scroll through a directory and present a new variable when the user replies "N". I have it all figured out except how to go to the next variable.
cd "C:\Test"
for /r %%F in (*) do SET Show=%%~NF
echo %Show%
echo.
SET /P Continue=Continue?(Y/N)
if /I "%Continue%" EQU "y" goto :Run
if /I "%Continue%" EQU "n" goto :Start

If you're looking to scroll the directory and prompt the user the file name and have them choose to choose it or continue, then bellow should help you.
Firstly, we can use dir /b /a:d to display only directories (folders) in the the current directory. By using a code block ( & ) we can put batch script inside the for loop. For your sake, we can use the CHOICE command to prompt to continue the loop or to save current folder to string and do something with it.
ScrollTreeWithPrompt.bat:
#echo off
setlocal EnableDelayedExpansion
Rem | Configuration
Set "MainDir=C:\Test"
Rem | Get Each Project Folder
for /f "tokens=*" %%A in ('dir "!MainDir!\" /b /a:d') do (
Cls
Echo Current Folder: %%A
echo(
CHOICE /M "Continue?"
Rem | Check for "N" - If so Set String & goto
IF "!ERRORLEVEL!"=="2" (
Set "Choice=%%A"
GOTO Run
)
)
Rem | No Further Results
Cls
Echo Warning: No further folders found.
pause>NUL
goto :EOF
:Run
Cls
echo Currently selected: !MainDir!\!Choice!
pause>NUL
goto :EOF
I have left a few Rem comments in the script to help you along. For any more help on the commands, type the following into a command prompt:
choice /?
set /?
for /?
goto /?

Is this what you need:
For /R "C:\Test" %%A In (*) Do (Choice /M "%%~nA"
If Not ErrorLevel 2 (Set "Show=%%~nA" & GoTo Run))
Exit /B
:Run
Echo Running against %Show%
Pause
Alternatively, should you wish to return to the loop after running against the file name, then use Call instead of GoTo:
For /R "C:\Test" %%A In (*) Do (Choice /M "%%~nA"
If Not ErrorLevel 2 Call :Run "%%~nA")
Exit /B
:Run
Set "Show=%~1"
Echo Running against %Show%
Pause

Related

Issue with "findstr" using Batch

Below, I wrote some code. It detects if a Micro-SD card is inserted into the computer and if so, it will ask to enter your pin. After you enter the pin, it will look through the card for a text file that contains a list of pins.
:start
cls
echo.
echo.
if exist E:\ (
goto enterPin
) else (
echo INSERT YOUR CARD
)
timeout 1 >nul
goto start
:enterPin
echo Enter Account Pin: %chip%
set /p pin=": "
:: Finding the specified pin
findstr /m "%pin%" E:\Chip\CardInfo.txt >Nul
if %errorlevel%==0 (
echo Pin "%pin%" is valid
timeout 1 >nul
goto account
)
if %errorlevel%==1 (
echo Pin "%pin%" is invalid
pause
goto start
)
:account
cls
:: Finds the name of the account owner and continues
setlocal enableextensions disabledelayedexpansion
for /F "tokens=2 delims=/" %%a in ('findstr /I "%pin%/" E:\Chip\CardInfo.txt') do set "user=%%a"
for /F "tokens=3 delims=/" %%b in ('findstr /I "%pin%/%user%/" E:\Chip\CardInfo.txt') do set "balance=%%b"
echo.
echo.
echo Welcome, %user%.
echo.
echo ACCOUNT BALANCE: $%balance%
echo.
echo 1=Deposit / 2=Withdraw / 3=Exit / 4=Refresh
choice /c 1234 >nul
if %ERRORLEVEL% EQU 1 goto deposit
if %ERRORLEVEL% EQU 2 goto withdraw
if %ERRORLEVEL% EQU 3 exit
if %ERRORLEVEL% EQU 4 goto account
:deposit
echo.
echo.
set /p add="Money to Deposit: "
set /a moneytoadd=%balance%+%add%
call jrepl "%pin%/%user%/%balance%" "%pin%/%user%/%moneytoadd%" /f E:\Chip\CardInfo.txt /o -
goto account
:withdraw
echo.
echo.
set /p sub="Money to Withdraw: "
set /a moneytosub=%balance%-%sub%
call jrepl "%pin%/%user%/%balance%" "%pin%/%user%/%moneytosub%" /f
E:\Chip\CardInfo.txt /o -
goto account
endlocal
Here's when the issue comes in. A pin consists of 4 numeric characters (ex. 1234), but if there's two pins with the same characters (ex. 1234, 6543), it will say the pin is valid. So for example, if I type 4, it will just look for just the number 4 in the file. And will say the pin is valid. Even though, just the number 4 is not an existing pin. My guess is that it's a flaw with "findstr". But I'm not sure.
Contents of "CardInfo.txt":
1234/Test User/1000
6543/Another Test User/2000
use REGEX (using <StartOfLine><PIN></>):
findstr /m "^%pin%/" E:\Chip\CardInfo.txt >Nul
where ^ is "Start of Line".
Here is what exactly does what you want:
#echo off
::add your path below
for /f %%a in (file.txt) do (
call :funch %%a
)
:funch
set input=%1
set "modifiedinput=%input:~0,4%"
set /p pin=Enter Account Pin:
if %modifiedinput% equ %pin% ( goto authentication_passed) else ( goto authentication_failed)
:authentication_passed
echo auth passed
rem your code
pause >nul
exit
:authentication_failed
echo auth failed
goto funch
it will read the input from file and then extract first four characters which in your case is the pin.
I rewrote the entire batch file to be more fail safe on execution:
#echo off
setlocal EnableExtensions DisableDelayedExpansion
rem endlocal is executed implicitly by cmd.exe on exiting batch file processing.
:Begin
cls
echo\
echo\
if exist E:\ goto enterPin
echo INSERT YOUR CARD
%SystemRoot%\System32\timeout.exe /T 1 >nul
goto Begin
:enterPin
set "pin="
set /p pin="Enter account pin for %chip%: "
if not defined pin goto enterPin
set "pin=%pin:"=%"
if not defined pin goto enterPin
for /F delims^=01234567890^ eol^= %%I in ("%pin%") do goto enterPin
rem Finding the specified pin.
%SystemRoot%\System32\findstr.exe /B /L /M /C:"%pin%/" E:\Chip\CardInfo.txt >Nul
if errorlevel 1 (
echo Pin "%pin%" is invalid.
pause
goto Begin
)
echo Pin "%pin%" is valid.
%SystemRoot%\System32\timeout.exe /T 1 >nul
:account
cls
rem Finds the name of the account owner and continues
for /F "tokens=2,3 delims=/" %%I in ('%SystemRoot%\System32\findstr.exe /B /L /C:"%pin%/" E:\Chip\CardInfo.txt') do set "user=%%I" & set "balance=%%J"
echo/
echo/
echo Welcome, %user%.
echo/
echo ACCOUNT BALANCE: $%balance%
echo/
echo 1=Deposit / 2=Withdraw / 3=Exit / 4=Refresh
%SystemRoot%\System32\choice.exe /c 1234 >nul
if not errorlevel 1 goto account
if errorlevel 4 goto account
if errorlevel 3 exit /B
if errorlevel 2 goto withdraw
:deposit
echo/
echo/
set "add="
set /P "add=Money to deposit: "
set /A moneytoadd=balance + add
call "%~dp0jrepl.bat" "%pin%/%user%/%balance%" "%pin%/%user%/%moneytoadd%" /L /f E:\Chip\CardInfo.txt /o -
goto account
:withdraw
echo/
echo/
set "sub="
set /P "sub=Money to withdraw: "
set /A moneytosub=balance - sub
call "%dp0jrepl.bat" "%pin%/%user%/%balance%" "%pin%/%user%/%moneytosub%" /L /f E:\Chip\CardInfo.txt /o -
goto account
Issues fixed with this code:
There is the command START. For that reason it is not advisable to use the string start as label although it is possible.
It is advisable to avoid an IF (...) ELSE (...) condition if a simple IF condition with GOTO can be used too.
The usage of full qualified file names wherever possible avoids a batch file not running as expected on environment variables PATH (too often) or PATHEXT (rarely) are corrupted on the userĀ“s machine.
A user has the freedom to enter on a prompt done with set /P really anything from nothing to something resulting in further processing in a syntax error with an immediate exit of batch file execution on code not being prepared for any user input. For that reason the first set /P prompt is improved and validates if the user entered a string consisting only of digits.
The usage of FINDSTR is done with additional options to find the pin only at beginning of a line case-sensitive with a literal search and the next character must be a slash character.
The recommended syntax for ERRORLEVEL evaluation is used in the code.
The arithmetic expressions are written using the recommended syntax to work even if the user enters nothing or a string which cannot be converted to an integer number at all.
The command EXIT is used with option /B to just exit the processing of the batch file and not the entire command process.
For understanding the used commands and how they work, open a command prompt window, execute there the following commands, and read entirely all help pages displayed for each command very carefully.
call /?
choice /?
cls /?
echo /?
findstr /?
for /?
goto /?
if /?
pause /?
rem /?
set /?
setlocal /?
timeout /?
Useful pages regarding to the improvements on code:
How does the Windows Command Interpreter (CMD.EXE) parse scripts?
Why is no string output with 'echo %var%' after using 'set var = text' on command line?
How to stop Windows command interpreter from quitting batch file execution on an incorrect user input?
Syntax error in one of two almost-identical batch scripts: ")" cannot be processed syntactically here
DosTips forum topic: ECHO. FAILS to give text or blank line - Instead use ECHO/
Single line with multiple commands using Windows batch file
Safe number comparison in Windows batch file

Batch to copy all files in subfolders to a destination without recreating the subfolders

I'm still pretty new to batch scripting, but I'm currently working on a batch file that when launched lets me select a source and destination folder from a menu. Now in my source folder, it has sub-directories with more directories in those. I'm trying to get the batch file to take any and all files in my source folder and copy them into a single folder[Destination] without recreating the folder structure so that all of the files in my sources sub-directories are nice compiled at destination.
I've tried xcopy, robocopy, and to an extent for loops. My guess is that it'll have to be done through for loops, however I'm not sure the appropriate code I should be using for this. I would like all file types to be workable with this program and not just: jpg, jpeg, png, and gif.
Thanks for the help.
#echo off
title File Copier
color 0a
:Menu
cls
echo Main Menu
echo ---------
echo Press 1 to copy files
echo.
echo Press 2 for information
echo.
echo Press 3 to exit
echo ---------------
set /p input=
if %input% == 1 goto 1
if %input% == 2 goto 2
if %input% == 3 goto 3
goto Menu
:1
rem Source
cls
echo Please select your source folder.
echo ---------------------------------
setlocal
set "psCommand="(new-object -COM 'Shell.Application')^
.BrowseForFolder(0,'Please select your source folder:',0,0).self.path""
for /f "usebackq delims=" %%I in (`powershell %psCommand%`) do set "folder=%%I"
setlocal enabledelayedexpansion
cls
rem Destination
echo Please select your destination folder.
echo --------------------------------------
set "psCommand="(new-object -COM 'Shell.Application')^
.BrowseForFolder(0,'Please select your destination folder:',0,0).self.path""
for /f "usebackq delims=" %%I in (`powershell %psCommand%`) do set "folder2=%%I"
setlocal enabledelayedexpansion
cls
rem Source/Destination Info
Set source=!folder!
Set target=!folder2!
Echo Source: %source%
Echo Destination: %target%
echo ---------------------------------------------------------------------
:Choice
set /P c=Would you like to proceed? [Y/N]
if /I "%c%" EQU "Y" goto Yes
if /I "%c%" EQU "N" goto No
goto Choice
:Yes
cls
rem echo D | xcopy %source% %target% /-y
rem robocopy "%source%" "%destination%" *.* /E
for /d %a in (%source%) do #copy %a\*.jpg %target%
for /d %a in (%source%) do #copy %a\*.png %target%
for /d %a in (%source%) do #copy %a\*.gif %target%
pause
goto Success
:No
goto 1
:Success
cls
echo The file(s) were successfully copied.
timeout /t 4 >nul
goto Menu

using for loop and windows tasklist cmd i am trying to open several programs from a batch file which are not already running

My code below doesn't work
echo will now go ahead and load the essential programs needed for
project: %project%
set "programlistopen=sublime_text.exe xampp-control.exe"
for /f "delims=" %%j in (%programlistopen%) do (
if %%j=="sublime_text"(set pathtopen=%defaultpath%\Sublime_Text&&set
dirpath="%workdirectory%\%project%") else
if %%j=="xampp-control.exe"(set pathtopen=%xampp%\&&set dirpath=)
tasklist /FI "IMAGENAME eq %%j" 2>NUL | find /I /N "%%j">NUL
if "%ERRORLEVEL%"=="1" goto notstartedsublimetext
if "%ERRORLEVEL%"=="0" goto startedsublimetext
:notstartedsublimetext
Echo started %%j at %time%
pause
start /d "%pathtopen%" %%j %dirpath%
:startedsublimetext
echo %%j is already running......
)
I would suggest possibly changing the structure to this:
#Echo Off
For %%A In ("C:\Program Files\SomeName\madeup.exe"
"C:\Users\Vibrations\Portables\Some Name\dummy.exe"
"C:\Windows\built-in.exe"
) Do TaskList|FindStr/BRIC:"%%~nxA\>">Nul&&(Echo %%~nxA already running
)||(Start "" "%%~A"&Echo Started %%~nxA at %TIME%)
Pause
Just list the full paths to the executables you want to check/start similarly to the three I've used as an example
Edit
As a result of the latest comment, here is an example of what I assume you're trying to do by way of your modification, (replace from line 6):
)||(If "%%~nxA"=="sublime_text.exe" (Start "" "%%~A" "%workdirectory%\%project%"
) Else Start "" "%%~A"
Echo Started %%~nxA at %TIME%)
Pause
#echo off
setlocal
#rem Variables to be set.
#rem changedir is an optional pushd on each call of :notstarted.
#rem startdir is passed to the /d argument in the start command.
#rem programpath is the path to the program executable.
#rem args are any arguments to pass to the program executable.
#rem Variables are undefined at start of loop.
echo will now go ahead and load the essential programs needed for project: %project%
set "programlistopen=wordpad.exe notepad.exe"
for %%j in (%programlistopen%) do (
for %%B in (changedir startdir programpath args) do set "%%~B="
if "%%~j" == "wordpad.exe" (
set "changedir=%userprofile%"
set "startdir=%cd%"
set "programpath=C:\Program Files\Windows NT\Accessories"
) else if "%%~j" == "notepad.exe" (
rem Nothing to set. Just start notepad.exe.
)
tasklist /FI "IMAGENAME eq %%~j" 2>NUL | find /I /N "%%~j" >NUL
if errorlevel 1 (
call :notstarted "%%~j"
) else call :started "%%~j"
)
exit /b
:notstarted
setlocal
echo started "%~1" at %time%
set "cli=start """
if defined startdir set "cli=%cli% /d "%startdir%""
if defined programpath (
set "cli=%cli% "%programpath%\%~1""
) else set "cli=%cli% "%~1""
if defined args set "cli=%cli% %args%"
if defined changedir pushd "%changedir%"
echo %cli%
%cli%
if defined changedir popd
exit /b
:started
echo "%%~1" is already running......
exit /b
Your code has many unknowns so I have done an example which you
can adapt to your needs.
I chose some simple programs like notepad and wordpad to test with.
Variables for use are commented at the top of the script. These
variables are undefined at start of each loop so you do not need
to undefined them and just use the variables that you want to set
with each program.
The errorlevel of tasklist is checked and will call the name of
the label required. This allows the call to return back to the
position of the caller so the loop can continue.
The :notstarted label will bulid the command line (cli) with
each of the defined variables that are relevent to the cli. The
optional pushd and popd was added just for an unusual use.

How to make bat file listing with options to choose

I want to make a bat file that list all of the files in a specific directory, and add numbers at the beginning of the every one of the listed items. This numbers need to be a selectable options.
Example:
I have a folder with 5 files in it, aaa.exe, bbb.exe, ccc.exe, ddd.exe, eee.exe. When i run bat file i need to see
aaa.exe
bbb.exe
ccc.exe
ddd.exe
eee.exe
So now if i wana run 5-th exe i need to press 5, than press enter and that 5th exe will now start.
I allredy find how to list all of the items in folder with this code
REM -start "c:\windows\system32" notepad.exe
for /r %%i in (*) do echo %%i
pause
exit
but i can't figure out how to add numbers in front of the text and make that numbers to be a selectable options.
Edit---
Now im getting
ERROR: Duplicate choices are not allowed. running '""' is not
recognized as an internal or external command, operable program or
batch file.
when i'm trying to run this loop for a second time.
This is code that i wrote:
#ECHO OFF
setlocal enabledelayedexpansion
REM ---Prompt part
:choise
SET /P AREYOUSURE=Install programs (Y/[N])?
IF /I "%AREYOUSURE%" EQU "Y" GOTO :chooseInstall
IF /I "%AREYOUSURE%" EQU "N" GOTO :nope
REM --Cheking for Y or N
GOTO :choise
:nope
echo "Ok. Have a nice daty / night"
pause
exit
:chooseInstall
echo Wich program do you wana install ?
echo.
echo 1. 7Zip
echo 2. CPU Z
echo.
SET /P AREYOUSURE=Choosing:
IF /I "%AREYOUSURE%" EQU "1" set "pathToSoft=C:\Users\usr\Desktop\hello"
IF /I "%AREYOUSURE%" EQU "2" set "pathToSoft=C:\Users\usr\Desktop\bye"
echo.
echo.
echo %pathToSoft%
echo.
echo.
REM ---Installs
echo "Wich file to install"
cd %pathToSoft%
echo.
echo.
REM --Loops that scan files
set /A counter=0
for /R %%i in (*) do (
if not "%%~nxi" == "%~nx0" (
set /A counter+=1
echo !counter!: %%~nxi
set exe[!counter!]=%%i
set choice=!choice!!counter!
)
)
if %counter% LSS 10 (
choice /C %choice% /M "Choose: "
set EXENUM=!ERRORLEVEL!
) else set /P EXENUM="enter exe number: "
set EXECUTABLE=!exe[%EXENUM%]!
echo running %EXECUTABLE%
call "%EXECUTABLE%"
echo.
echo.
echo.
:installmore
SET /P INSTALLMORE=Do you wana install somthing else (Y/[N])?
IF /I "%INSTALLMORE%" EQU "Y" GOTO :chooseInstall
IF /I "%INSTALLMORE%" EQU "N" GOTO :nope
count the executables and associate them with the counter, creating kind of "array" variables (filter out the current batch script)
build the choice list at the same time
after the loop, use choice if no more than 9 choices, else use a classical interactive set
retrieve the user selection and call the executable/batch file
(you have to enable delayedexpansion to be able to use % and ! env. var separators & instant evaluation within the loop)
can be done like this:
#echo off
setlocal enabledelayedexpansion
set /A counter=0
set choice=
for /R %%i in (*) do (
if not "%%~nxi" == "%~nx0" (
set /A counter+=1
echo !counter!: %%~nxi
set exe[!counter!]=%%i
set choice=!choice!!counter!
)
)
if %counter% LSS 10 (
choice /C %choice% /M "type exe number"
set EXENUM=!ERRORLEVEL!
) else set /P EXENUM="enter exe number: "
set EXECUTABLE=!exe[%EXENUM%]!
echo running %EXECUTABLE%
call "%EXECUTABLE%"

How to check if given path points to a file or a directory?

How to find out for example if C:\Windows\something.tmp is a file or a directory?
Sometimes applications write their temporary data to a folder with an extension, and deleting a directory differs from deleting a file. So I must call a different subroutine for that.
The solution below works both for ordinary and network cases. There is much confusion and has even been heated arguments about distinguishing between files and folders. One reason is that the method familiar from the MS-DOS days (testing for the nul) is no more the valid solution to distinguish between a file and a folder in the Windows command-line. (This is getting complicated.)
#echo off & setlocal enableextensions
if "%~1"=="" (
echo Usage: %~0 [FileOrFolderName]
goto :EOF)
::
:: Testing
call :IsFolderFn "%~1" isfolder_
call :IsFileFn "%~1" isfile_
echo "%~f1" isfile_=%isfile_% isfolder_=%isfolder_%
endlocal & goto :EOF
::
:: Is it a folder
:: First the potential case of the root requires special treatment
:IsFolderFn
setlocal
if /i "%~d1"=="%~1" if exist "%~d1\" (
set return_=true& goto _ExitIsFolderFn)
if /i "%~d1\"=="%~1" if exist "%~d1" (
set return_=true& goto _ExitIsFolderFn)
set return_=
dir /a:d "%~1" 2>&1|find "<DIR>">nul
if %errorlevel% EQU 0 set return_=true
:_ExitIsFolderFn
endlocal & set "%2=%return_%" & goto :EOF
::
:: Is it just a file
:IsFileFn
setlocal
set return_=
if not exist "%~1" goto _ExitIsFileFn
call :IsFolderFn "%~1" isfold_
if defined isfold_ goto _ExitIsFileFn
dir /a:-d "%~1" 2>&1 > nul
if %errorlevel% EQU 0 set return_=true
:_ExitIsFileFn
endlocal & set "%2=%return_%" & goto :EOF
Originally from http://www.netikka.net/tsneti/info/tscmd075.htm
How to test if a file is a directory in a batch script?
In short :
FOR %%i IN (%VAR%) DO IF EXIST %%~si\NUL ECHO It's a directory
But all credits go to Dave Webb
You can used dir /a-d to tell you
if I check errorlevel it tells me
With a file
C:\Users\preet>echo. > something.tmp
C:\Users\preet>dir /a-d something.tmp > nul & echo %errorlevel%
1
C:\Users\preet>del something.tmp
with a directory
C:\Users\preet>md something.tmp
C:\Users\preet>dir /a-d something.tmp > nul & echo %errorlevel%
File Not Found
0

Resources