Batch script help, script exiting after parentheses - windows

I wrote a very simple script to output the host machine's MAC addresses to a text file.
The script is exiting right after line 3 - 'IF DEFINED WRITEOK ('.
#echo off
cls
copy /Y NUL "%CD%\.writable" > NUL 2>&1 && set WRITEOK=1
IF DEFINED WRITEOK (
rem ---- we have write access ----
set DIR=%CD%\interfaces
set FILE=%DIR%\%USERNAME%.txt
IF NOT EXIST "%DIR%" (
MKDIR "%DIR%"
echo DIR '%DIR%' was created
) else (
echo DIR '%DIR%' already exists
) for /f "tokens=2 delims=:" %%i in ('ipconfig /all ^| findstr /i "Physical Host"') do (
echo %%i >> "%FILE%"
echo OUTPUT written to '%FILE%'
)
) else (
rem ---- we don't ----
echo DIR '%DIR%' is not writable
)
echo.
echo DONE!
pause

Try to put the FOR one line after the closing parenthesis :
...)
for /f "tokens=2 delims=:" %%i in ('ipconfig /all ^| findstr /i "Physical Host"') do (...
you can't start a FOR with a closing parenthesis in front :
This will not work :
(echo 1
) for /l %%a in (1,1,10) do echo %%a
and this will work :
(echo 1
)
for /l %%a in (1,1,10) do echo %%a
EDIT 1 :
For the path variables containing space use double quote :
"%cd%"
when using it.

Related

Looping through %1 as a directory in batch?

I've searched the web for answers but can't seem to find an answer. I want the user to provide a directory and to be able to loop through it. I'm able to loop through the current directory like so:
#Echo off
for /r %%f in (*.*) do (
echo %%f
)
But then when I try to do the same by looping through %1, I can't get the result I'm looking for. What am I doing wrong? Here's where I'm at in the batch file:
#Echo off
if exist %1 (
for /r %%f in (%1) do (
echo %%f
)
) else (
echo "That directory does not exist."
)
I've tried using /D but all that did was echo the directory I provided like this:
FileCount C:\Users\Me\Desktop
> C:\Users\Me\Desktop
Edit: My goal for this program is to eventually count the number of files within the given directory. I expect the directory to be provided as it's absolute path and I'll be executing this file through cmd. Here's an example of the input I'm expecting.
FileCount C:\Users\Me\Desktop
And the desired output would be something like:
> Hello world.txt
> Cat.png
> There are 2 files within this directory.
Side-note: I don't want to filter out the output of the dir command, I want to do this with a for loop.
Here's what you asked for, plus the optional recurs feature. Note that this will miss hidden files and directories.
#setlocal EnableExtensions
#prompt=$G
#set _Error_Success=0
#set _Error_PathNotFound=3
#if "%~1" equ "/?" goto :Usage
#if "%~1" equ "" goto :Usage
#if "%~1" equ "/r" (#set _recurs=/r & #set _root=%~2) else (#set _root=%~1)
#if not exist "%_root%" goto :Oops
#set count=0
#pushd "%_root%"
#for %_recurs% %%f in (*) do #call :Counter "%%f"
#popd
#echo There are %count% entries within this directory.
#exit /b %_Error_Success%
:Counter
#set /a count+=1
#echo %~1
#exit /b %_Error_Success%
:Oops
#echo "That directory does not exist."
#exit /b %_Error_PathNotFound%
:Usage
#echo Usage: FileCount [/r] path
And this uses the dir command, without resorting to invoking findstr:
#setlocal EnableExtensions
#prompt=$G
#set _Error_Success=0
#set _Error_PathNotFound=3
#set _Error_InvalidParameter=87
#set _attributes=
#set _recurs=
#set _count=0
#if "%~1" equ "/?" #goto :Usage & #exit
#if "%~1" equ "" goto :Usage
#set _root=%~1
#if not exist "%_root%" goto :Oops
#shift
#pushd "%_root%"
for /f %%G in ('dir /B /A-d %1 %2 %_root%') do #call :Counter "%%G"
#popd
#echo There are %_count% entries within this directory.
#exit /b %_Error_Success%
:Counter
#set /a _count+=1
#echo %~1
#exit /b %_Error_Success%
:HandleOptions
:Oops
#echo "That directory does not exist."
#exit /b %_Error_PathNotFound%
:Usage
#echo Usage: FileCount [/A<Attributes>] [/S] rootPath
#echo Where <Attributes> corresponds to 'dir /A' optiions (see 'help dir')
#echo and /S will cause recursion into subdirectories of rootPath.
This example, uses a for loop, and does not use the dir command, as per your inexplicable request, but it does use xcopy to list and count the files within it instead:
#For %%G In ("%~1") Do #If "%%~aG" Lss "d" (If "%%~aG" GEq "-" (
Echo Error: File argument given, expected a directory.
%SystemRoot%\System32\timeout.exe /T 3 /NoBreak 1> NUL
Exit /B 1) Else (
Echo Error: Invalid argument, directory path expected.
%SystemRoot%\System32\timeout.exe /T 3 /NoBreak 1> NUL
Exit /B 1)
) Else Echo File content of "%~1":& For /F Delims^= %%H In (
'%SystemRoot%\System32\xcopy.exe "%~1" : /HIL') Do #Echo %%~nxH
#%SystemRoot%\System32\timeout.exe /T -1 & Exit /B 0
If you want it to recurse the input directory, then I'd suggest this very small modification:
#For %%G In ("%~1") Do #If "%%~aG" Lss "d" (If "%%~aG" GEq "-" (
Echo Error: File argument given, expected a directory.
%SystemRoot%\System32\timeout.exe /T 3 /NoBreak 1> NUL
Exit /B 1) Else (
Echo Error: Invalid argument, directory path expected.
%SystemRoot%\System32\timeout.exe /T 3 /NoBreak 1> NUL
Exit /B 1)
) Else Echo File content of "%~1":& For /F Delims^= %%H In (
'%SystemRoot%\System32\xcopy.exe "%~1" : /HILS') Do #Echo %%H
#%SystemRoot%\System32\timeout.exe /T -1 & Exit /B 0
Or with a little more work, outputting relative paths instead:
#For %%G In ("%~1") Do #If "%%~aG" Lss "d" (If "%%~aG" GEq "-" (
Echo Error: File argument given, expected a directory.
%SystemRoot%\System32\timeout.exe /T 3 /NoBreak 1> NUL
Exit /B 1) Else (
Echo Error: Invalid argument, directory path expected.
%SystemRoot%\System32\timeout.exe /T 3 /NoBreak 1> NUL
Exit /B 1)
) Else Echo File content of "%~1":& For /F Delims^= %%H In (
'%SystemRoot%\System32\xcopy.exe "%~1" : /HILS') Do #(
Set "}=%%H" & SetLocal EnableDelayedExpansion
For %%I In ("!}:*%~1=.!") Do #EndLocal & Echo %%~I)
#%SystemRoot%\System32\timeout.exe /T -1 & Exit /B 0
setlocal enabledelayedexpansion
rem Put it into a folder that is in ENV PATH variable.
rem So, you can call it from wherever you want.
if not "%~1"=="" (
if exist "%~dpn1" (
set /a "filecount=0"
for /f "tokens=* delims=" %%f in ('dir /b "%~dpn1"') do (
echo %%f
set /a "filecount+=1"
)
echo:
echo In "%~dpn1" found !filecount! file^(s^).
) else (
echo:
echo [ERROR] Invalid input. Please specify:
echo 1. A full path.
echo 2. A folder in cwd.
echo:
echo If input is empty, current working directory (cwd)
echo will be considered.
exit /b 1
)
) else (
set /a "filecount=0"
for /f "tokens=* delims=" %%f in ('dir /b "%~dp0"') do (
echo %%f
set /a "filecount+=1"
)
echo:
echo In "%~dp0" found !filecount! file^(s^).
)
endlocal
If you want it recursive call it as progname.bat /r [foldname]:
setlocal enabledelayedexpansion
rem Put it into a folder that is in ENV PATH variable.
rem So, you can call it from wherever you want.
if "%1"=="/r" shift
if not "%1"=="" (
if exist "%~dpn1" (
set /a "filecount=0"
set /a "totalcount=0"
set "oldroot=%~dpn1"
for /f "tokens=* delims=" %%f in ('dir /b /s "!cd!"') do (
if not "%%~dpf"=="!oldroot!" (
echo:
echo In "!oldroot!" found !filecount! file^(s^).
echo:
set /a "filecount=0"
set "oldroot=%%~dpf"
)
echo --- %%f
set /a "filecount+=1"
set /a "totalcount+=1"
)
echo:
echo In "%~dpn1" found !totalcount! file^(s^).
) else (
echo:
echo [ERROR] Invalid input. Please specify:
echo 1. A full path.
echo 2. A folder in cwd.
echo:
echo If input is empty, current working directory (cwd)
echo will be considered.
exit /b 1
)
) else (
set /a "filecount=0"
set /a "totalcount=0"
set "oldroot=!cd!"
for /f "tokens=* delims=" %%f in ('dir /b /s "!cd!"') do (
if not "%%~dpf"=="!oldroot!" (
echo:
echo In "!oldroot!" found !filecount! file^(s^).
echo:
set /a "filecount=0"
set "oldroot=%%~dpf"
)
echo --- %%f
set /a "filecount+=1"
set /a "totalcount+=1"
)
echo:
echo In "%~dp0" found !totalcount! file^(s^).
)
endlocal
Try it and see if it is what you expected.
Thank you for the help everybody, I've found the solution to the problem and it was very simple. All I needed to do was loop through %1\*.* instead of %1 itself.
#Echo off
if exist %1 (
for %%f in (%1\*.*) do (
echo %%f
)
) else (
echo "That directory does not exist."
)

