set /p is not working as expected - batch-file

I am trying to create the interactive bat file which ask for the folder details it is able to take the userchoice but after that it is not able to set the folder path given by useri.e. it takes the path till Desktop only.Below is my code for the same:
#echo off
set /p UserInfo= "Do you have abc software(y/n)? "
echo %UserInfo% // here it is working as expected
IF %UserInfo%==y (
echo "Reply is true-----"
set /p Path= "Please enter path for abc directory? "
echo %Path% //but here it takes the path till the desktop only(C:\user\username\Desktop)
CD %Path%
dir
set /p Path1= "Please enter path1 directory path provided in package? "
echo %Path1% //but here it takes the path till the desktop only(C:\user\username\Desktop)
CD %Path1%
)
IF %UserInfo%==n (
echo "Reply is False**************"
)
pause
How to read the folder directive?

Hmm.. Please use the search bar as user Magoo, LotPings said.
Also, Stephan & Squashman mentioned, do not set a variable with the name path because there is a internal variable named path. If you rename it, other programs may not work properly.
What's DelayedExpansion?
When batch files are run, cmd process them line by line. The entire if statement get processed at once. That's why the variable are un-set.
Since we want cmd to process those variable at run-time, we will need to tell it to do so, by adding setlocal enableDelayedExpansion. This enables run-time variable expansion. To disable, just change enable to disable.
You may want to add it like so:
#echo off
setlocal enableDelayedExpansion
rem your code follows...
How To Make Variable Get Processed Run-Time?
Simply change %var% to !var!.
Please note that for loop metavariable %%n cannot be changed to !!n, since itself already implicated a delayed expansion.
Command-line arguments %n cannot be changed to !n. You may want to do this instead:
if "%var%"=="abc" (
set variable=%1
echo !variable!
)
SET /P Code Injection Cause Security Issue?!
If the input of %Userinput% is a==a format D:\ && echo, cmd sees:
if a==a
do format D:\
do echo ==y (
Which... formats your D drive. Adding quotes like if "%var%"=="abc" won't help since user can just escape the quote and execute the commands.
See here for more info.
SET /P Alternatives
You may want to consider CHOICE for single letter choice. It's command syntax is like so:
choice /c choices /n /cs /t timeout /d default_choice /m prompt
/n hides the list of options, letting /m to display it's own prompt
/cs == case-insensitive.
PATH Variable
Again mentioned above, PATH is a internal variable used by Windows and other programs. Mis-setting it may cause some Windows functions or programs to stop functioning properly.
Instead, use another variable name like programPath.

Related

How to add spaces while renaming files in batch [duplicate]

This question already has an answer here:
Variables are not behaving as expected
(1 answer)
Closed 12 months ago.
So recently, I have tried to make myself a batch script to rename files by replacing a certain string by another. It is sucessful, until you add spaces. This is what my code currently looks like :
#echo off
:0
cls
set /p "str=String to replace : "
set /p "rsw=Replace string with : "
set /p "infile=In file : "
for %%a in ("%infile%") do (
cd %%~dpa
set "fn1=%%~nxa"
call set fn2=%%fn1:%str%=%rsw%%%
ren "%%~dpa%fn1%" "%%~dpa%fn2%"
)
echo "%str%" "%rsw%"
echo "%fn1%" "%fn2%"
pause
goto 0
Solved :
I have modified my code to look like this and now it works :
#echo off
set /p "str=String to replace : "
set /p "rsw=Replace string with : "
title Replace "%str%" with "%rsw%"
:0
cls
set /p "infile=In file : "
for %%a in ("%infile%") do (
set "wkdir=%%~dpa"
set "fn1=%%~nxa"
)
call set "fn2=%%fn1:%str%=%rsw%%%"
cd %wkdir%
ren "%fn1%" "%fn2%"
pause
goto 0
I even tried using setlocal EnableDelayedExpansion but it didn't help so I simply took the renaming process out of the for command.
The only problem that I now run into is renaming a file containing spaces in it's name.
First issue: We normally assume that a batch is being run from the prompt. You appear to be using the "point, click and giggle" method (clicking a "shortcut")
Initially, a cmd instance contains no user-set variables. It is standard practice to include
setlocal
immediately after the #echo off line to establish a "local" environment. Changes made to that local environment (like establishing str etc) are removed when the batch ends.
Since you have not used this setlocal statement, any variables you have established in a run remain set for subsequent runs (if you are running from the prompt).
Next issue : the ever-faithful "delayed expansion" characteristic (see Stephan's DELAYEDEXPANSION link: https://stackoverflow.com/a/30284028/2128947
).
You would understand from there that in your code, ren "%%~dpa%fn1%" "%%~dpa%fn2%" will be resolved using the values of fn1 and fn2 as they stood when the for was parsed, not the modified values that were set within the for block.
It could be that you are being deceived by the fact that fn1 and fn2 would retain their values when the loop back to :0 is executed, or even between invocations if you are running from the prompt where the modified values are not deleted in consequence of the absence of a setlocal.
Third issue: a ren statement may have a path specifier on its first argument, but must NOT have a path specifier on the second - only a name[.extension] is allowed.

Using CMDER, issue with setting PATH

I'm trying to use CMDER for a development environment that I've setup.
Basically I've created a .bat file that calls:
#ECHO OFF
start Z:\_DEV\OS_WINDOWS\9_MISC_TOOLS\CMDER\Cmder.exe
Then I've placed the file startdev.bat in:
%CMDER_HOME%\config\profile.d
So everything seems to work just fine, but when the startdev.bat finishes, issuing an:
echo %PATH%
returns:
Z:\_DEV\OS_WINDOWS\1_COMPILER\JDK\ORACLE\1.8.0_181\bin;Z:\_DEV\OS_CYGWIN\bin;Z:\_DEV\OS_WINDOWS\9_MISC_TOOLS\CLutils;Z:\_DEV\OS_WINDOWS\9_MISC_TOOLS\PUTTY;Z:\_DEV\OS_WINDOWS\6_VERSION_CONTROL\PortableGit\bin;C:\WINDOWS;C:\WINDOWS\SysWOW64;C:\WINDOWS\System32
...any idea what's happening?
I would either expect CMDER to override PATH with the value from its own settings, or use my full path, which before the startdev.bat ends shows the value of:
PATH=Z:\_DEV\OS_WINDOWS\9_MISC_TOOLS\CMDER\vendor\conemu-maximus5;Z:\_DEV\OS_WINDOWS\9_MISC_TOOLS\CMDER\vendor\conemu-maximus5\ConEmu;Z:\_DEV\OS_WINDOWS\9_MISC_TOOLS\CMDER\vendor\conemu-maximus5\ConEmu\Scripts;Z:\_DEV\OS_ALL\JVM\3_BUILD_TOOLS\GRADLE\5.4\bin;Z:\_DEV\OS_ALL\JVM\3_BUILD_TOOLS\MAVEN\3.5.4\bin;Z:\_DEV\OS_ALL\JVM\3_BUILD_TOOLS\ANT\1.10.5\bin;Z:\_DEV\OS_WINDOWS\3_BUILD_TOOLS\NODE\LTS\10.15.3;Z:\_DEV\OS_WINDOWS\3_BUILD_TOOLS\NODE\LTS\10.15.3\node_modules;Z:\_DEV\OS_WINDOWS\1_COMPILER\GO\1.12.4\bin;Z:\_DEV\OS_WINDOWS\1_COMPILER\PYTHON\32bit\2.7.13;Z:\_DEV\OS_WINDOWS\1_COMPILER\PYTHON\32bit\2.7.13\scripts;Z:\_DEV\OS_WINDOWS\1_COMPILER\ANDROID\android-sdk-windows\platform-tools;Z:\_DEV\OS_WINDOWS\1_COMPILER\JDK\ORACLE\1.8.0_181\bin;Z:\_DEV\OS_CYGWIN\bin;Z:\_DEV\OS_WINDOWS\9_MISC_TOOLS\CLutils;Z:\_DEV\OS_WINDOWS\9_MISC_TOOLS\PUTTY;Z:\_DEV\OS_WINDOWS\6_VERSION_CONTROL\PortableGit\bin;C:\WINDOWS;C:\WINDOWS\SysWOW64;C:\WINDOWS\System32
..but the fact that it only seems to be keeping the value as defined about halfway through the batch job is strange.
Any ideas?
First I recommend opening a command prompt window and run setlocal /? and endlocal /? to get displayed the help/documentation for those two commands. Very important to know is that every setlocal without a corresponding endlocal results in an implicit execution of endlocal by cmd.exe before exiting processing of a batch file or a subroutine called with command CALL.
Next I suggest reading this answer for even more details about the commands SETLOCAL and ENDLOCAL and what happens on using them.
I suggest like michael_heath to change this code block:
setLocal EnableDelayedExpansion
set CLASSPATH=.
for /R %JRE_HOME%\lib %%a in (*.jar) do (
set CLASSPATH=!CLASSPATH!;%%a
)
set CLASSPATH=!CLASSPATH!
Better would be:
setLocal EnableExtensions EnableDelayedExpansion
set CLASSPATH=.
for /R "%JRE_HOME%\lib" %%a in (*.jar) do set "CLASSPATH=!CLASSPATH!;%%a"
endlocal & set "CLASSPATH=%CLASSPATH%"
Now the local environment is ended with passing the environment variable CLASSPATH from local environment, on which it was defined, to the restored previous environment because of cmd.exe expands %CLASSPATH% to current value of the environment variable CLASSPATH in current local environment before executing the command endlocal which restores the previous environment.
Wrong in your batch file is also set WINDIR=%SystemRoot%;%SystemRoot% which should be set "WINDIR=%SystemRoot%".
I recommend further reading Why is no string output with 'echo %var%' after using 'set var = text' on command line? It explains why the syntax set "variable=string value" is recommended nowadays. Many of the environment variable definitions use directly or indirectly %UserProfile% which means depending on whatever the user currently running the batch file has entered as user name on creation of the user account. I have seen users entering their name containing a space and non ASCII characters. And I have seen users creating an account with a user name containing character & like Company GmbH & Co. An ampersand outside a double quoted argument string is interpreted as AND operator and cmd.exe tries to execute after set also the remaining string after & as command line on using something like set USERHOME=%DEVHOME%\%USERNAME% instead of set "USERHOME=%DEVHOME%\%USERNAME%". Well, startdev.bat redefines nearly all predefined Windows Environment Variables including USERNAME and USERPROFILE and so is written safe for most environment variable definitions.
This code block is also not optimal:
FOR /F "usebackq" %%i IN (`hostname`) DO SET HOSTNAME=%%i
echo Running on hostname: %HOSTNAME%
The host name respectively computer name could contain also a space or characters critical for command line or start with a semicolon for some unknown reason. So better would be:
FOR /F delims^=^ eol^= %%i IN ('hostname') DO SET "HOSTNAME=%%i"
setlocal EnableDelayedExpansion & echo Running on host name: !HOSTNAME!& endlocal
Whereby there is the environment variable COMPUTERNAME predefined by Windows making it possible to use just following command line:
setlocal EnableDelayedExpansion & echo Running on host name: !ComputerName!& endlocal
An ECHO command line containing an immediately expanded environment variable reference on which it is unknown if its value contains &|<> is always a problem because of the environment variable reference is expanded before further processing of the command line by cmd.exe as described at How does the Windows Command Interpreter (CMD.EXE) parse scripts?
I suggest also reading DosTips forum topic ECHO. FAILS to give text or blank line - Instead use ECHO/ and avoid the usage of echo. in the batch file to output an empty line.
"halfway through the batch job" as you have a
setLocal EnableDelayedExpansion which sets any further
changes to the variable PATH or other set variables as local.
The endLocal not specified is implied at the end of the script.
To resolve this, use endLocal and set CLASSPATH=%CLASSPATH%
on the same parsed line to set CLASSPATH as global.
Change this part:
setLocal EnableDelayedExpansion
set CLASSPATH=.
for /R %JRE_HOME%\lib %%a in (*.jar) do (
set CLASSPATH=!CLASSPATH!;%%a
)
set CLASSPATH=!CLASSPATH!
to this:
setLocal EnableDelayedExpansion
set CLASSPATH=.
for /R %JRE_HOME%\lib %%a in (*.jar) do (
set CLASSPATH=!CLASSPATH!;%%a
)
endLocal & set CLASSPATH=%CLASSPATH%
After that changed part, the script will set variables as global again.

Writing a Batch Program from Local System Variables Using the Set Command

I'm required to write a program that displays the computer name, username, and path to user files. All of these should be taken from local system variables. It's been hinted that I'm supposed to use the set command, however, I'm not sure how to use the set command in this situation... I had assumed that I could just use echo %COMPUTERNAME% etc. How can I implement the set command?
I'm guessing that the hint about the Set command was so that you could use the output of it to help you identify the local system variables to use in your batch file, not that you need to use Set to output them.
When you enter Set at the Command prompt you'll get output showing you each of the defined system variables.
Additionally, if you enter Set ComputerName at the prompt, you should get output showing you all variables which begin with the string ComputerName.
So based on the output of the Set command you could Echo, your three variables from a batch file like this:
#Echo Off
Echo %ComputerName%
Echo %UserName%
Echo %UserProfile%
You could also include the variables with their values:
#Echo Off
Echo %%ComputerName%%=%ComputerName%
Echo %%UserName%%=%UserName%
Echo %%UserProfile%%=%UserProfile%
You could also consider running a simple For loop in your batch file to show the same content using the Set command directly:
#Echo Off
For %%A In (ComputerName,UserName,UserProfile) Do Set %%A
Pause
Or you could return just their values using Set and Echo from nested For loops:
#Echo Off
For %%A In (ComputerName,UserName,UserProfile) Do (
For /F "Tokens=1* Delims==" %%B In ('Set %%A') Do Echo %%C)
Pause
to take the question very literal ("display the computer name ... using set command"):
set computername
set username
set userprofile
output like:
COMPUTERNAME=Elon-PC
USERNAME=Muscrat
USERPROFILE=C:\Users\Muskrat
(Compo already has this method in his answer, but I guess using the for command is over the boundaries of the current state of your course)
(Note: for practical use, in most cases Compo's answer (using variables) is better, because in practice, you will probably do something with the values, not "just" show them, but this literally answers your question)

How to identify spacebar in a Batch Script?

So, I created a program, which can create and delete folders on the desktop. And I have a problem, when I just write a single space for the name I got the error "Please write a valid folder name!" so it works, but if I'm using more than one spaces, it says "Folder created successfully", and I want to make this program to make an error when I only using spaces in the folder's name. Please help!
Here's a part of my code (the full code is 132 lines long)
set Choice=
set /p Choice="Choose an option: "
if '"%Choice%"'=='"1"' goto masodik
if '"%Choice%"'=='"2"' goto negyedik
if '"%Choice%"'=='"3"' goto otodik
if '"%Choice%"'=='"4"' goto harmadik
if not '"%Choice%"'=='"1"' goto hiba2
if not '"%Choice%"'=='"2"' goto hiba2
if not '"%Choice%"'=='"3"' goto hiba2
if not '"%Choice%"'=='"4"' goto hiba2
:masodik
cls
echo Create a folder
echo ---------------
echo.
cd "%systemdrive%/documents and settings/%username%/desktop"
echo Enter the folder's name!
echo.
set /p mappaneve="The folder's name: "
if "%mappaneve%" EQU "" goto hiba
if EXIST "%mappaneve%" goto hiba3
md "%mappaneve%"
cls
echo Create a folder
echo ---------------
echo.
echo Successfully created "%mappaneve%"!
timeout /t 3 >nul
cls
goto elso
if "%mappaneve: =%" EQU "" goto hiba
ie, replace all spaces with nothing and if the result is nothing then the input must have been all spaces (if that was what you were asking)
quotes is used in variable asignation to make sure space are handle correctly. don't include quotes inside your variable unless when you want to use it.try change your code into this.
set /p "mappaneve=The folder's name: "
Magoo posted the right code in his short answer.
Here is a much longer answer with commented batch code and additional explanations on the various improvements in this code in comparison to code in question post.
set "UserChoice="
set /p "UserChoice=Choose an option: "
if "%UserChoice%" == "1" goto masodik
if "%UserChoice%" == "2" goto negyedik
if "%UserChoice%" == "3" goto otodik
if "%UserChoice%" == "4" goto harmadik
rem None of the 4 valid numbers was entered.
goto hiba2
:masodik
rem Set current directory to desktop directory of current user.
cd /D "%USERPROFILE%\Desktop"
cls
echo Create a folder
echo ---------------
echo.
rem Define a double quote as default value to be able to remove all
rem double qotes from input string with no syntax error even if the
rem user just hits key RETURN or ENTER without entering any string.
set "mappaneve=""
set /p "mappaneve=Enter folder name: "
rem Remove all double quotes from entered folder name.
set "mappaneve=%mappaneve:"=%"
rem Check if user has entered anything at all and if entered folder name
rem does not exist of only 1 or more spaces by using environment variable
rem substitution which removes for string comparison all spaces from the
rem entered folder name.
if "%mappaneve%" == "" goto hiba
if "%mappaneve: =%" == "" goto hiba
rem Appending \* makes sure to test on existence of a folder and not a file.
rem It does not matter if entered folder name ends already with a backslash.
rem Does the folder already exist?
if exist "%mappaneve%\*" goto hiba3
rem Create the folder and verify if that was successful with
rem saving error message into a temporary file for output below.
md "%mappaneve%" 2>"%TEMP%\%~n0_FolderError.tmp"
if errorlevel 1 goto FolderError
rem On successful creation of the folder an empty file is
rem created which should be removed before processing further.
del "%TEMP%\%~n0_FolderError.tmp"
cls
echo Create a folder
echo ---------------
echo.
echo Created successfully "%mappaneve%".
timeout /t 3 >nul
cls
goto elso
:FolderError
cls
echo Failed to create folder "%mappaneve%".
echo.
echo Error message:
echo.
type "%TEMP%\%~n0_FolderError.tmp"
del "%TEMP%\%~n0_FolderError.tmp"
echo.
pause
The improvements are:
Comparing strings with command IF should be done with using surrounding double quotes only. The single quotes are removed from the 4 string comparisons.
Of course if the batch user enters for example "2" (number 2 with double quotes) the batch execution would be exited by command processor because of a syntax error caused by processing if ""2"" == "1" goto masodik. Using delayed variable expansion would be one solution for this issue.
The 4 lines with if not '"%Choice%"'==... can be replaced simply by goto hiba2 as they are all definitely true after the first 4 string comparisons.
choice (SS64 article) is a standard Windows command. Therefore it is advisable to avoid choice (Microsoft article) as name for an environment variable or label. UserChoice (CamelCase spelling for easier reading) is used instead of Choice.
Command choice would be a very good alternative for first user prompt because then the user can't enter something different than 1, 2, 3, or 4.
There is predefined by Windows the environment variable USERPROFILE containing path to the user´s profile directory containing the directory Desktop and other user account related directories. This variable should be used instead of building path with other variables.
The directory separator on Windows is the backslash character and not the forward slash character. Windows supports in the meantime also directory paths with / instead of \, but it is nevertheless better to use the right directory separator.
The user´s profile directory can be on a different drive than system drive. Or the drive from which the batch file is executed is a different one than the drive of user´s profile directory. Therefore it is advisable to use command CD with parameter /D as otherwise changing directory could fail if current drive is different to drive of user´s profile directory.
It is advisable to define a default for an environment variable before prompting a user or clearing the variable. The user can hit just RETURN or ENTER in which case the environment variable keeps its value.
This was done for Choice, but was forgotten for mappaneve.
The user could enter a folder name with double quotes. Therefore it is advisable to remove all double quotes from entered folder name as otherwise the batch script processing would be exited by command processor because of a syntax error on further processing the batch file.
To really test existence of a folder with if exist and not also a file, it is necessary to append \* to the folder name as otherwise if exist could be true also with user input string is name of an existing file.
Creation of folder could fail because of 1 or more invalid characters in folder name, a file exists with same name already, or the user does not have permission to create a folder.
The last reason is very unlikely here with current directory being the desktop directory of the user if user really enters just a folder name and not a directory path to create anywhere a directory (tree) which would be possible here, too.
So it is advisable to test on success on creating the folder.
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.
cd /?
cls /?
del /?
echo /?
goto /?
if /?
md /?
rem /?
set /?
timeout /?
type /?
And read also the Microsoft articles:
Testing for a Specific Error Level in Batch Files
Using command redirection operators

Make A Batch File Remember Something

I'm having trouble with a batch file. I need it to remember somthing for a long
period of time. Lets say I have a variable called %Rememberme%: I need to remember this for lets say a year for some reason. How can I make my batch file remember that variable?
Well... I could echo the variable to a file using the command
echo >>%Rememberme% C:\File.txt
Well the thing is I can't have that. I need it to be remembered some other way.
Or somehow I need to give the batch file administrator rights so that it can read or write to a file. Is there a way to do this?
You can use environment variables to do this, but be careful not to overwrite existing variables.
EX:
SETX REMEMBERME "C:\windows\system32"
And then in another file,
>echo %REMEMBERME%
>C:\windows\system32
The documentation for SETX is here: TechNet - SETX:
Important remark from the link:
Setx provides the only command-line or programmatic way to directly and permanently set system environment values. System environment variables are manually configurable through Control Panel or through a registry editor. The set command, which is internal to the command interpreter (Cmd.exe), sets user environment variables for the current console window only.
Here's an example of saving a variable in a file name. This obviously assumes the variable is limited to filename-friendly characters (like a number).
:: Reading variable
for %%f in (*.myvariable) do (
set myvariable=%%f
)
:: Remove extension
set myvariable=%myvariable:~0,-11%
:: Setting variable
del *.myvariable
echo. > "%myvariable%.myvariable"
echo %myvariable%
You can also store the variable inside the text file, but this requires opening the file in order to read the variable.
:: Reading variable
for /F "tokens=*" %%A in (myvariable.txt) do (
set "myvariable=%%A"
)
:: Setting variable
echo %myvariable%> myvariable.txt
echo %myvariable%
Your question is not clear. It have not any example nor a clear description of the request, so I can only guess...
The obvious point first: how to have a variable in a Batch file that remember its value for a long period of time? (i.e.: always) Easy: just define the variable in the Batch file:
set Rememberme=The value to remember
Of course, previous method does not allows to change the value of the variable, but you had mentioned nothing about this point in your request: "the value of the variable may be changed"...
Although SETX command should work, it requires admin rights and SETX is not designed for cases like this one. For example, what happens if the Batch file is changed or is not used anymore in a given computer? Well, the last value of the variable will remain in such computer for ever!
The second obvious solution is to write the variable into a separate file and read it from there when the Batch file start. If the separate file is a data file, the method described by Matt Johnson should work and it does not require administrator rights. You must note that the separate file may also be a Batch file, so the value of the variable may be read via a simple call statement:
rem Save the value
echo set Rememberme=%Rememberme%> setTheValue.bat
rem Read the value
call setTheValue.bat
However "the thing is you can't have that, so you need to be remembered some other way", although you don't explain the reasons for this restriction...
Another solution (that I think is what you are looking for) is to set the definition of the variable in the same Batch file:
rem Read the variable at beginning of the Batch file:
call :setTheValue
echo Value = %Rememberme%
rem The rest of the Batch file goes here
. . .
rem If the value needs to be changed:
if %changeValue% equ "yes" (
rem Do it:
echo set Rememberme=%Rememberme%>> "%~F0"
)
rem End the Batch file
goto :EOF
rem Define the subroutine that set the value:
:setTheValue
set Rememberme=Initial value of the variable
In previous code "%~F0" represent the name of the running Batch file itself. This way, each change in the variable value will append a new line at the bottom of the Batch file.
first:
echo >>%Rememberme% C:\File.txt
is wrong. It tries to write the string "C:\File.txt" into a filename referenced by the variable %rememberme%. What you want is:
echo %Rememberme%>>c:\File.txt
(or only one > to overwrite the file)
Second: if you have no permission to write to the root-directory, use another directory, where you have, for example:
echo %Rememberme%>%userprofile%\file.txt
or
echo %Rememberme%>%public%\file.txt
Note: be sure, there is no space between %Rememberme% and >; it would become part of the string, if you try to read it back.
to read it back, use:
set /p "remembered=" <%public%\file.txt
Here. This should help.
#echo off
echo What would you like to do?
echo 1. Enter your name
echo 2. Load your Name
choice /c 12
if %errorlevel% equ 1 goto newname
if %errorlevel% equ 2 goto loadname
:newname
cls
echo Input your name
set /p name=Name:
echo Your Name is saved!
::Here is the command where your name saves to a file.
(
echo %name
)>yourname.name
pause
exit /b
:loadname
cls
::Here is the command where it loads your name
(
echo %name%
)<yourname.name
echo Your Name: %name%
pause
exit /b

Resources