I have this code:
SETLOCAL enabledelayedexpansion enableextensions
SET OutofService=Weblog_Doc(file:///C:/Bla/BlaKon.htm?send=2000)
REM - Declare and set the Array
FOR /f "delims=" %%a IN (C:\Folder1\log.dat) DO (
SET /a c+=1
SET x[!c!]=%%a
)
REM - Read Array from end to start
FOR /l %%I IN (!c! -1 1) DO (
SET _result=!x[%%I]:~-47%!
ECHO !_result!
ECHO !OutofService!
IF "!_result!"=="!OutofService!" (
ECHO yahooo!
)
)
The string in file log.dat is as follows:
09/17/15 15:18:52:577 Container:
Weblog_Doc(file:///C:/Bla/BlaKon.htm?send=2000)
My ECHO statement is outputting the result:
Weblog_Doc(file:///C:/Bla/BlaKon.htm?send=2000)
Weblog_Doc(file:///C:/Bla/BlaKon.htm?send=2000)
The if statement is returning false and not outputting yahooo! as it should, given the fact that these two strings should be equal. What am I doing wrong?
SET x[!c!]=%%a
^^^^^^^^^^ Spaces included in value
....
SET _result=!x[%%I]:~-47%!
^^^^^^ Spaces included in value
Try with (percent sign in the third line is not needed)
SET "OutofService=Weblog_Doc(file:///C:/Bla/BlaKon.htm?send=2000)"
....
SET "x[!c!]=%%a"
....
SET "_result=!x[%%I]:~-47!"
This way, while the assignment operation is quoted, the quotes are not included in the value, nor the ending spaces if present.
Related
I want to find the string A in the variable Code=AAABASDG
and count each time 1 up if "A" was found so the result should be that it outputs 4 because in Code variable there are 4 A's
Example Code :
#echo off
set /A C=0
set Code=AAABASDG
for %%i in (%Code%) do IF "%%i"=="A" set /A C=%C%+1
echo %C%
pause
You could get the length of original string A, then delete the "A" letters from the string and get the length of the result, to finally subtract both lengths.
To easily get the length of the string, you could store it in a file and then ask for the %%~Z size of the file. Here it is:
#echo off
setlocal
set "Code=AAABASDG"
> before.txt echo %code%
> after.txt echo %code:A=%
for %%b in (before.txt) do for %%a in (after.txt) do set /A "count=%%~Zb-%%~Za"
echo %count%
The only drawback of this method is that it is not case-aware: both upcase and lowcase letters are delete in the replacement operation
#echo off
set /A C=0
set "Code=AAABASDG"
:loop
if defined code (
if "%code:~-1%"=="A" set /a C+=1
set "code=%code:~0,-1%"
goto loop
)
echo %C%
Use set "var=value" for setting string values - this avoids problems caused by trailing spaces. Don't assign " or a terminal backslash or Space. Build pathnames from the elements - counterintuitively, it is likely to make the process easier.
Substrings in batch are obtained from %var:~m,n% where ,n is optional; m is count-of-chars-from-beginning-of-string, from end if negative. ,n positive = max length to return; negative = end-position in chars from end; missing=return all after m
Here's a quick example which gets help from PowerShell:
#Echo Off
SetLocal EnableExtensions
Set "Code=AAABASDG"
For /F %%G In ('%SystemRoot%\System32\WindowsPowerShell\v1.0\powershell.exe
-NoProfile "[RegEx]::Matches('%Code%','A').Count"') Do Set "C=%%G"
Echo(%C%
Pause
So my code here:
#echo off
pause
setlocal ENABLEEXTENSIONS ENABLEDELAYEDEXPANSION
set alfanum=ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789
:a
timeout /t 1
set generator=
FOR /L %%b IN (0, 1, 5) DO (
SET /A rnd_num=!RANDOM! * 62 / 32768 + 1
for /F %%c in ('echo %%alfanum:~!rnd_num!^,1%%') do set generator=!generator!%%c
)
echo %generator%
goto generator
Is slightly broken because sometimes "ECHO" shows up in the middle of generating. for example:
vMECHO8ECHOE <<
DQTGv0
aECx5i
lLECHOO3H <<
cOd4ECHOg <<
6950pC
Help? running on Windows 10 CMD.
Substring modification is 0 indexed. ensure the index you use is EQU to the number of characters - 1
FOR /L %%n IN (0,1,5)Do For /F "delims=" %%c In ( 'SET /A "_r=!RANDOM! %% 62"' )Do (
Set "generator=!generator!!alfanum:~%%c,1!"
)
Remove the + 1 from your set /A command line and you will be fine:
set /A "rnd_num=!RANDOM!*62/32768"
Which can be simplified to:
set /A "rnd_num=!RANDOM!%%62"
You actually point past the string in !alfanum!, because the position index for sub-string expansion is zero-based, meaning 0 points to the first character, and 61 to the last one in your 62-character string. Your current code returns 62 as the greatest possible random number, so the sub-string expansion returns an empty string, which lets the echo command in your for /F loop output ECHO is {on|off}., resulting in the result ECHO due to the default token string tokens=1 of for /F.
Anyway, The for /F loop is not necessary, just replace it by the line:
rem /* The standard `for` loop ensures that the value of `!rnd_num!` is expanded
rem BEFORE delayed sub-string expansion of `!alfanum:~...!` occurs: */
for %%a in (!rnd_num!) do set "generator=!generator!!alfanum:~%%a,1!"
Or (slower):
rem /* The `call` command ensures that the sub-string of `%alfanum:~...%`
rem is expanded AFTER delayed expansion of `!rnd_num!` occurs: */
call set "generator=!generator!%%alfanum:~!rnd_num!,1%%"
(EDITED) How can I read data from a text file and assign certain parts of it to variables? In the lines below, for example, I want to assign the data to variables where indicated but ignore the header line, the preface word "DATA:" and any quotation marks.
HEADER (ignore)
DATA: "set text inside quotes to VAR1"
DATA: "set text inside quotes to VAR2"
DATA (etc.)
The code I'm using is:
setlocal enabledelayedexpansion
set COUNT=0
for /f "usebackq delims=" %%a in ("data.txt") do (
set "INPUT=%%a"
set /a COUNT=!COUNT!+1
echo !INPUT! | findstr /i /c:"HEADER" > nul
if errorlevel 1 (
set "INPUT=!INPUT:DATA:=!"
set "INPUT=!INPUT:"=!"
set VAR!COUNT!=!INPUT!
echo Variable !COUNT! = !VAR!!COUNT!
)
)
My expected output is
Variable 1 = set text inside quotes to VAR1
Variable 2 = set text inside quotes to VAR2
but what I get is
Variable 2 = 2
Variable 3 = 3
Variable 4 = 4
What am I doing wrong?
I took your code and fixed it up.
In particular:
I switched the findstr to find all lines that do not match HEADER
I used arrays to store the variables.
It may need some minor tweaks to get it exactly as you want it, but I think I've given you a working outline.
#echo off
setlocal enabledelayedexpansion
set COUNT=0
for /f "tokens=*" %%a in ('findstr /i /v HEADER data.txt') do (
set "INPUT=%%a"
set /A COUNT=!COUNT!+1
set "INPUT=!INPUT:DATA:=!"
set VAR[!COUNT!]=!INPUT!
call echo Variable !COUNT! = %%VAR[!COUNT!]%%
)
Output:
Variable 1 = "set text inside quotes to VAR1"
Variable 2 = "set text inside quotes to VAR2"
Variable 3 = DATA (etc.)
To match lines that have leading spaces, use switches:
findstr /V /R /C:"^ *HEADER"
The regular expression means:
^ : Beginning of line
[space] : a literal space
* : the previous character (space) repeated as many times as needed
HEADER : the text to find after leading spaces
The switches mean:
/R Use Regular Expressions
/C: Use this search-string
/V Show all lines that do NOT match this expression.
I want create a batch to replace spaces with a + sign if the space is in between quotes. Then I want to remove the quotes from a text file. How can I accomplish this?
So I want to change a line like this:
2016-01-11 14:45:09 Server 127.0.0.1 GET /global/images/logo_small.jpg - 80 - 173.252.120.117 "facebookexternalhit/1.1 (+http://www.facebook.com/externalhit_uatext.php)" "-" www.vietnam.ttu.edu 200 200 200 1868 0
To this line.
2016-01-11 14:45:09 Server 127.0.0.1 GET /global/images/logo_small.jpg - 80 - 173.252.120.117 facebookexternalhit/1.1+(+http://www.facebook.com/externalhit_uatext.php) - www.vietnam.ttu.edu 200 200 200 1868 0
Thanks
You could use JREPL.BAT to arrive at a very concise and efficient solution. JREPL is a pure script based (JScript/batch) regular expression text processing utility that runs on any version of Windows from XP onward.
jrepl "\q| " "q=!q;''|q?'+':' '" /j /x /t "|" /jbegln "q=false" /f test.txt /o -
For this solution I use the /T option, which is very similar to the unix tr utility, or the sed y command.
I define two search terms, the first for a quote (The \X option enables the \q escape sequence), and the second for a space.
The /J option treats replacement strings as JScript. The first replacement string for the quote toggles a "q" variable TRUE or FALSE, and replaces the quote with an empty string. The second replacement string conditionally replaces the space with a plus or space, depending on the state of the "q" variable.
The /JBEGLN option initializes the "q" variable to FALSE at the beginning of each line.
The /F option specifies the input file, and the /O - option specifies that the output overwrites the original file.
#ECHO OFF
SETLOCAL
SET "sourcedir=U:\sourcedir"
SET "filename1=%sourcedir%\q34732271.txt"
FOR /f "usebackqdelims=" %%a IN ("%filename1%") DO ECHO %%a&SET "line="&CALL :process %%a
GOTO :EOF
:process
SET "addition=%~1"
IF not DEFINED addition ECHO %line:~1%&GOTO :eof
IF "%~1"==%1 (
REM quoted
SET "line=%line% %addition: =+%"
) ELSE (
SET "line=%line% %addition%"
)
shift
GOTO process
You would need to change the setting of sourcedir to suit your circumstances.
I used a file named q34732271.txt containing your data for my testing.
The echo %%a shows your one line of data on the screen and the echo within the :process routine shows that line processed.
Batch is not an ideal language to process strings as it exhibits sensitivity to many symbols. This process should work provided you are happy to have space-strings compressed and the source string does not contain , ;,tab % or any other symbol that cmd treats specially.
Here is a pure batch-file solution that walks through the characters in each line in file line.txt, replaces all SPACEs in between a pair of quotation marks "" by + signs and stores the result in text_new.txt. The input string may contain any characters, even special ones:
#echo off
setlocal EnableExtensions DisableDelayedExpansion
rem Define global constants here:
set "INFILE=line.txt"
set "OUTFILE=line_new.txt"
set "SEARCH= "
set "REPLACE=+"
set "KEEPQUOTES="
set "QUOTE="""
set "QUOTE=%QUOTE:~,1%"
set "QFLAG="
> "%OUTFILE%" (
for /F usebackq^ delims^=^ eol^= %%L in ("%INFILE%") do (
set "LINE=%%L"
call :SUB LINE
)
)
endlocal
exit /B
:SUB
setlocal EnableDelayedExpansion
set "LINE=!%1!"
set "LINENEW="
set /A "POS=0"
:LOOP
set "CHAR=!LINE:~%POS%,1!"
set /A "POS+=1"
if not defined CHAR (
echo(!LINENEW!
endlocal
exit /B
)
if "!CHAR!"=="!QUOTE!" (
if defined QFLAG (
set "QFLAG="
) else (
set "QFLAG=Quoted"
)
if defined KEEPQUOTES (
set "LINENEW=!LINENEW!!CHAR!"
)
) else if defined QFLAG (
if "!CHAR!"=="!SEARCH!" (
set "LINENEW=!LINENEW!!REPLACE!"
) else (
set "LINENEW=!LINENEW!!CHAR!"
)
) else (
set "LINENEW=!LINENEW!!CHAR!"
)
goto :LOOP
%params% contains a variable set of arguments:
/tidy /log /truncate /convert D:\libdir
or maybe
/log /tidy D:\cyclea\libfolder /test /convert /truncate
for everything but the (currently single) filepath element I use it such:
if "%params%"=="%params:log=%" goto :DontLogit
if NOT "%params%"=="%params:/tidy=%" (call tidysub: & do something else )
Now I want to extract the filepath element and use it as an argument to a command eg chdir
I've played with, but I'm weak with CMD string manipulation and for loops.
I'd like to keep the order of params variable.
For info it comes from here:
FOR %%s IN (%*) DO (set params=!params! %%s)
#ECHO OFF
SETLOCAL
SET swparams=log tidy test convert truncate
FOR %%i IN (%swparams% other) DO SET "%%i="
FOR %%i IN (%*) DO (
SET "used="
FOR %%p IN (%swparams%) DO (IF /i "/%%p"=="%%~i" SET %%p=Y&SET used=Y)
IF NOT DEFINED used CALL SET other=%%other%% "%%~i"
)
ECHO =============paramsreport===========
FOR %%i IN (%swparams%) DO IF DEFINED %%i (ECHO %%i:set) ELSE (ECHO %%i:clear)
ECHO other=%other%
FOR %%i IN (%other%) DO ECHO %%i or %%~i
GOTO :EOF
Here's a way that should be extensible for you.
Simply set you switch-parameters into the list in swparams.
the parameter-names and OTHER are set to [nothing] to ensure they're not already set in the environment.
Ech supplied parameter is applied to %%i in turn, and matched against each defined swparam in turn. the variable USED is cleared before the match and if the match (of /switchparametername is found, the switch parameter is set and the USED flag is set.
if the used flag is not set gainst any of the switch parameters, then a parsing trick is used to accumulate any unrecognised strings into OTHER
The "%%~i" mechanism first dequotes the item in %%i, then quotes it. In this way, it ends up quoted, regardless of whether it originally has quotes or not.
The /i on the if performs a case-insensitive match.
hence running this batch
thisbatch /tidy "C:\some filename with spaces.txt"
will yield TIDY set to Y, LOG,test, convert, truncate not set and other set to "C:\some filename with spaces.txt"
#echo off
setlocal EnableDelayedExpansion
rem Get the single filepath element (with colon in second character):
set params=/tidy /log /truncate /convert D:\libdir
set filepath=
for %%a in (%params%) do (
set par=%%a
if "!par:~1,1!" == ":" (
set filepath=%%a
)
)
if defined filepath (
echo Filepath = %filepath%
) else (
echo Filepath not given
)
echo/
rem Get multiple filepath elements in an *array*:
set params=/log /tidy D:\cyclea\libfolder /test /convert D:\libdir /truncate
set i=0
for %%a in (%params%) do (
set par=%%a
if "!par:~1,1!" == ":" (
set /A i+=1
set filepath[!i!]=%%a
)
)
echo There are %i% filepath elements:
for /L %%i in (1,1,%i%) do (
echo %%i- !filepath[%%i]!
)
You may review a further description on array management at this post: Arrays, linked lists and other data structures in cmd.exe (batch) script