Use of "set /p myvariable=<myfile.txt" in batch file - batch-file

I'm trying to set the contents of a text file (it contains a single line of text) to a variable. To do this, I'm utilizing "set /p myvariable=
SetLocal EnableExtensions EnableDelayedExpansion
Set RegExist=No
Set RegUnins=HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall
Reg Query "%RegUnins%\{########-####-####-####-############}"
If "%errorlevel%"=="0" Set RegExist=Yes
If "%regexist%"=="Yes" (
Reg Query "%RegUnins%\{########-####-####-####-############}" /V "DisplayName" >"%temp%\appnam1.txt"
Find /I "This is the value for 'DisplayName'" "%temp%\appnam1.txt" >"%temp%\appnam2.txt"
More +2 "%temp%\appnam2.txt" >"%temp%\appnam3.txt"
Set /P _appnam=<"%temp%\appnam3.txt"
Set appnam=%_appnam:~24,53%
If "%appnam%"=="This is the value for 'DisplayName'" (
Echo - Current version installed: Performing reinstall...
Start "Reinstall" /B /High /Wait "\\server\installs\reinstall.exe"
) Else (
Echo - Previous version installed: Performing upgrade...
Start "Upgrade" /B /High /Wait "\\server\installs\upgrade.exe"
)
) Else (
Echo - Existing version not found: Performing new install...
Start "Install" /B /High /Wait "\\server\installs\new.install.exe"
)
However, even though the "%temp%\appnam3.txt" file contains the correct text, when I check the variables "%_appnam%" and "%appnam%" at those points in the code, they are blank. Therefore, if the machine does have the initial registry entry, it will always perform the upgrade process instead of the reinstall process. Any suggestions? I don't understand why the "set /p" line isn't working. Thanks in advance.

PLease use delayed expansion.
I tried to reproduce your case below. It seems the variable are set delayed, If you'll try to run you script several times, the values will be set.
#echo off
setlocal enableDelayedExpansion
set regexist=Yes
If "%regexist%"=="Yes" (
Set /P _appnam=<"C:\result.csv"
echo !_appnam!
Set appnam=!_appnam:~24,53!
echo !appnam!
)

Related

Am I the only one who have this problem: While running something like .bat, the "X:\..\..path" often becomes ""X:\..\path and producing errors?

While running something like .bat, the "X:\..\..path" often becomes ""X:\..\path and producing errors. For example, I was installing apktool, then it just appeared this:
'""C:\Program' is not recognized as an internal or external command,
operable program or batch file.
I then copy the command and put one of the double quote to the end, which is like this: "C:\Program"
And everything just went smoothly, installation was successful. Then I tried to decode an apk, and the exactly same problem occurred: '""C:\Program' is not recognized as an internal or external command, operable program or batch file. This time I have no idea how to fix it, it's not like the .bat now, I cannot get the #echo on and copy the last command and edit it. So I am here to ask: If I am the only one who met this? Any way to fix this? Thank you.
My command:
apktool d test.apk
Image of running a decode command : 1
apktool.bat content:
#echo off
setlocal
set BASENAME=apktool_
chcp 65001 2>nul >nul
set java_exe=java.exe
if defined JAVA_HOME (
set java_exe="%JAVA_HOME%\bin\java.exe"
)
rem Find the highest version .jar available in the same directory as the script
setlocal EnableDelayedExpansion
pushd "%~dp0"
if exist apktool.jar (
set BASENAME=apktool
goto skipversioned
)
set max=0
for /f "tokens=1* delims=-_.0" %%A in ('dir /b /a-d %BASENAME%*.jar') do if %%~B gtr !max! set max=%%~nB
:skipversioned
popd
setlocal DisableDelayedExpansion
rem Find out if the commandline is a parameterless .jar or directory, for fast unpack/repack
if "%~1"=="" goto load
if not "%~2"=="" goto load
set ATTR=%~a1
if "%ATTR:~0,1%"=="d" (
rem Directory, rebuild
set fastCommand=b
)
if "%ATTR:~0,1%"=="-" if "%~x1"==".apk" (
rem APK file, unpack
set fastCommand=d
)
:load
"%java_exe%" -jar -Duser.language=en -Dfile.encoding=UTF8 "%~dp0%BASENAME%%max%.jar" %fastCommand% %*
rem Pause when ran non interactively
for /f "tokens=2" %%# in ("%cmdcmdline%") do if /i "%%#" equ "/c" pause
Use set "var=value" for setting string values - this avoids problems caused by trailing spaces. Don't assign a terminal \, Space or " - build pathnames from the elements - counterintuitively, it is likely to make the process easier. If the syntax set var="value" is used, then the quotes become part of the value assigned.
set java_exe="%JAVA_HOME%\bin\java.exe"
Should be
set "java_exe=%JAVA_HOME%\bin\java.exe"
(apply this principle throughout your code)
Then, if you require " anywhere, insert it where it's needed - don't try to include it as part of a variable's value.
This should clean up at least some of your problems.

