This is my batch script:
#echo off
title
setlocal enabledelayedexpansion
:a
set /p a=
!d!
for %%G in (%a%) do (set /a b+=1
if !b! neq 1 (set c=!c!-%%G) else (set c=%%G))
echo wscript.createobject("sapi.spvoice").speak "!c!">a.vbs
start a.vbs
exit
For every time that this program runs, it overwrites the a.vbs file with the new code as variable c. Is it possible to have "wscript.createobject("sapi.spvoice").speak "!c!"" preexisting in a VBScript and simply have batch assign the variable and execute it instead of overwriting and then executing?
With the help of aphoria, I tweaked my scripts to this:
VBScript:
wscript.createobject("sapi.spvoice").speak wscript.arguments(0)
Batch Script:
#echo off
title
setlocal enabledelayedexpansion
set /p a=
for %%G in (!a!) do (set /a b+=1
if !b! neq 1 (set c=!c!-%%G) else (set c=%%G))
cscript //nologo b.vbs !c!
exit
May I suggest you another solution?
JScript language is similar to VBScript, but have an advantage in this case: the JScript code can be placed inside the Batch file itself via a very simple trick. This way, it is not necessary to create a separated file with the JScript code:
#if (#CodeSection == #Batch) #then
:: Previous line is:
:: - in Batch: a valid IF command that does nothing
:: - in JScript: a conditional compilation IF statement that is false
:: so the following code is omitted until the next atSign-end
#echo off
title
setlocal enabledelayedexpansion
set /p a=
for %%G in (!a!) do (set /a b+=1
if !b! neq 1 (set c=!c!-%%G) else (set c=%%G))
rem Execute this Batch file as a JScript one:
cscript //nologo //E:JScript "%~F0" !c!
exit
#end
WScript.CreateObject("sapi.spvoice").Speak(WScript.Arguments(0));
In this case the original VBScript code is so simple that the JScript translation is immediate; just note that the uppercase letters are needed in JScript. However, I am not entirely sure that spvoice execute the same in JScript than in VBScript; you must do a test...
Create a script file SpeakNumber.vbs (call it whatever you want).
Put this inside it:
Set args = Wscript.Arguments
WScript.CreateObject("sapi.spvoice").Speak args(0)
Then, change your batch file like this:
#echo off
title
setlocal enabledelayedexpansion
:a
set /p a=
!d!
for %%G in (%a%) do (set /a b+=1
if !b! neq 1 (set c=!c!-%%G) else (set c=%%G))
START SpeakNumber.vbs !c!
exit
This is my batch script:
#echo off title setlocal enabledelayedexpansion :a set /p a= !d!
for %%G in (%a%)
do (set /a b+=1
if !b! neq 1
(set c=!c!-%%G)
else
(set c=%%G))
echo wscript.createobject("sapi.spvoice").speak "!c!">a.vbs
start a.vbs
exit
You dont have use a hybrid as you can embed the vbs file inside the batch file.
#echo off
set /p "Voice= Enter what you would like to say : "
echo dim speechobject >> sapi.vbs
echo set speechobject=createobject("sapi.spvoice") >> sapi.vbs
echo speechobject.speak "%Voice%" >> sapi.vbs
start sapi.vbs
timeout /t 1 /nobreak
del sapi.vbs
Related
#echo off
#chcp 65001
setlocal enableextensions enabledelayedexpansion
set test=qwert
goto start
:IsStrInStrFunc
setlocal
call set check=%%1:%2=%
echo %check%
endlocal
exit /b
:start
call :IsStrInStrFunc %test%, q
pause
The "check" variable must contain "wert". What's wrong?.......
if you want to set %check% to be "wert"
set check=%%1:%2=%
should be
set check=%test:~1%
For more info check command help set in Command Prompt
Perhaps this example will assist you:
#Echo Off
SetLocal EnableExtensions DisableDelayedExpansion
For /F "Delims==" %%G In ('"(Set _cp) 2> NUL"') Do Set "%%G="
For /F Tokens^=* %%G In ('"%SystemRoot%\System32\chcp.com"'
) Do For %%H In (%%G) Do Set "_cp=%%~nH"
If Not %_cp% Equ 65001 (Set "_cpc=TRUE"
"%SystemRoot%\System32\chcp.com" 65001 >NUL)
Set "test=qwert"
GoTo Start
:IsStrInStrFunc
Set "check=%~1"
Echo Before: %check%
SetLocal EnabledelayedExpansion
Set "check=!check:%~2=!"
EndLocal & Echo After: %check%
Exit /B
:Start
Call :IsStrInStrFunc "%test%" "q"
Pause
If Defined _cpc "%SystemRoot%\System32\chcp.com" %_cp% >NUL
GoTo :EOF
To do substring substitution on a variable, you need the variablename, not its value (see set /?), so your parameter in the call can't be %test% (which would pass the string quert), but must be test.
And as you are using delayed expansion anyway, why not using it?
#echo off
#chcp 65001
setlocal enableextensions enabledelayedexpansion
set "test=qwert"
goto start
:IsStrInStrFunc
setlocal
REM call set "check=%%%~1:%~2=%%"
set "check=!%~1:%~2=!"
echo %check%
endlocal
exit /b
:start
call :IsStrInStrFunc test q
PS: you don't need the ~ chars with your simple example, but they don't disturb either. Imagine you want to replace a string, you can simply do that with call :IsStrInStrFunc test "a string" (that's where the ~ are necessary. Good practice to include them anyway (just in case))
So I am trying to make a running batch file to create a new batch file which contains:
#setlocal enableextensions enabledelayedexpansion
#echo off
:remloop
set recfilepath=%pof%
set filename=%pof%
SET filename=%_filename:*\=%
if not x%pof:bcd=%==x%pof% goto remloop
endlocal
(Variable POF has already been declared in another file)
So I tried using echo command to make another batch file
echo #setlocal enableextensions enabledelayedexpansion > file2.bat
echo #echo off > file2.bat
echo :remloop >> file2.bat
echo set recfilepath=%pof% >> file2.bat
echo set filename=%pof% >> file2.bat
echo SET filename=%_filename:*\=% >> file2.bat
echo if not x%pof:bcd=%==x%pof% goto remloop >> file2.bat
echo endlocal >> file2.bat
but the result was unexpected, the results are:
#echo off
:remloop
set recfilepath=C:\Users\Palm2570Playz\Desktop\djfbjfbfbj.txt
set filename=C:\Users\Palm2570Playz\Desktop\djfbjfbfbj.txt
SET filename=*\=
if not xC:\Users\Palm2570Playz\Desktop\djfbjfbfbj.txt==xC:\Users\Palm2570Playz\Desktop\djfbjfbfbj.txt goto remloop
endlocal
The "SET filename=*= " lines was unexpected so the code cannot run correctly
Is there any command to fix this?
To show you what your question asks, without providing any fixes for any of the content of `file2.bat`:
#( Echo #setlocal enableextensions enabledelayedexpansion
Echo #echo off
Echo :remloop
Echo set recfilepath=%%pof%%
Echo set filename=%%pof%%
Echo SET filename=%%_filename:*\=%%
Echo if not x%%pof:bcd=%%==x%%pof%% goto remloop
Echo endlocal)>"file2.bat"
If you don't need escaping anything?!
The best and most efficient way to escape is to use no escape, use only the bat file itself to decode the second bat file with the content in Base64 itself:
Where it is possible to use CertUtil to decode File2.bat, taking advantage that it already comes with Windows.
Your code bat:
#(%__APPDIR__%CertUtil.exe -f -decode "%~f0" "%~dp0File2.bat" >nul & goto :EOF)
<-----BEGIN -----QGVjaG8gb2ZmICYmIHNldGxvY2FsIGVuYWJsZWRlbGF5ZWRleHBhbnNpb24NCj
psb29wDQpzZXQgInJlY2ZpbGVwYXRoPSVwb2YlIiAmJiBjbWQuZXhlIC92Om9uIC9jICJzZXQgImZpb
GVuYW1lPSFyZWNmaWxlcGF0aDoqXD0hIiAiDQplY2hvOyJ4IXBvZjpiY2Q9ISJ8ZmluZC9pIC92ICJ4
IXBvZiEiID5udWwgJiYgZ290byA6bG9vcCB8fCBlbmRsb2NhbCAmIGdvdG86RU9G-----END ----->
The File2.bat content result:
#echo off && setlocal enabledelayedexpansion
:loop
set "recfilepath=%pof%" && cmd.exe /v:on /c "set "filename=!recfilepath:*\=!" "
echo;"x!pof:bcd=!"|find/i /v "x!pof!" >nul && goto :loop || endlocal & goto:EOF
This code above has some suggestions, liable to (critical/not), so follow code use the same method using your current code without modifications:
#(%__APPDIR__%CertUtil.exe -f -decode "%~f0" "%~dp0File2.bat" >nul & goto :EOF)
<-----BEGIN CERTIFICATE----- QHNldGxvY2FsIGVuYWJsZWV4dGVuc2lvbnMgZW5hYmxlZGVsYX
llZGV4cGFuc2lvbg0KQGVjaG8gb2ZmDQo6cmVtbG9vcA0Kc2V0IHJlY2ZpbGVwYXRoPSVwb2YlDQpzZ
XQgZmlsZW5hbWU9JXBvZiUNClNFVCBmaWxlbmFtZT0lX2ZpbGVuYW1lOipcPSUNCmlmIG5vdCB4JXBv
ZjpiY2Q9JT09eCVwb2YlIGdvdG8gcmVtbG9vcA0KZW5kbG9jYWw= -----END CERTIFICATE----->
The File2.bat content result:
#setlocal enableextensions enabledelayedexpansion
#echo off
:remloop
set recfilepath=%pof%
set filename=%pof%
SET filename=%_filename:*\=%
if not x%pof:bcd=%==x%pof% goto remloop
endlocal
Some further reading:
[√] CertUtil -Decode
[√] CertUtil -Encode / -Decode
[√] CertUtil (Microsoft Documentation)
You can use FINDSTR / a FOR loop (eol&skip) / MORE on the batch file itself, and redirect it to file2.bat. That way no parsing is involved.
I made no edits/improvements as it's out of scope of the question.
#echo off
%__APPDIR__%findstr.exe /R "^;" "%~f0" >file2.bat
exit /b
<--- FILE2.BAT --->
;#setlocal enableextensions enabledelayedexpansion
;#echo off
;:remloop
;set recfilepath=%pof%
;set filename=%pof%
;SET filename=%_filename:*\=%
;if not x%pof:bcd=%==x%pof% goto remloop
;endlocal
Executing batch file gives ECHO is off.
The batch file code is present below:
#echo off
setlocal EnableDelayedExpansion
SET a = Hello
SET b = World
SET /A d = 50
SET c = %a% and %b% %d%
echo %c%
endlocal
pause
As MC ND wrote, you have to get rid of spaces before and behind the equality sign. It should be SET a=Hello and not SET a = Hello and so on. This code works as expected:
#echo off
setlocal EnableDelayedExpansion
SET a=Hello
SET b=World
SET /A d=50
SET c=%a% and %b% %d%
echo %c%
endlocal
pause
Further, the lines setlocal EnableDelayedExpansion and endlocal are useless in your code as you never use the delayed expansion (e.g. !a! instead of %a%). Your code is still correct as there is doesn't need delayed expansion.
If you have further questions, please post them as such. Don't expand this post on other questions.
Here are your two, altered codes:
#ECHO OFF
SETLOCAL ENABLEDELAYEDEXPANSION
SET "a=Hello"
SET "b=World"
SET/A "d=50"
SET "c=%a% and %b% %d%"
ECHO %c%
ENDLOCAL
PAUSE
Please check and try them, then read up on the individual commands to learn from your errors.
#ECHO OFF
SETLOCAL ENABLEDELAYEDEXPANSION
SET/P "pathToJava= **Provide your Response: "
IF /I "%pathToJava%"=="Y" ECHO found
ENDLOCAL
PAUSE
I am trying to double my delayed expansion if that makes any sense. Here is what I want.
set var1=hello
set var2=var1
set var3=var2
echo %!%var3%!%
and then have hello be displayed. This is not my actual code but an example of how I need it to work.
even possible without delayed expansion (although even uglier than rojo's answer) Just a matter of the number of "layers" of parsing and correct escaping the %:
#echo off
set var1=hello
set var2=var1
set var3=var2
call call echo %%%%%%%var3%%%%%%%
Another one without call (faster):
#echo off
setlocal enabledelayedexpansion
set "var1=hello"
set "var2=var1"
set "var3=var2"
for %%v in (!%var3%!) do echo !%%v!
EDIT: Reply to rojo's challenge
Your code have an error in the creation of the variables; all variables contain the string: "var!X!" and the final result is "var!X!X". Below is your code with the variables creation part fixed:
#echo off
setlocal EnableDelayedExpansion
set "var1=hello"
for /L %%I in (2,1,1000) do (
set /a X = %%I - 1
set "var%%I=var!x!"
)
call :follow var1000
goto :EOF
:follow <varname>
setlocal enabledelayedexpansion
set "var=!%~1!"
:follow_loop
if defined !%var%! (
set "var=!%var%!" & goto follow_loop
) else (
echo !%var%!
)
This program correctly show "hello" at end; it takes about 2.51 seconds when run in my computer.
The method is pretty short, so there is not too much chance to improve it; the obvious modification is to change the goto loop by a for (while) one. Here it is:
#echo off
setlocal EnableDelayedExpansion
set "var1=hello"
for /L %%I in (2,1,1000) do (
set /a X = %%I - 1
set "var%%I=var!x!"
)
call :follow var1000
goto :EOF
:follow <varname>
set "var=%~1"
cmd /V:ON /C for /L %%? in () do #for %%v in (^^!var^^!) do #if defined %%v (set "var=^!%%v^!") else echo %%v ^& exit
This code takes about 1.22 seconds to run, that is, just the 48.6% of your method (2 times faster) ;)
You could add a call and surround your first delayed expansion with double percents like this.
#echo off
setlocal enabledelayedexpansion
set "var1=hello"
set "var2=var1"
set "var3=var2"
call echo %%!%var3%!%%
Seems horribly convoluted to me, though. I'd probably rewrite the script to make such trickery not needed if I were me.
Edit: Since there are so many solutions being added here, I'll propose another one. Here's a subroutine that will follow the line of variables from beginning to end, even if it's 1000 levels deep. Just as an academic exercise.
#echo off
setlocal
set "var1=hello"
for /L %%I in (2,1,1000) do (
set /a X = %%I - 1
setlocal enabledelayedexpansion
for %%x in (!X!) do endlocal & set "var%%I=var%%x"
)
call :follow var1000
goto :EOF
:follow <varname>
setlocal enabledelayedexpansion
set "var=!%~1!"
:follow_loop
if defined !%var%! (
set "var=!%var%!" & goto follow_loop
) else (
echo !%var%!
)
And here's another using a batch + JScript hybrid (because the JScript while loop is faster than a batch goto loop).
#if (#CodeSection == #Batch) #then
#echo off
setlocal
set "var1=hello"
for /L %%I in (2,1,1000) do (
set /a X = %%I - 1
setlocal enabledelayedexpansion
for %%x in (!X!) do endlocal & set "var%%I=var%%x"
)
cscript /nologo /e:JScript "%~f0" "var1000"
goto :EOF
#end // end batch / begin JScript hybrid chimera
var env = WSH.CreateObject('Wscript.Shell').Environment('Process'),
itm = WSH.Arguments(0);
while (env(itm)) itm = env(itm);
WSH.Echo(itm);
Your move, Aacini.
Okay so I basically need a code that will do something like this:
#echo off
start:
echo Type what you want me to remember!
set /p newline=
<add %newline% to Line 4 in safe.txt>
goto start
I don't want to replace the existing Line 4 in safe.txt.
If you want to append the input to the end of the file:
#echo off
start:
echo Type what you want me to remember!
set /p newline=
Echo %newline% >> safe.txt
goto start
If you want to add the line after the 4th line:
#echo off
start:
echo Type what you want me to remember!
set /p newline=
setlocal enabledelayedexpansion
set count=0
ren safe.txt safe.tmp
for /f "delims=" %%a in (safe.tmp) do (
set /a count+=1
Echo %%a >> safe.txt
if !count!==4 Echo !newline! >> safe.txt
)
del safe.tmp
goto start
And one of these codes should help you with your problem.
Mona