Manage accented characters in string - batch-file

I am trying to make a simple batch script to compare two files and open them if it found a difference.
So I use FC to compare the files; if no difference is found, it'll send me this text:
Comparaison des fichiers FILE1 et FILE2
FC : aucune différence trouvée
As you can see, it's in French, and it contains accented characters. That's my problem.
So here's my code so far:
#echo off
set "FILE1=file1path"
set "FILE2=file2path"
set "edit=editorpath"
for /F "tokens=*" %%F in ('fc /A /C /N "%FILE1%" "%FILE2%"') do (
set "DIFF=%%F"
)
set "NODIFF=FC : aucune différence trouvée"
if /I "%DIFF%"=="%NODIFF%" (
echo "no difference found"
) else (
start "" %edit% %FILE1%
start "" %edit% %FILE2%
)
The problem is in "%DIFF%==%NODIFF%: the two vars are always different, even when they should be the same (I've tried with or without "" for the set and the If comparison). To see this, I've tried to echo both var. Here's what I get:
echo %DIFF%
FC : aucune différence trouvée
echo %NODIFF%
FC : aucune diff├®rence trouv├®e
seems that the encoding is not the same. Most answer I've found for it was to use some chcp (with different values). If I understand it well, it's supposed to change the encoding so that accented characters "works". So i've tried to add
chcp 65001>nul
to my code, but then I got this result:
echo %DIFF%
FC[?]: aucune diff[?]rence trouv[?]e
echo %NODIFF%
FC : aucune différence trouvée
So now the second string is ok, but the first one no more. I've tried others numbers instead of 65001, but they would just make both strings wrong (and not in the same way).
ofc I can also do something like this:
chcp 850
echo %DIFF%
FC : aucune différence trouvée
chcp 65001
echo %NODIFF%
FC : aucune différence trouvée
But then in the IF statement, I can't have change the chcp while doing the comparison.
Have someone an idea on how to make it works?
PS: i'm using cmd and NOT POWERSHELL on windows10 64bits with MINGW.

If you really wanted to do what you intended, then just narrow your result to verifying just the known standard characters:
#Echo Off
Set "FILE1=file1path"
Set "FILE2=file2path"
Set "edit=editorpath"
For /F Delims^=^ EOL^= %%G In (
'""%__APPDIR__%fc.exe" /A /C /N "%FILE1%" "%FILE2%""') Do Set "DIFF=%%G"
If /I Not "%DIFF%"=="%DIFF: aucune diff=%" (Echo no difference found) Else (
Start "" "%edit%" "%FILE1%"
Start "" "%edit%" "%FILE2%")
Exit /B
Essentially you're case insensitively comparing two strings, the second with the substring aucune diff removed. If they're not the same, then the substring was part of the string. Please note that as English versions would use FC: no differences encountered, your current idea is still language/locale dependent.
However, in my opinion, there's no need for a for-loop or to jump through hoops with language/locale dependent strings. You can simply use the returned exit code, (ErrorLevel):
2 Could not open at least one of the files.
1 Differences found.
0 No differences encountered.
-1 Invalid syntax used.
#Echo Off
Set "FILE1=fileone.cmd"
Set "FILE2=filetwo.cmd"
Set "FILE3=filethree.cmd"
"%__AppDir__%fc.exe" /A /C /N "%FILE1%" "%FILE2%" >NUL 2>&1
If %ERRORLEVEL% Equ 2 (Echo Could not open at least one of the files.
) Else If %ERRORLEVEL% Equ 1 (Start "" "%edit%" "%FILE1%"
Start "" "%edit%" "%FILE2%") Else If %ERRORLEVEL% Equ 0 (
Echo No differences encountered.) Else Echo Invalid syntax used.
Pause
GoTo :EOF
Although for your purposes, you could simply use && and || to conditionally determine if the previous command was successful or not:
#Echo Off
Set "FILE1=file1path"
Set "FILE2=file2path"
Set "edit=editorpath"
%__APPDIR__%fc.exe /A /C /N "%FILE1%" "%FILE2%" >NUL 2>&1 && (
Echo no difference found) || (Start "" "%edit%" "%FILE1%"
Start "" "%edit%" "%FILE2%")
Exit /B