Batch script to install fonts not setting fext variable

This is really driving me insane. The following is part of an 8,000 line batch script. This section of code is at line 3380 approx and not working for me, as the fext variable is not getting set.
Apologies for the long post.
Rem *********************************************************************************************************************************************
Rem * Copy and register fonts *
Rem *********************************************************************************************************************************************
:FONTS
IF EXIST "%SrcPath%\Fonts\" (
Echo Installing Custom Fonts
Echo. >>C:\%USERDOMAIN%.PostInstall.Log 2>&1
Echo %time% === Installing Custom Fonts === >>C:\%USERDOMAIN%.PostInstall.Log 2>&1
FOR %%a in ("%SrcPath%\Fonts\*.?tf") do call :Installfont "%%~nxa"
Echo %time% Fonts will not be available until the system has been restarted >>C:\%USERDOMAIN%.PostInstall.Log 2>&1
Echo %time% === Finished Installing Custom Fonts === >>C:\%USERDOMAIN%.PostInstall.Log 2>&1
)
Goto SYMLNK
:Installfont
Set font=
Set fext=
set ftype=
Set "font=%~1"
IF EXIST "%LOCALAPPDATA%\Microsoft\Windows\Fonts\%font%" echo Font "%font%" already installed. >>C:\%USERDOMAIN%.PostInstall.Log 2>&1
IF EXIST "%WINDIR%\Fonts\%font%" echo Font "%font%" already installed. >>C:\%USERDOMAIN%.PostInstall.Log 2>&1
IF NOT EXIST "%LOCALAPPDATA%\Microsoft\Windows\Fonts\%font%" IF NOT EXIST "%WINDIR%\Fonts\%font%" (
Set "fext=%font:~-3%"
IF "%fext%"=="" Echo null extension for font "%font%"
IF /i "%fext%"=="ttf" Set ftype=Truetype
IF /i "%fext%"=="otf" Set ftype=Opentype
Echo %time% Installing "%font%" to "%LOCALAPPDATA%\Microsoft\Windows\Fonts" >>C:\%USERDOMAIN%.PostInstall.Log 2>&1
Echo %time% Processing font "%font%" Extension: %fext% Type: "(%ftype%)" >>C:\%USERDOMAIN%.PostInstall.Log 2>&1
echo "%font%" "%fext%" "%ftype%"
Pause
copy "%SrcPath%\Fonts\%font%" "%LOCALAPPDATA%\Microsoft\Windows\Fonts" /y >>C:\%USERDOMAIN%.PostInstall.Log 2>&1
REG ADD "HKEY_CURRENT_USER\Software\Microsoft\Windows NT\CurrentVersion\Fonts" /v "%font% (%ftype%)" /d "%LOCALAPPDATA%\Microsoft\Windows\Fonts\%font%" /t REG_SZ /f >>C:\%USERDOMAIN%.PostInstall.Log 2>&1
)
exit /b
:SYMLNK
Echo Finished
Endlocal
The srcpath and src variables are set at the top of the script...
#Echo Off
powershell -command "&{$w=(get-host).ui.rawui;$w.buffersize=#{width=132;height=2500};$w.windowsize=#{width=128;height=70};}"
setlocal
Rem What drive are we on? Save the source drive
SET SRC=%CD:~0,2%
Rem Shorten the source path
set SrcPath=%SRC%\PostInstall\%USERNAME%
If I don't clear the variables at the start of the subroutine the effect is cumulative. First time neither fext nor ftype are set. 2nd time fext is set, but ftype is not, third time both are set, so I added the sets at the start of the subroutine to clear them.
What I end up with is the registry entry name (eg). airstrike.ttf (). The value data is correct. What should be in the brackets is either truetype or opentype.
The copy command doesn't work at all. Just says 0 files copied.
Some fonts have spaces in the name such as Spirit & Ghost.ttf, which is why I've quoted everything.
I must admit I don't really have a good grasp of delayedexpansion but attempting to use it totally bricks the script.
The entire script contains a considerable amount of personal info, so sharing it is problematic. But if it's definitely needed I can go through and mask out the personal stuff, but then it's not an accurate copy of the real script.
You will see that the script writes to a log file. This is what's in the log file...
16:11:41.91 === Installing Custom Fonts ===
16:11:41.94 Installing "airstrike.ttf" to "C:\Users\Phillip\AppData\Local\Microsoft\Windows\Fonts"
16:11:41.94 Processing font "airstrike.ttf" Extension: Type: "()"
0 file(s) copied.
The operation completed successfully.
Would greatly appreciate some help with why this doesn't work.
thank you.
IF EXIST "%LOCALAPPDATA%\Microsoft\Windows\Fonts\%font%" exit /b
IF EXIST "%WINDIR%\Fonts\%font%" exit /b
Set "fext=%font:~-3%"
IF "%fext%"=="" Echo null extension for font "%font%"
IF /i "%fext%"=="ttf" Set ftype=Truetype
IF /i "%fext%"=="otf" Set ftype=Opentype
Echo %time% Installing "%font%" to "%LOCALAPPDATA%\Microsoft\Windows\Fonts" >>C:\%USERDOMAIN%.PostInstall.Log 2>&1
Echo %time% Processing font "%font%" Extension: %fext% Type: "(%ftype%)" >>C:\%USERDOMAIN%.PostInstall.Log 2>&1
echo "%font%" "%fext%" "%ftype%"
Pause
copy "%SrcPath%\Fonts\%font%" "%LOCALAPPDATA%\Microsoft\Windows\Fonts" /y >>C:\%USERDOMAIN%.PostInstall.Log 2>&1
REG ADD "HKEY_CURRENT_USER\Software\Microsoft\Windows NT\CurrentVersion\Fonts" /v "%font% (%ftype%)" /d "%LOCALAPPDATA%\Microsoft\Windows\Fonts\%font%" /t REG_SZ /f >>C:\%USERDOMAIN%.PostInstall.Log 2>&1
exit /b
The issue is that within a block statement (a parenthesised series of statements), the entire block is parsed and then executed. Any %var% within the block will be replaced by that variable's value at the time the block is parsed - before the block is executed - the same thing applies to a FOR ... DO (block).
Hence, IF (something) else (somethingelse) will be executed using the values of %variables% at the time the IF is encountered.
Two common ways to overcome this are 1) to use setlocal enabledelayedexpansion (outside of the block or more usually after the initial #echo off) and use !var! in place of %var% to access the changed value of var or 2) to call a subroutine to perform further processing using the changed values.
Note therefore the use of CALL ECHO %%var%% which displays the changed value of var. CALL ECHO %%errorlevel%% displays, but sadly then RESETS errorlevel.
In this case, simply exit /b if the block in question is NOT to be executed, then execute the individual statements of the block, so they will be processed as you expect, avoiding the characteristic of blocks - which is a commonly-encountered phenomenon with thousands of mentions in SO solutions.

Batch script: Convert path to linux format using wslpath

I was trying to convert current working directory of a .bat script into linux format by using wsl wslpath. To show you it works on CMD:
However, when I put it in a .bat file, and changed %cd% to %~dp0, the path is empty:
test.bat contains:
FOR /F %%i IN ('wsl wslpath -a %~dp0') DO set lp=%%i
echo %lp%
Any idea why?
Try this:
echo "%cd%" -- "%~dp0"
%cd% returns the path without ending backslash. So you can add a second variable that clears it.
set "scriptDir=%~dp0"
set "scriptDir=%scriptDir:~0,-1%"
UPDATE (with string substitution only - use the toLinuxPath subroutine)
#echo off
call ::toLinuxPath "%userprofile%\AppData\Local\Temp" tempF
echo %tempF%
exit /b 0
:toLinuxPath [returnVariable - the result will be stored in it; If omitted will be only echoed]
setlocal
set "_path=%~p1"
set "name=%~nx1"
set "drive=%~d1"
set "rtrn=%~2"
set "result=/mnt/%drive:~0,1%%_path:\=/%%name%"
endlocal & (
if "%~2" neq "" (
set "%rtrn%=%result%"
) else (
echo %result%
)
)

Need a little tip on batch files

I'm very new to coding and iI'm having a problem that is probably trivial, but is making me pull out my hair.
I'm using a batch script to automate mounting a VHD, executing a file inside and then pause until the user presses any key, which makes the VHD get unmounted and the script exits.
This is the main batch file:
#echo off
set fileVHD=Gord
CD /D "%~dp0"
powershell -command "Start-Process mount.cmd '%~dp0%fileVHD%.vhd' -Verb runas"
timeout /t 1
for /f %%D in ('wmic volume get DriveLetter^, Label ^| find "%fileVHD%"') do set usb=%%D
CD /D %usb%
index.html
echo "!!!!!!!!!!!!!!!!!!!!Press any key to fully close this program.!!!!!!!!!!!!!!!!!!!!!!!!!"
pause
CD /D "%~dp0"
powershell -command "Start-Process unmount.cmd '%~dp0%fileVHD%.vhd' -Verb runas"
exit
This is the mount script (Not made by me):
#echo off
setlocal enabledelayedexpansion
if "%~1"=="" (
echo Usage: %~nx0 [vhd] [letter]
exit /b 1
)
set "vhdPath=%~dpnx1"
set "driveLetter=%2"
if "!driveLetter!"=="" (
echo Mounting "!vhdPath!"
) else (
echo Mounting "!vhdPath!" to "!driveLetter!":
)
REM
REM create diskpart script
REM
set "diskPartScript=%~nx0.diskpart"
echo select vdisk file="!vhdPath!">"!diskPartScript!"
echo attach vdisk>>"!diskPartScript!"
REM assign the drive letter if requested
if not "!driveLetter!"=="" (
echo select partition 1 >>"!diskPartScript!"
echo assign letter="!driveLetter!">>"!diskPartScript!"
)
REM Show script
echo.
echo Running diskpart script:
type "!diskPartScript!"
REM
REM diskpart
REM
diskpart /s "!diskPartScript!"
del /q "!diskPartScript!"
echo Done!
endlocal
When all the files are located in a system path that contains no spaces, everything works fine. But it breaks where there are spaces.
That means that somewhere in the code a path is badly defined by the lack of quotes, probably in the mount script. The trouble is that i don't fully grasp the mount script when it starts using all the "%~...." variable path names.
I had to mix in some powershell commands because for some reason the script wouldn't work unless executed as Administrator.
If someone could give some insight to a newbie, it would be greatly appreciated.
You need end quotes around your parameters when you change directory, i.e.
CD /D "%~dp0"
You can also see all of the %~ options by running 'help for' in a console window. In those scripts it's getting the path or filename from a variable.
Discovered the root of my problem.
The path from script 1 was not being passed faithfully to script 2, even using using quotes or multiquotes.
Thanks for all the input guys!

Windows script doesn't work when user types in a whitespace

I'm writing a Windows script in batch. I have a problem with whitespaces in variables. When the user types in a space, the script breaks.
Here's the part of my script:
:package
SET /P packageName="Set package name:"
IF [%packageName%] EQU [] (
ECHO Empty package name.
goto package
) ELSE (
set "packageName=%packageName: =%"
echo %packageName%
pause
)
This schould work:
#ECHO OFF
SETLOCAL ENABLEDELAYEDEXPANSION
:package
SET /P packageName="Set package name:"
IF "%packageName%"=="" (
ECHO Empty package name.
goto package
) ELSE (
set packageName=%packageName: =%
echo !packageName!
pause
)
There are two modifications to your script:
[%packageName%] EQU [] was replaced with "%packageName%"==""
I've added SETLOCAL ENABLEDELAYEDEXPANSION and changes echo %packageName% with echo !packageName!
The second point is because you are changing the value of a variable inside an IF-construction. As the interpreter doesn't know what the new value will be at "compile" time, you have to evaluate the variable at run time. That's why you need SETLOCAL ENABLEDELAYEDEXPANSION and !...! instead of %...%. This forces the expansion at run time.
I suggest to use this code:
#echo off
setlocal EnableDelayedExpansion
:package
rem Predefine variable packageName with a single double quote as value.
rem This value is kept if the user just hits RETURN or ENTER on prompt.
rem The single double quote is removed 2 command lines below if the user
rem does not enter anything or it is overwritten by user entered string.
set "packageName=""
set /P "packageName=Set package name: "
rem Remove double quotes from entered string. This is necessary to
rem avoid a syntax error on next command line with the IF condition.
set "packageName=!packageName:"=!"
if "!packageName!" == "" (
echo Empty package name.
goto package
) else (
set "packageName=%packageName: =%"
echo Package name with spaces: %packageName%
echo Package name without spaces: !packageName!
pause
)
endlocal
For understanding the used commands and how they work, open a command prompt window, execute there the following commands, and read entirely all help pages displayed for each command very carefully.
if /?
set /?
setlocal /?
Especially the help pages output on execution of if /? should be read carefully and completely as this helps explains delayed expansion as it must be used here on examples.
See also the output of the 2 echo lines in ELSE branch in code above to understand what is the difference between referencing a variable with percent signs or with exclamation marks in blocks defined with ( ... ).
Your script is almost correct except for "variable search/replace" which its position is to be before "IF"
#echo off
:package
set /p packagename="set package name:"
set packagename=%packagename: =%
if [%packagename%] equ [] (
echo empty package name &goto package
) else (echo %packagename%)

Resources