Use a Batch File to list files and allow the user to select which file to copy into a new destination

I am a newbie to Windows Scripting.
I am trying to list some txt files in several sub directories & want to copy a user selected file to a new destination. Please note that the file name is unique in different locations.
I got the first part to work (Listing out the files & locations) using the following script, but I am unable to copy the selected file to the new location.
#ECHO OFF
SET index=1
SETLOCAL ENABLEDELAYEDEXPANSION
SET FFPath="C:\Scripts - Backup Server\DKXpress_bkp"
SET NewPath=C:\DKServer
ECHO Recursively searching %FFPath%
echo.
FOR /F "delims=" %%f in ('DIR %FFPath%\*.txt /a:-d /s /b') DO (
SET file!index!=%%f
ECHO !index! - %%f
SET /A index=!index!+1
)
SETLOCAL DISABLEDELAYEDEXPANSION
SET /P selection="select file by number:"
SET file%selection% >nul 2>&1
IF ERRORLEVEL 1 (
ECHO invalid number selected
EXIT /B 1
)
SET NewFile=file%selection%
ECHO Copying %NewFile% to %NewPath%
ECHO.
COPY /Y "%NewFile%" "%NewPath%"
ECHO.
PAUSE
I think I am doing this part wrong
SET NewFile=file%selection%
Thank you all in advance
You don't need to set an index variable or delayed expansion, if you let Find do the work for you:
#Echo Off
Set "FFPath=C:\Scripts - Backup Server\DKXpress_bkp"
Set "NewPath=C:\DKServer"
Echo Recursively searching %FFPath%
Echo=
For /F "Delims==" %%A In ('"Set File[ 2>Nul"') Do Set "%%A="
For /F "Tokens=1* Delims=]" %%A In (
'"Dir /B/S/A-D-S-L "%FFPath%\*.txt" 2>Nul|Find /N /V """') Do (
Echo %%A] %%B
Set "File%%A]=%%B"
)
Echo=
Set /P "#=Select file by number: "
Echo=
For /F "Tokens=1* Delims==" %%A In ('"Set File[%#%] 2>Nul"') Do (
Echo Copying %%B to %NewPath%&Echo=
Copy /Y "%%B" "%NewPath%"
GoTo :End
)
Echo Invalid number selected
:End
Echo=
Pause
You need to use delayed expansion to get the file name assigned to the variable correctly.
SET NewFile=!file%selection%!
Remove the setlocal to disable delayed expansion.
You can try something like that :
#ECHO OFF
:Main
cls
SET index=1
SETLOCAL ENABLEDELAYEDEXPANSION
SET FFPath="C:\Scripts - Backup Server\DKXpress_bkp"
SET "NewPath=C:\DKServer"
ECHO Recursively searching %FFPath%
echo.
FOR /F "delims=" %%f in ('DIR %FFPath%\*.txt /a:-d /s /b') DO (
SET filepath[!index!]=%%f
ECHO [!index!] - %%~nxf - %%f
SET /A index=!index!+1
)
echo(
echo select file by number :
set /p Input=""
For /L %%i in (1,1,%index%) Do (
If "%INPUT%" EQU "%%i" (
ECHO Copying "!filepath[%%i]!" to "!NewPath!"
COPY /Y "!filepath[%%i]!" "!NewPath!"
)
)
echo Copying another file ? (Y = Yes or N = No) ?
set /p input2=""
If /I "!input2!"=="Y" (
goto :Main
) else (
goto :eof
)

find multiple files paths with single string

I tried to write a batch script that find all the paths of files that have the same name as the input string. right now it can find only the first file found, and i cant think of a way to make it list multiple files locations. I am not very experienced and I need some help.
this is part of the script code:
:start
cls
echo Enter file name with extension:
set /p filename=
echo Searching...
for %%a in (C D E F G H U W) do (
for /f "tokens=*" %%b in ('dir /s /b "%%a:\%filename%"') do (
set file=%%~nxb
set datapath=%%~dpb\
::the path of the file without the filename included "C:\folder\folder\"
set fullpath=%%b
::the path of the file with the filename included "C:\folder\folder\file"
goto break
)
)
:notfound
cls
echo Enter file name with extension:
echo %filename%
echo File Not Found!
ping localhost -n 4 >nul
goto start
:break
if "%datapath:~-1%"=="\" set datapath=%datapath:~,-1%
cls
echo 3 %filename% found
echo %fullpath1%
echo %fullpath2%
echo %fullpath3%
--- || ---
I want the script to search the computer and list every encountered files with the same name and I want to be able to put those files' paths into different variables.
For example, if readme.txt is the input, then I want the list of all the paths of all the files with that specific name (readme.txt) and I want to set variable for each path so I can use it after that.
input:
readme.txt
output:
3 files found
C:\folder\folder\readme.txt
C:\folder\folder\folder\readme.txt
D:\folder\readme.txt
#echo off
set filename=readme.txt
for %%a in (C D E F G H U W) do (
for /f "tokens=*" %%b in ('dir /s /b "%%a:\%filename%"') do (
echo you can do something here with %%~nxb in %%~dpb
echo full name: %%b
)
)
I see no need to set the filenames to variables, as you can process them inside your loop. But if you really need them (for some reason) in variables:
#echo off
setlocal enabledelayedexpansion
set filename=readme.txt
set count=0
for %%a in (C D E F G H U W) do (
for /f "tokens=*" %%b in ('dir /s /b "%%a:\%filename%" 2^>nul') do (
set /a count+=1
set _file[!count!]=%%b
)
)
set _file
You can try with this code :
#echo off
Title Searching for the path with the same file name
Mode con cols=80 lines=3 & Color 9E
SET /a Count=0
set /a cnt=1
set "FileName=Readme.txt"
set "Report=%~dp0Report.txt"
set "Folder2Copy=%~dp0Readme_Folder"
set "Result2Copy=%~dp0Result2Copy.txt
If exist %Folder2Copy% RD /S /Q %Folder2Copy%
If Exist %Report% Del %Report%
If Exist %Result2Copy% Del %Result2Copy%
echo(
Echo Searching for the path with the same file name
Rem Looking for fixed drives and store them into variables
SETLOCAL enabledelayedexpansion
For /f "skip=1" %%a IN ('wmic LOGICALDISK where driveType^=3 get deviceID') DO (
for /f "delims=" %%b in ("%%a") do (
SET /a "Count+=1"
set "Drive[!Count!]=%%b"
)
)
:Display
for /L %%i in (1,1,%Count%) do (
cls
Title Please wait a while ... Searching for "%FileName%" on "!Drive[%%i]!\"
echo(
echo Please wait a while ... Searching for "%FileName%" on "!Drive[%%i]!\"
Call :FindPathFile !Drive[%%i]!\ %FileName% >> %Report%
)
Start "" %Report%
Goto :AskQuestion
::***************************************************************************************
:FindPathFile <Location> <FileName>
Where.exe /r %1 %2
Goto :eof
::***************************************************************************************
:AskQuestion
cls & Mode con cols=100 lines=5
echo(
echo Did you want to make copy of all files found as name "%FileName%"
echo saved on "%Report%" ? (Y/N) ?
set /p "Input="
If /I "%INPUT%"=="Y" (
for /f "delims=" %%i in ('Type "%Report%"') do (
Call :MakeCopy "%%~i" "%Folder2Copy%\"
)
)
Call :Explorer "%Folder2Copy%\" & exit
If /I "%INPUT%"=="N" (
Exit
)
Goto :eof
::***************************************************************************************
:MakeCopy <Source> <Target>
If Not Exist "%~2\" MD "%~2\" (
if not exist "%2\%~n1" (
echo copying "%~1" to "%~2"
copy /N /B "%~1" "%~2" >>%Result2Copy% 2>&1
) else (
call :loop "%~1" "%~2"
)
)
::***************************************************************************************
:loop
set "fname=%2\%~n1(%cnt%)%~x1"
if exist "%fname%" set /a cnt+=1 && goto :loop
copy "%~1" "%fname%"
exit /b
::***************************************************************************************
:Explorer <file>
explorer.exe /e,/select,"%~1"
Goto :EOF
::***************************************************************************************

for command is executed only for the first value when a label is inside

I have the script
for /f "delims=" %%i in ('dir "%folder%*.txt" /b /s') do (
set s=%%i
set s=!s:%folder%=!
set new_s=!s:\=!
if "x!new_s!" NEQ "x!s!" (
:ProcessListSource
For /f "tokens=1* delims=\" %%A in ("!s!") do (
if "%%A" NEQ "" (
if "!Folder1!" NEQ "" (
Set Folder1=!Folder1!\!Name!
)else (
Set Folder1=!Name!
)
Set Name=%%A
)
if "%%B" NEQ "" (
set s=%%B
goto :ProcessListSource
)
)
echo Folder is: !Folder1!
echo Name is: !Name!
echo ---------------------
) else (
echo Not a folder !s!
)
)
but it does not work as I would have expected:
The first for is executed only once and also the last echo is printed on the screen.
Given a folder I need the files from subfolders without the given folder and than split them into the folder and file
Ex: folder=C:\test
The for would give me the file C:\test\test1\test2\t.txt
And I need test1\test2 and t.txt
GOTO breaks your FOR /F \ IF context and they can be executed only once.
More simple example:
#echo off
for /l %%S in (1=1=5) do (
echo %%S
goto :inner_label
rem
:inner_label
rem
)
This will print only 1 . Do you really need the GOTO here?
When the parser reads your code, all the code inside your for loop is "considered" as only one command that is readed, parsed and executed. As stated in the npocmaka answer, any goto call takes you out of this "line" of code, ending the process of the for loop.
This is a alternative. Use pushd + xcopy /l /s commands to generate a list of the relative paths of the files.
#echo off
setlocal enableextensions disabledelayedexpansion
set "folder=%cd%"
pushd "%folder%"
for /f "delims=" %%a in ('xcopy /l /s /y * "%temp%"^|findstr /vbr /c:"[0-9]"'
) do for /f "delims=: tokens=1,*" %%b in ("%%~a") do (
echo [%%c] [%%~nxa]
)
popd

batch script to search file better or close to window search

this batch script to search file better
using "find" its just ordinary...and need to type exactly the file name "file 1.txt" "file2.txt" "file letter.txt"
and exactly folder location...
any other way?
just try type "file"
its show all file with name "file"
"file 1.txt"
"file2.txt"
"file letter.txt"
and have number
1 . "file 1.txt"
2 . "file2.txt"
3 . "file letter.txt"
and enter the number to select the file what we want...
and it will be open.
#echo off
setlocal EnableDelayedExpansion
if exist log del log
set "token=%~1"
if not defined token (
echo Search for what string?
set /p token=^>
echo.
)
set a=0
for /f "delims=" %%A in ('dir /b ^| find "%token%"') do (
set /a a+=1
echo !a!. %%A
echo !a!. %%A >>log
)
echo.
echo Enter number of file to open.
set /p op=^>
for /f "tokens=1,2 delims=." %%A in (log) do (
if %%A EQU %op% start %%B
)
del log
the problem is
when enter the number...batch otomatic close...file wont open...
any suggestion?
you might try this:
#echo off &setlocal
set /p "spat=Enter search pattern: "
for /f "tokens=1*delims=:" %%a in ('dir /b /s /a-d \%spat%*.txt 2^>nul^|findstr /ri "%spat%[^a-z]"^|findstr /rn $') do set "$%%a=%%~b"&set /a fcnt+=1
if not defined fcnt (echo Error! Not such file "%spat%".&goto:eof)
:loop
for /f "tokens=1*delims==$" %%a in ('set "$" 2^>nul') do echo %%a.%%~b
set /p "fno=Enter file number to run: "
echo %fno%|findstr "[1-9][0-9]*" >nul || (echo Error! Try again.&goto:loop)
if %fno% gtr %fcnt% (echo Error! Enter number between 1-%fcnt%. Try again.&goto:loop)
for /f "tokens=1*delims==$" %%a in ('set "$%fno%"') do "%%~b"

Resources