Related

Batch file to edit .ini file but do not delete blank space

I am new to StackOverflow. I want to run a batch file to find and replace a single string in an .ini file. I tried several solutions given on stackoverflow and other sites too.
A few of them are working - but delete my other lines having "space" or ";".
Here is the string that I want to find and change in my file RDConfigSettings.ini
CommunicationMode:1
I want it vice-versa:
if it is "CommunicationMode:1" then change it to "CommunicationMode:0"
if it is "CommunicationMode:0" then change it to "CommunicationMode:1"
Here is the whole content of my RDConfigSettings.ini file
;0 for Staging, 1 for Pre-Production, 2 for Production
RDEnviroment:2
;0 for disable, 1 for Enable
RDServiceLogs:0
;0 for disable, 1 for Enable
ClientValidation:0
;Validate Management Server Certificate -- 0 for Yes, 1 for No
ValidateCertificate:0
;Proxy Configuration -- 0 for Direct Internet Access, 1 for Access via Proxy
ProxyConfig:0
ProxyIP:[Proxy IP]
ProxyPort:[Proxy Port]
;0 for Https, 1 for Http
CommunicationMode:1
;Port Range Setting in below field
PortBegin:11100
PortEnd:11120
;ManagementServerURL
Registration:https://rdm.smartbioplus.com/rdm-device-app/registration
Keyrotation:https://rdm.smartbioplus.com/rdm-key-management-app/keyRotation
Telemetry:https://rdm.smartbioplus.com/rdm-telemetry-app/telemetry
Domain:rdm.smartbioplus.com
URL_Port:443
Could anyone help me? THis is my code:
#echo off
set "file=E:\CSC Softwares\MorphoRdServiceL0Soft\RDConfigSettings.ini"
:loop
findstr "^CommunicationMode:0$" "%file%" >nul || (
type "%file%"|repl "^CommunicationMode:1" "CommunicationMode:0" >"%file%.tmp"
move "%file%.tmp" "%file%" >nul
)
timeout 120 >nul
goto :loop
Moreover, it will be a great help if someone can add an Command with administrative rights that will stop a particular service "MORPHO_RD_Service" before replacing the string and then after replace the string, start the same service again.
You have code to switch from 1 to 0, but no code to switch from 0 to 1.
Below code alternates between 1 and 0 with each run of the loop.
I also changed to jrepl (more modern and powerful). It isn't necessary (though possible) to process piped data and redirect the result to another file. The /f switch gives the inputfile to process, the /o switch gives the outputfile. By giving it a single -, it uses the same filename as the input file (and overwrites it with the new(changed) data).
#echo off
set "file=t.txt"
:loop
findstr "^CommunicationMode:" "%file%" & REM this line for troubleshooting only
findstr "^CommunicationMode:0$" "%file%" >nul && (
call jrepl "CommunicationMode:0" "CommunicationMode:1" /f "%file%" /o -
) || (
call jrepl "CommunicationMode:1" "CommunicationMode:0" /f "%file%" /o -
)
timeout 1 >nul
goto :loop
Don't forget to adapt the data file name and the timeout to your needs.
Without the need for an external utility such as jrepl, which is great for some things, but not needed for such a task:
#echo off
setlocal enabledelayedexpansion
set "file=E:\CSC Softwares\MorphoRdServiceL0Soft\RDConfigSettings.ini"
for /f "tokens=1,*delims=]" %%i in ('type "%file%" ^| find /v /n "" ^& break^>"%file%"') do (
set "line=%%j"
if "!line!" == "CommunicationMode:1" (
set "line=!line:1=0!"
set "hold=!line!"
) else if "!line!" == "CommunicationMode:0" (
set "line=!line:0=1!"
set "hold=!line!"
)
echo(!line!>>"!file!"
)
echo Changed to !hold!
pause

Check if substring exist in string from cmd/bat script

I want to check if count exists in mycountry or not, and then do some operations according.
My code snippet :
rem #ECHO OFF
cls
SET FILE="mycountry"
If true I want to run 3 statements and if false I want to run 3 other statements.
I have tried this combination:
Echo.%FILE% | findstr /C:"count">nul && (Echo.TRUE) || (Echo.FALSE)
But how to write multiple statements if the condition gets true? I don't wanna use any flag variable.
Below snippet is not working.
Echo.%FILE% | findstr /C:"count">nul &&
(
Echo.TRUE
echo "ran correct."
)
|| (Echo.FALSE)
You can use the %errorlevel% value combined with an if/else.
See the example below:
REM #echo off
cls
SET FILE="mycountry"
SET STR="TEST"
findstr %STR% %FILE% >nul
if %errorlevel% equ 1 (
goto searchError
) else (
goto searchSucces
)
:searchSucces
echo String %STR% found in file %FILE%
pause
exit
:searchError
echo String %STR% not found in file %FILE%
pause
exit
Your code, (integrated into a batch file), appears to work as expected:
#Echo Off
Set "FILE="
Set /P "FILE=Enter String: "
If Not Defined FILE Exit /B
Echo.%FILE% | findstr /C:"count">nul && (Echo.TRUE) || (Echo.FALSE)
Pause
In addition, the following two methods both appear to work as expected:
Using Echo and FindStr (as in your code):
#Echo Off
Set "FILE="
Set /P "FILE=Enter String: "
Echo=%FILE%|FindStr /IC:"count">Nul 2>&1&&(Echo TRUE
Echo Ran correct.
Timeout 3 /NoBreak>Nul
Echo Still running!)||Echo FALSE
Pause
Using variable substitution:
#Echo Off
Set "FILE="
Set /P "FILE=Enter String: "
If /I "%FILE:count=%"=="%FILE%" (Echo FALSE) Else (Echo TRUE
Echo Ran correct.
Timeout 3 /NoBreak>Nul
Echo Still running!)
Pause
If the examples above do not work for you, you should edit your question to include the actual code and strings you're using in your real world scenario. We cannot fix something we cannot see, especially if you don't fully explain the issue, (snippet is not working is a statement only, not an explanation).

Findstr with wild card or greater than "X" Time

Trying to put a batch file together that will find a string within a text file. Only obstacle is I want to find values that occur in the evening(PM) and NOT in the Morning(AM).
I am trying to find "XBR Upload successful" however only if exists in the PM:
Exert from the log file:
[3:35:07AM] XBR Upload successful.
I have the following:
#echo off
findstr /M "[*PM] XBR Upload successful." C:\Test.log
if errorlevel = 1 GOTO NOMATCH
if errorlevel = 2 GOTO MATCH
Wildcards * does not seem to be working for me. Seems to find [*PM] even though in the log file no PM timing exists yet.
Any guidance appreciated!
You should try like that :
#echo off
Set InputFile=c:\Test.log
Set OutPutFile=c:\LogFile.txt
Type "%InPutFile%" |findstr /M /R /C:"\[.*PM\] XBR Upload successful." > %OutPutFile%
If "%Errorlevel%" EQU "1" GOTO :NOMATCH
If "%Errorlevel%" EQU "0" GOTO :MATCH
:MATCH
Color 0A
echo MATCH
pause
Start "" %OutPutFile%
Exit /b
:NOMATCH
Color 0C
echo NO MATCH
pause
Exit /b
Your code does not work as you want because you are misinterpreting what * does in regular expressions. Normally it is a quantifier, not a wild card.
The expression x* means "match 0 or more x characters". But your case is a bit special because the * appears within square brackets, so it is interpreted as a character class. [*] matches a * literal character.
The expression you wanted was \[.*]
. is the wildcard, and \ escapes the [ so that it is a literal instead of the beginning of a character class.
Also, you must use the /C option if your search string includes spaces. Since you are doing a regular expression, then you also need the /R option to override the /C string literal interpretation behavior.
findstr /R /C:"\[.*PM] XBR Upload successful." C:\Test.log >nul && goto Match || goto NoMatch
But as others have indicated, you could probably get away with a simpler string literal search, without any wildcard.
findstr /C:"PM] XBR Upload successful." C:\Test.log >nul && goto Match || goto NoMatch

Why does the error message appear when `IF` comparison is in the piped block command?

I simplified the code.
The following three are work.
for /L %a in (1,1,9) do #(if %a NEQ 0 (echo %a))
&
for /L %a in (1,1,9) do #(if not %a == 0 (echo %a))
&
(for /L %a in (1,1,9) do #(if not %a == 0 (echo %a)))|sort /R
But the next one didn't work,
(for /L %a in (1,1,9) do #(if %a NEQ 0 (echo %a)))|sort /R
What's the problem of NEQ in the piped block command?
more simplified,
This works, (if 3 == 3 echo yes)|sort
This doesn't work, (if 3 NEQ 2 echo yes)|sort
Part of my code.
#echo off
setlocal enabledelayedexpansion
set Unx_path=.....\bin\UnxUtils\
(
for /F %%a in ('^""%Unx_path%pclip.exe"^|"%Unx_path%sed.exe" -r "s/^^$/none/"^|"%Unx_path%sed.exe" -rf "script_file"^"') do #(
if not "%%a" == "none" (
"%Unx_path%grep.exe" -iEe "%%a" "file4search"|"%Unx_path%sed.exe" -r "s/^^[^,]+$/,&/";"s/^^([^.]+)[.][^.]+$/\1/"|"%Unx_path%gawk.exe" "BEGIN{FS=\",\";ORS=\" \"}{print $2}"|"%Unx_path%sed.exe" "s/%%a//I g";"s/.*/%%a &|/";"s/ -/ /g";"s/ |/\n/g";"s/ /\t/g";"s/~/\t/g"
) else (
echo none
)
)
)|"%Unx_path%gclip.exe"
exit /b
try this:
set "myline=if 3 NEQ 2 echo yes"
( %myLin^e%)|sort
or from batch file (double expansion works differently from batch file and the console):
set "myline=if 3 NEQ 2 echo yes"
( %%myLine%%)|sort
The "mystery" was solved by jeb here and here . Though you are facing the issue before the pipe it is the same bug because the cmd creates two threads on each side of the pipe.
Here's how the for loop can be made to work:
set "line=if %a NEQ 0"
(for /L %a in (1,1,9) do #( %lin^e% echo %a))|sort /R
For testing purposes the cmdcmdline variable can be used.
But this fails, when somewhere in the expression is a syntax error, as the complete code block will be dropped.
#echo off
echo dummy | (
echo %%cmdcmdline%
if 1 NEQ 2 echo Work
)
This results into "2" can't be syntactically evaluated here (From german "2" kann syntaktisch an dieser Stelle nicht verarbeitet werden.)
So exactly in the case of a syntax error, you can't see the cause!
I build a small debug variable for this case
#echo off
setlocal
(set \n=^
%=empty=%
)
set "debug=echo ### %%cmdcmdline%% ^) %%\n%%"
echo dummy | (
%debug%
if 1 NEQ 2 echo Work
)
When you add the %debug% you will see the cmdcmdline, but the code will not be executed, so you can examine how different modification take effect.
Like
...
| (
%debug%
break & if 1 NEQ 2 echo THIS FAILS
)
but
...
| (
%debug%
break ^& if 1 NEQ 2 echo This Works !!!
)
The trick is to add ^) %%\n%%, this closes the debug expression code block with ) and cancels further parsing of the remaing code by the linefeed %%\n%%.
Base on the idea & method from npocmaka & jeb.
Another way was found to solve the error of IF command in piped code.
TO ADD AN ESCAPE SPACE AT RIGHT POSITION
For EQU NEQ LSS LEQ GTR or GEQ,
ONE ^ has to be added after 1st compared string/number,
At least TWO SPACE have to be added between this ^ and EQU NEQ LSS LEQ GTR or GEQ.
Example,
echo pipe|IF 1234^ GTR 124 echo true
true can be replaced by %^cmdcmdline% to see the parser.
(IF 1234^ NEQ 124 echo right)|more
For IF DEFINED & IF EXIST
At least ONE SPACE has to be added after IF DEFINED or IF EXIST,
At least TWO SPACE have to be added before variable or file/folder,
ONE ^ has to be added between above added SPACE.
Example,
echo pipe|IF DEFINED ^ username echo true
echo pipe|IF EXIST ^ c:\windows echo true
true can be replaced by %^cmdcmdline% to see the parser
(IF DEFINED ^ username echo right)|more
(IF EXIST ^ c:\windows echo right)|more
But so far I didn't know why all of them have to work like above.
Something interesting,
echo pipe|if 123^ equ ====== 123 ====== echo %^cmdcmdline%
All = are ignored.
Updated (2016-04-23),
As npcmaka mentioned, =,, are also delimiters.
CASE 1
echo pipe|if not defined^===neq === echo %^cmdcmdline%
Outputs,
C:\Windows\system32\cmd.exe /S /D /c" if not defined=== neq echo %cmdcmdline%"
CASE 2
echo pipe|if not defined^ === neq === echo %^cmdcmdline%
Outputs,
C:\Windows\system32\cmd.exe /S /D /c" if not defined == = neq === echo %cmdcmdline%"
One space appears between ===.
CASE 3
echo pipe|if not defined^,,,neq ,,, echo %^cmdcmdline%
Outputs,
C:\Windows\system32\cmd.exe /S /D /c" if not defined,NEQ echo %cmdcmdline%"
Some phenomenon can be found, which may be known how to parse...
neq is identified as variable in all CASE. (do set neq=blah before will occur no output for all CASE)
In CASE 2, == in Delimiter === seems be identified as comparison and auto be added one space after
According to the rule in CASE 2, in CASE 3, input neq is lowercase and output NEQ is uppercase. But in CASE 1 & 2, due to existed == before neq, this time, neq is kept in lowercase, which is not identified as comparison.
So it has several steps in parser period. But has some bugs of adding or deleting delimiters. Right?
CASE 4
The next code seems trigger cmd executing infinitely,
echo pipe|if not defined^ == echo %^cmdcmdline%
it runs like if not "defined" == "echo" recursive command
I think the easiest work-around to get if statements working within pipes is the following (the outer surrounding pair of parentheses is mandatory):
(if^ comparison_expression conditional_command_line)
(if^ comparison_expression (conditional_command_line) else other_conditional_command_line)
I tested it with all keywords like not, exist and defined, else clauses, all possible comparison operators (==, EQU, NEQ, etc.), for either side of the pipe, and in cmd and batch-files.
Also I also successfully tested the if statements embedded within the body of a for loop (in which case the outer parentheses are no longer required).

Batch File w/ Delayed Variable Expansion - URL Encoding - equal sign - RSA Token Converter

I am automating RSA soft token conversion and passing the conversion string over to Outlook. I realize I cannot make the string into a URL using a batch to outlook command line, however that is not my issue. My issue is converting the pesky equal sign over to it's URL encoded equivalent, "%3D".
#echo off
setlocal enableDelayedExpansion
set /p fname=Enter the Filename:
set /p pss=Enter the encryption pass:
IF NOT EXIST "%fname%".sdtid (
echo File Not Found! Closing...
PING 1.1.1.1 -n 4 >NUL
exit
)
echo File Found! starting process...
REM tokenconverter %fname%.sdtid -iphone >> temp_batch.txt
tokenconverter %fname%.sdtid -p %pss% -iphone >> temp_batch.txt
set /p result= < temp_batch.txt
DEL temp_batch.txt
REM %result% | clip
set "stringclean1=!result:?=%%3F!"
set "stringclean2=!stringclean1::=%%3A!"
set "stringclean3=!stringclean2:/=%%2F!"
The following line fails to encode the equal sign:
set "stringclean4=!stringclean3:==%%3D!"
I've tried:
set "stringclean4=!stringclean3:=^=%%3D!"
set "stringclean4=!stringclean3:=%=%%3D!"
However the equal sign remains unencoded.
echo Piping over to outlook..
REM passing stringclean3 since stringclean4 no worky.
pushd "C:\Program Files\Microsoft Office\Office12"
outlook.exe /c ipm.note /m "&subject=TEsT&body=%stringclean3%"
What is the proper way to URL encode the equal sign using delayed variable expansion?
Any assistance is appreciated. Thanks in advance.
Sorry, a simple solution for replacing = in batch simply does not exist :-(
About the best you can do using pure batch is to loop through the string, character by character, and replace as needed.
Here is a brute force solution that has some room for more optimization. But it is good enough. It first checks to see if = exists before taking the time to encode =.
:: test if string contains =
:: only take the time to encode = if it exists
set "test=a!stringClean3!"
for /f "delims=" %%S in ("!test!") do if /i "!test:%%S=%%S!" neq "!test!" (
:: compute length of string - 1
set end=0
for /l %%A in (12,-1,0) do (
set /a "end|=1<<%%A"
for %%B in (!end!) do if "!stringClean3:~%%B,1!"=="" set /a "end&=~1<<%%A"
)
:: replace = with %3D
for /l %%N in (0 1 !end!) do (
if "!stringClean3:~%%N,1!" equ "=" (
set "stringClean4=!stringClean4!%%3D"
) else (
set "stringClean4=!stringClean4!!stringClean3:~%%N,1!"
)
)
) else set stringClean4=!stringClean3!
EDIT
Here is another completely different approach that uses CERTUTIL to encode and decode the string as hex. It is a simple matter to encode the hex string. I don't think CERTUTIL is delivered with XP. I can't remember, but the CERTUTIL syntax may change slightly depending on the version of Windows. I developed and tested this on Vista.
set "tempFile=%temp%\replaceEqual%random%"
(>"%tempFile%.before" echo(!stringClean3!)
certutil -encodehex "%tempFile%.before" "%tempFile%.hex" >nul
>"%tempFile%.hex2" (
for /f "usebackq tokens=1*" %%A in ("%tempFile%.hex") do (
set ln=%%B
set "ln=!ln:~0,48!"
(echo !ln:3d=25 33 44!)
)
)
certutil -decodehex "%tempFile%.hex2" "%tempFile%.after" >nul
<"%tempFile%.after" set /p "stringClean4="
del "%tempFile%.*"
The use of SET /P to read the result leads to the following limitations:
the string must be less than or equal to 1021 characters long.
the string must not end with a control character (trailing control chars are stripped)
the string must not contain line feeds
The result could be read using FOR /F, but then the delayed expansion will corrupt any ! when the FOR variable is expanded.
dbenham had a good idea about using JScript's encodeURIComponent method. Here it is, stuffed into the OP's example script:
#echo off
setlocal
set /p fname=Enter the Filename:
set /p pss=Enter the encryption pass:
IF NOT EXIST "%fname%".sdtid (
echo File Not Found! Closing...
PING 1.1.1.1 -n 4 >NUL
exit
)
echo File Found! starting process...
echo WScript.Stdout.WriteLine(encodeURIComponent(WScript.StdIn.ReadLine()));>uri.js
for /f "delims=" %%I in (
'tokenconverter %fname%.sdtid -p %pss% -iphone ^| cscript /nologo uri.js'
) do set "result=%%I"
del uri.js
SET result=qm?colon:slash/equal=qm?colon:slash/equal=end
set "stringclean0=!result!"
:loop3D
FOR /f "tokens=1,2*delims==" %%i IN ('SET stringclean0') DO (
IF NOT "%%k"=="" set stringclean0=%%j%%3D%%k&GOTO loop3D
)
set "stringclean1=!stringclean0:?=%%3F!"
set "stringclean2=!stringclean1::=%%3A!"
set "stringclean3=!stringclean2:/=%%2F!"
SET stri

Resources