I posted a question earlier today but the answers received did not solve the issue (probably an error on my part by not providing enough sample code...not to mention a few typos). In this case, everything works just fine until I get to a filepath that has "!" or "&" in the path itself. When there is one of these characters the characters are stripped from the path (note the rest of the path appears normal) but when the hash function is called the modified path is not found (as one would expect). I need to prevent these characters from being stripped but also function in the case where the path has spaces or no spaces.
I know I need to use expansion (or some form thereof), just not sure as to the exact placement to get the desired effect.
Code Snip
#echo off
for /f "delims=?" %%A in (dir-selected_tmp.txt) do (
set filepath=%%A
call :filepathparse
call :md5hashchk
call :echohash
)
goto :eof
:filepathparse
for %%B in ("%filepath%") do (
set filename=%%~nxB
)
goto :eof
:md5hashchk
for /f "delims= " %%b in ('md5deep64.exe "!filepath!"') do set hashvalue=%%b
goto :eof
:echohash
echo !hashvalue!
goto :eof
Add setLocal enableDelayedExpansion to the start of your script.
You cannot wrap variables with exclamation marks unless you have that set. See this page for more information about variable expansion in batch.
Your code, as it was written, don't need the delayed expansion !variables!; just replace exclamation-marks by percents:
:md5hashchk
for /f "delims= " %%b in ('md5deep64.exe "%filepath%"') do set hashvalue=%%b
goto :eof
:echohash
echo %hashvalue%
goto :eof
EDIT: Response to comment
Try this:
#echo off
for /f "delims=?" %%A in (dir-selected_tmp.txt) do (
set "filepath=%%A"
call :filepathparse
call :md5hashchk
call :echohash
)
goto :eof
:filepathparse
for %%B in ("%filepath%") do (
set "filename=%%~nxB"
)
goto :eof
:md5hashchk
for /f "delims= " %%b in ('md5deep64.exe "%filepath%"') do set "hashvalue=%%b"
goto :eof
:echohash
set /P "=%hashvalue%" < NUL
echo/
goto :eof
Related
I have an XML file (generated by a third party tool) which is of format
<?xml version="1.0" encoding="UTF-8"?><ROOT test_count="22" test_fail_count="1" test_pass_count="21".......</ROOT>
All the content is in one line of the file with name Report.xml.
I have been trying to write a batch script
#echo off
setlocal EnableDelayedExpansion
set "Report="
for /f "delims=" %%x in (Report.xml) do set "Report=!Report! %%x"
REm set /p Report=< %Results_File%
echo report is !Report!
call:parseVal !Report!
exit/b
:parseVal
setlocal enableDelayedExpansion
set val="%~1"
echo %val%
echo !val!|findstr /rc:"test_count=.[0-9]*." >nul || (
echo !val!
EndLocal
exit /b
)
rem ..
Basically I am trying to grab values for test_count(22), test_fail_count(1) and test_pass_count(21) from the XML file.
Any ideas on how to achieve this?
#ECHO Off
SETLOCAL
SET "sourcedir=U:\sourcedir"
SET "filename1=%sourcedir%\q42057260.txt"
SET "testcount="
SET "testfailcount="
FOR /f "usebackqdelims=" %%a IN ("%filename1%") DO (
SET "xmlline=%%a"
CALL :process
)
ECHO test count=%testcount% test fail count=%testfailcount%
GOTO :EOF
:process
:: dispose of awkward characters
SET "xmlline=%xmlline:?= %"
SET "xmlline=%xmlline:>= %"
SET "xmlline=%xmlline:<= %"
CALL :select %xmlline%
GOTO :EOF
:select
IF /i "%~1"=="" GOTO :EOF
IF DEFINED testcount IF DEFINED testfailcount GOTO :EOF
IF /i "%~1"=="test_count" SET /a testcount=%~2
IF /i "%~1"=="test_fail_count" SET /a testfailcount=%~2
SHIFT
GOTO select
GOTO :EOF
You would need to change the setting of sourcedir to suit your circumstances.
I used a file named q42057260.txt containing your data for my testing.
Read the file to %%a and transfer to xmlline.
Use :process to remove awkward characters (those with a special meaning to cmd) by replacing each with a space, then pass the resultant line to :select as a parameter-list.
look at each parameter in turn, stripping quotes. When the target strings appear, set their storage variables to the following value. When both values are assigned, bail out.
and report results.
Provided the structure and order of Report.xml is constant this could do (cmd line)
for /f "tokens=5,6 delims=<> " %A in (Report.xml) Do #Set %A&Set %B
Sample output with your Report.xml
> set test
test_count="22"
test_fail_count="1"
So the situation is like so... I have two nested if statements and then a loop inside them (using the GoTo command and an incremented variable - for loop simulation :D). As you probably know to assign new values to variables inside of parentheses (of an if statement) you have to use delayedexpansion. Also to use variables in the for command you have to double the percent marks like so %%. I want to set the tokens in a for /f command to be the value of the variables I'd like. The problem is doubling the exclamation marks has no effect. I also tried all sorts ... like using quotes, escaping those quotes, using quote alternatives, but it was all to no avail. If you can help in any way that would be just great, because I can't think of anything at all :(. Thank you in advance guys!
If that made no sense here's the code:
#echo off
set FilePath=test.bat
set RefreshRate=3
setlocal enabledelayedexpansion enableextensions
:GetData
if defined FilePath (
if exist "%FilePath%" (
:GetLines
cls
:: This is how I find out how many lines there is in the file
set "cmd=findstr /R /N "^^" "%FilePath%" | find /C ":""
for /f %%a in ('!cmd!') do set Lines=%%a
:ShowCode
cls
set LineNum+=1
if ""!LineNum!"" GTR ""!Lines!"" GoTo Refresh
::THIS IS THE MAIN PROBLEM
for /f "tokens=%%LineNum%% delims=$" %%b in ("%FilePath%") do (
set Line%LineNum%=%%b
echo !LineNum!. | !Line%LineNum%!
GoTo ShowCode
)
)
)
:Refresh
ping localhost -n %RefreshRate% >nul
GoTo GetData
I'm sorry that I didn't have enough time to make it more readable, but it should make the whole thing a little clearer.
First: do not use neither :: remark comments nor :label in a code block enclosed in () parentheses. A proof of harmfulness you could find in the labels.bat script encoded in output from a script provided thereinafter; an explanation here: Comments within bracketed code blocks.
In next script, non-empty lines of a particular plain text file (cf. set "FilePath=labels.bat") are saved to a pseudo-array LineAAA, where index AAA = line number. I do not know whether it isn't off topic according to your question but could give some useful clue...
#echo off
setlocal enabledelayedexpansion enableextensions
cls
set line
set "FilePath=labels.bat"
set /A "RefreshRate=3"
:GetData
if not defined FilePath (
echo %%FilePath%% not defined
goto :eof
)
if not exist "%FilePath%" (
echo %FilePath% does not exist
goto :eof
rem following 'else' (sub)statement seems to be superabundant
) else (
rem GetLines
rem This is how I find out how many lines there is in the file
set "cmd=findstr /R /N "^^" "%FilePath%" | find /C ":""
for /f %%a in ('!cmd!') do set /A "Lines=%%a"
set /A "LineNum=0"
set "Line000=#rem %FilePath%"
for /f "tokens=*" %%b in (%FilePath%) do (
set /A "LineNum+=1"
set "LineX=000000000!LineNum!"
set "LineX=!LineX:~-3!"
set "Line!LineX!=%%b"
)
call :Refresh
)
set line
rem pause
endlocal
goto :eof
:Refresh
ping localhost -n %RefreshRate% | findstr /I "Packets: statistics"
rem >nul
GoTo :eof
Output:
Environment variable line not defined
Ping statistics for ::1:
Packets: Sent = 3, Received = 3, Lost = 0 (0% loss),
Line000=#rem labels.bat
Line001=#SETLOCAL enableextensions enabledelayedexpansion
Line002=#ECHO ON >NUL
Line003=if ""=="" (
Line004=rem comment
Line005=#echo rem comment
Line006=)
Line007=if ""=="" (
Line008=:: comment
Line009=#echo :: comment
Line010=)
Line011=if ""=="" (
Line012=:label
Line013=#echo :label
Line014=)
Line015=#ENDLOCAL
Line016=#goto :eof
LineNum=16
Lines=16
LineX=016
labels.bat output:
d:\bat>labels.bat
d:\bat>if "" == "" (
rem comment
)
rem comment
d:\bat>if "" == "" (#echo :: comment )
'#echo' is not recognized as an internal or external command,
operable program or batch file.
d:\bat>if "" == "" (#echo :label )
'#echo' is not recognized as an internal or external command,
operable program or batch file.
d:\bat>
Tokens property don't go in the brackets they go in quotes and are wrong anyway. It's the nth to nth delimited term.
Type
for /?
for examples
I am running into an issue where I have a complete directory listing of a computer (located in the text file shown below).
The issue appears in cases where the directory listing contains special characters such as "! or &". When that issue occurrs, the filename is parsed such that those special characters are omitted (thus causing issues with leveraging those variables to compute other sub-tasks). Below is a snapshot of the code. Please advise as to how I might proceed.
Note that within the text file might be paths such as:
C:\Windows!temp!\file.txt
C:\Windows\file.txt
This will parse as:
C:\Windows\temp\file.txt (without quotes)
C:\Windows\file.txt
code snip
for /f "delims=?" %%a in (dir.txt) do (
setlocal enabledelayedexpansion
set filepath=%%a
)
call :subproc1
)
goto :proc2
:subproc1
echo !filepath!
endlocal
goto :eof
:proc2
continue with script here
You are toggling delayed expansion on too early, and there is no need for the subroutine.
for /f "delims=?" %%a in (dir.txt) do (
set filepath=%%a
setlocal enabledelayedexpansion
echo !filepath!
endlocal
)
#echo off
setlocal enableDelayedExpansion
for /f "delims=?" %%a in (dir.txt) do (
setlocal disableDelayedExpansion
(echo(%%a)
endlocal
)
endlocal
goto :proc2
:proc2
echo -------end
the Jeb's trick...
Ok, here's the set up:
I have a ton of text files with the following format:
filename## time Description of file with spaces
I'm trying to rename the actual file on disk with the description of the file, using a for loop:
FOR /F "tokens=1,2,*" %%a IN (%1) DO call :rename %%a %%b "%%c"
goto :eof
:rename
set origfilename=%1
set last2=%1:~-2%
set time=%2
set "multiword=%~3"
ren %origfilename%.ext "%last2%_%time%_%multiword%.ext"
set origfilename=
set last2=
set time=
set multiword=
Here's what's happening:
last2 is never picking up the last 2 characters of the original file name, and if I echo %3 after the DO instead of the call to :rename, it has the full token with spaces. When I try to use %3 in the loop, it only contains the first token of %3.
I tried using setlocal EnableDelayedExpansion before the for, but it didn't work as I expected.
Am I trying to do too many things at once? Thanks for the help!
Try this. I think this will do what you want.
#echo off
for /f "Tokens=1,2,3*" %%a in ('dir /b filename*') do (
call :rename "%%a %%b %%c %%d" %%a %%b "%%c %%d")
goto :eof
:rename full orig time new
echo %2
set last2=%2
set last2=%last2:~-2%
echo ren "%~1.ext" "%last2%_%3_%~4.ext"
Remove the Echo if everything looks good
I've a batch script in which I loop trough all the filenames in a folder and then I invoke a command in order to remove the extension from the filename. I'd like to store at every iteration the filename (without extension) in a variable named result for later reuse.
The RemoveExtension function works fine. However I'm not able to retrieve the result and store it in the _result variable. When I print it, it's always empty. Thanks for your help!
#echo OFF
SETLOCAL EnableDelayedExpansion
set "_result="
for /f "delims=" %%i in ('dir "%~1\*.txt" /b') DO (
echo.filepath: "%~1\%%i"
call :RemoveExtension "%%i"
echo._result: "%_result%" // The "_result" variable is always EMPTY ""
)
goto :eof
:RemoveExtension
SETLOCAL
REM echo "%~1"
set "filename=%~1"
:loop
if "%filename:~-1%" NEQ "." (
set "filename=%filename:~0,-1%
goto :loop
)
set "filename=%filename:~0,-1%"
echo "%filename%"
ENDLOCAL & set "_result=%filename%"
goto :eof
Try this...much simpler way to remove the extension. Because you are changing _result inside a FOR loop, you need to access it using ! instead of %.
#ECHO OFF
SETLOCAL EnableDelayedExpansion
SET "_result="
FOR /f "delims=" %%i IN ('dir "%~1\*.txt" /b') DO (
ECHO.filepath: "%~1\%%i"
SET _result=%%~ni
ECHO._result: "!_result!"
)