I'm trying to make a file search engine in batch but it searching only files in the folred where the .bat file is.
This is full code:
#echo off
title Search engine
set path=%HOMEDRIVE%
set filename=\%empty\%
set filextension=\%empty\%
cls
REM echo Under the construction
REM pause
REM call main.bat
:search
cls
echo Where do you want to search? (Leave empty for %HOMEDRIVE%)
set /p path=
:name
cls
echo Whats the name of your file? (Without extension)
set /p filename=
if %filename% == \%empty\% goto :name
:extension
cls
echo What's the extension of your file?
set /p filextension=
if %filextension% == \%empty\% goto :extension
goto :searchingMessage
:searchingMessage
cls
echo Searching %filename%.%filextension% in %path% (This may take a while)
goto :searching
:searching
for /r %path% %%a in (*) do if "%%~nxa"=="%filename%.%filextension%" set p=%%~dpnxa
if defined p (
echo File found under %p%
) else (
echo File not found
)
pause
call main.bat
Thanks. And I'm sorry if it is something simple. Im new to the batch
Use a setlocal line after #echo off. This ensures that variables that have been set within your code in one run are not preserved for the next run within the same cmd instance.
Never change the value of the variable path. It is system-defined and contains a semicolon-separated ordered list of the directories searched for an executable if that executable is not found in the current directory.
Use the syntax set "var=value" for string-assignments. This syntax ensures that any trailing spaces in a set command are not appended to the value assigned to the variable.
to assign a value of nothing (which actually deletes the variable from the environment) use the syntax set "var=". The code you have used would set the variable to \ concatenated with the value of the variable empty\. In batch, % escapes %, not \ and ^ escapes for other characters that require to be escaped USUALLY.
if %var% == something dosomething would be interpreted as if == something dosomething if var is empty, if %var% == dosomething if something is intended to be empty and if == dosomething if both are empty; all generating a syntax error since the second string following the if is not a comparison-operator like ==. To detect empty, use if defined var dosomething, if not defined var dosomething or if defined var (dosomething) else (dosomethingelse) as appropriate - noting that the string ) else (, if used, must all be on the same physical line.
Note that set /p var=whatever, or preferably set /p "var=whatever" will not change var if the response is simply Enter. It is therefore prudent to execute a set "var=" on the line before a set/p. This characteristic can be used to set a default value:
set "var=xyz"
set /p "var=new value for var [%var%] ^> "
which should prompt with new value for var [xyz] > and will retain xyz as the value of var if the response is simply Enter. Note here that the > is a special character (a redirector) so it's escaped by ^.
Note that if p is defined before the for /r ... line and no file is found, then p will not be assigned by the for /r, and will retain its original value. This is especially important in the light of point (1), where p may be retained between runs. BUT - note the possibility to use this characteristic...
set "p=File not found"
for /r ....
echo %p%
... and please use more expressive variable-names.
Related
This question already has answers here:
Arrays, linked lists and other data structures in cmd.exe (batch) script
(11 answers)
Closed 3 years ago.
I have a list of paths from which I want to extract folder name
I wrote:
#echo off
set paths[0]="C:\p\test1"
set paths[1]="C:\p\test2"
set paths[2]="C:\p\test3"
(for %%p in (%paths%) do (
for %%F in (%%p) do echo Processing %%~nxF
))
but seems that nothing is shown.
I expected to see:
Processing test1
Processing test2
Processing test3
It makes a big difference if first " is specified on a set command line left to variable name or left to variable value. In most cases it is better to specify it left to the variable name, especially if a variable value holding a path should be concatenated later with a file name to a full qualified file name.
See also: Why is no string output with 'echo %var%' after using 'set var = text' on command line?
The solution for this task is:
#echo off
set "paths[0]=C:\p\test1"
set "paths[1]=C:\p\test2"
set "paths[2]=C:\p\test3"
for /F "tokens=1* delims==" %%I in ('set paths[ 2^>nul') do echo Processing %%~nxJ
The command FOR with option /F and a set enclosed in ' results in starting one more command process running in background with %ComSpec% /c and the command line specified between the two ' appended as further arguments. So executed is in this case with Windows installed to C:\Windows:
C:\Windows\System32\cmd.exe /c set paths[ 2>nul
The command SET outputs all environment variables of which name starts with paths[ line by line using the format VariableName=VariableValue to handle STDOUT of started background command process.
It could be that there is no environment variable of which name starts with paths[ which would result in an error message output to handle STDERR by command SET which would be redirected from background command process to handle STDERR of the command process which is processing the batch file and for that reason would be displayed in console window. For that reason a possible error message is redirected by the background command process to device NUL to suppress it with using 2>nul.
Read the Microsoft article about Using command redirection operators for an explanation of 2>nul. The redirection operator > must be escaped with caret character ^ on FOR command line to be interpreted as literal character when Windows command interpreter processes this command line before executing command FOR which executes the embedded set command line with using a separate command process started in background.
FOR captures in this case everything written to handle STDOUT of started background command process and process this output line by line after started cmd.exe terminated itself.
Empty lines are ignored by FOR which does not matter here as there are no empty lines to process.
FOR would split up a non-empty line into substrings using normal space and horizontal tab as string delimiters and would assign just first space/tab separated string to specified loop variable, if it does not start with default end of line character ;. This default line splitting behavior is not wanted here. For that reason the option delims== defines the equal sign as string delimiter.
The option tokens=1* instructs FOR to assign in this case the variable name to specified loop variable I and assign everything after the equal sign(s) after variable name without any further string splitting on equal signs to next loop variable according to ASCII table which is in this case J. That is the reason why loop variables are interpreted case-sensitive while environment variables are handled case-insensitive by the Windows command processor.
In this case only the variable value is of interest in the body of the FOR loop. For that reason just loop variable J is used on ECHO command line while I is not used at all.
The modifier %~nxJ results in removing surrounding double quotes from string value assigned to loop variable J and next get the string after last backslash or beginning of string in case of the string value does not contain a backslash at all. This is the name of the last folder in folder path string.
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.
echo /?
for /?
set /?
UPDATE:
There is a big advantage of this solution in comparison to the other two solutions posted up to now here:
There is not used delayed environment variable expansion which is always problematic on working with file or folder names on not being 100% sure that no folder and no file contains ever an exclamation mark in its name.
Let us compare the three solutions with unusual folder names containing !.
#echo off
rem Make sure there is no environment variable defined of which name starts with
rem paths[ as suggested by Compo which is a very valuable addition on my code.
for /F "delims==" %%I in ('set paths[ 2^>nul') do set "%%I="
set "paths[0]=C:\p\test1!"
set "paths[1]=C:\p\!test2"
set "paths[2]=C:\p\!test!3"
echo/
echo Results of solution 1:
echo/
for /F "tokens=1* delims==" %%I in ('set paths[ 2^>nul') do echo Processing %%~nxJ
echo/
echo Results of solution 2:
echo/
SetLocal EnableDelayedExpansion
for /L %%i in (0,1,2) do (
for %%j in (!paths[%%i]!) do echo Processing %%~nxj
)
endLocal
echo/
echo Results of solution 3:
echo/
Setlocal EnableDelayedExpansion
Call :process paths "!paths[0]!" "!paths[1]!" "!paths[2]!"
Endlocal
echo/
pause
goto :EOF
:process
Set P_C=0
Set /a P_C-=1
For %%a in (%*) DO (
CALL :populate %1 "%%~a"
)
Set /a P_C-=1
For /L %%b in (0,1,!P_C!) DO (
ECHO Processing %1[%%b] = "!%1[%%b]!"
)
GOTO :EOF
:populate
Set "%1[!P_C!]=%~2"
Set /a P_C+=1
GOTO :EOF
The output on running this batch file is:
Results of solution 1:
Processing test1!
Processing !test2
Processing !test!3
Results of solution 2:
Processing test1
Processing test2
Processing 3
Results of solution 3:
Processing paths[0] = "C:\p\test1\p\\p\3"
Solution 1 as posted here works for all three folder names correct.
Solution 2 omits for first and second folder name the exclamation mark which will most likely cause errors on further processing. The third folder name is modified to something completely different. Enabled delayed expansion results in parsing a second time echo Processing %%~nxj after %~nxj being replaced by !test!3 with interpreting test in folder name now as environment variable name of which value is referenced delayed. There was no environment variable test defined on running this batch file and so !test!3 became just 3 before echo was executed by Windows command processor.
Solution 3 produces garbage on any folder name contains an exclamation mark, even on full qualified folder name defined before enabling delayed expansion and referenced with delayed expansion on calling the subroutine process.
Well, folder and file names with an exclamation mark in name are fortunately rare which makes the usage of delayed expansion usually no problem. But I want to mention here nevertheless the potential problems which could occur on any folder name containing one or more !.
Something like that should work :
#echo off
set paths[0]="C:\p\test1"
set paths[1]="C:\p\test2"
set paths[2]="C:\p\test3"
SetLocal EnableDelayedExpansion
for /L %%i in (0,1,2) do (
for %%j in (!paths[%%i]!) do echo Processing %%~nxj
)
pause
Define the Array within the function.
This approach can be used to define multiplay Arrays.
#ECHO OFF
Setlocal EnableDelayedExpansion
:: REM P_C is used to define the range of the Array. The -1 operations on P_C is to shift the paths parameter out of the Arrays working Index.
::REM the first parameter passed is used as the Arrays Name. all other parameters are assigned to index values 0 +
Call :process paths "C:\p\test1" "C:\p\test2" "C:\p\test3"
pause
:process
Set P_C=0
Set /a P_C-=1
For %%a in (%*) DO (
CALL :populate %1 "%%~a"
)
Set /a P_C-=1
For /L %%b in (0,1,!P_C!) DO (
ECHO Processing %1[%%b] = "!%1[%%b]!"
)
GOTO :EOF
:populate
Set "%1[!P_C!]=%~2"
Set /a P_C+=1
GOTO :EOF
I'm making a Minecraft modding tool using a batch file. But on execution of the batch file the Windows command interpreter outputs the syntax error message:
) was unexpected
I can't figure out why.
This is my code:
#echo off
cd mods
setlocal enabledelayedexpansion
set "selected=1"
call:print 1
call:print 2
:menu
choice /c wse>nul
if "%errorlevel%"=="2" (
if not !selected! GEQ !a! (
set /a "selected+=1"
cls
call:print 1
call:print 2
)
)
if "%errorlevel%"=="1" (
if not !selected!==1 (
set /a "selected-=1"
cls
call:print 1
call:print 2
)
)
if "%errorlevel%"=="3" (
)
goto menu
:print
if "%1"=="1"set a=0
echo.
if "%1"=="1" (
echo Uninstalled:
) else (
echo Installed:
)
echo.
for %%f in (*.jar) do (
if "%1"=="1" (
if NOT EXIST
"C:/Users/Coornhert/AppData/Roaming/.minecraft/mods/%%~nf.jar" (
set /a "a+=1"
if "!a!"=="!selected!" (
echo -%%~nf
) else (
echo %%~nf
)
set "b=!a!"
)
) else (
if EXIST "C:/Users/Coornhert/AppData/Roaming/.minecraft/mods/%%~nf.jar" (
set /a "a+=1"
if "!a!"=="!selected!" (
echo -%%~nf
) else (
echo %%~nf
)
set "b=!a!"
)
)
)
goto :eof
And it works, but when I hit s, execution terminates with the error message.
Folder structure of folder containing the batch file:
mods
Foo.jar
Foo2.jar
Folder structure of target folder:
C:\Users\Coornhert\AppData\Roaming\.minecraft\mods
Foo.jar
I partly do not understand what this batch file should do, but here is the batch file rewritten with several improvements.
#echo off
setlocal EnableExtensions EnableDelayedExpansion
rem cd /D "%~dp0mods"
pushd "%~dp0mods"
set "a=0"
set "selected=1"
call :PrintIt 1
call :PrintIt 2
:Menu
choice /C wse /N
if errorlevel 3 popd & endlocal & goto :EOF
if errorlevel 2 goto AddOne
if %selected% == 1 goto Menu
set /A selected-=1
cls
call :PrintIt 1
call :PrintIt 2
goto Menu
:AddOne
if %selected% GEQ %a% goto Menu
set /A selected+=1
cls
call :PrintIt 1
call :PrintIt 2
goto Menu
:PrintIt
if %1 == 1 set "a=0"
echo/
if %1 == 1 (echo Uninstalled:) else echo Installed:
echo/
for %%I in (*.jar) do (
if %1 == 1 (
if not exist "%APPDATA%\.minecraft\mods\%%~nI.jar" (
set /A a+=1
if !a! == %selected% (echo -%%~nI) else echo %%~nI
set "b=!a!"
)
) else (
if exist "%APPDATA%\.minecraft\mods\%%~nI.jar" (
set /A a+=1
if !a! == %selected% (echo -%%~nI) else echo %%~nI
set "b=!a!"
)
)
)
goto :EOF
It does nothing useful as is, but batch code in question is also not useful at all.
The applied improvements are:
The command SETLOCAL is moved to top of file. The reason is:
It pushes path of current directory on stack.
It pushes state of command extensions on stack.
It pushes state of delayed expansion on stack.
It pushes the memory address of the current environment variables table on stack.
It creates a copy of the current environment variables table in memory and makes this new environment variables table active.
It sets command extensions and delayed expansion according to the specified parameters if the command is called with parameters at all.
The command ENDLOCAL is executed before leaving batch file. The reason is:
It deletes the current environment table which means no environment variable defined in this batch file exists anymore after ENDLOCAL except it existed already before execution of command SETLOCAL.
It pops memory address of previous environment table from stack and uses this address resulting in restoring initial environment variables.
It pops state of delayed expansion from stack and disables/enables delayed expansion accordingly.
It pops state of command extensions from stack and disables/enables command extensions accordingly.
It pops previous current directory path from stack and sets current directory to this path to restore the current directory.
So the entire command process environment is restored on exit of this batch file to exactly the same environment as it was on starting the batch file.
This makes it possible to call this batch file from within another batch file or from within a command prompt window with no impact on calling batch file or command process.
The command CD could be extended to include drive and path of argument 0 which is the full path of the batch file ending with a backslash because the subdirectory mods is most likely always expected in directory of the batch file and it should not matter what is the current directory on running the batch file.
But cd /D "%~dp0mods" could fail if the batch file is located on a network share accessed using UNC path and therefore command PUSHD is used instead working with enabled command extensions also for UNC paths.
In all programming and scripting languages it is required that variables are defined and initialized with a value before being used the first time. For that reason the environment variables a and selected are defined at top of the batch file with default values. By the way: a is a very bad name for a variable. Why? Search for a in batch file. It is quite often found on not using special find features like whole word only, isn't it.
PRINT is a command as it can be seen on running in a command prompt window print /?. While it is possible to use command names as labels or as names for subroutines, it is not advisable to do so as it could be confusing for readers of the batch file.
The command CHOICE has the option /N to hide the list of choices in the prompt. It is better to use this option than redirecting the output of CHOICE to device NUL.
The very old but still valid Microsoft support article Testing for a Specific Error Level in Batch Files explains that if errorlevel X means that the condition is true if the exit code of previous command or application is greater or equal X. The command CHOICE with 3 choices exits always with 1, 2 or 3 as exit code. So it is best to use:
if errorlevel 3 rem Do something on third choice avoiding fall through to next line.
if errorlevel 2 rem Do something on second choice avoiding fall through to next line.
Do something on first choice.
The advantage of using this method is that it even works with CHOICE within a command block on which if %ERRORLEVEL% == X fails because of delayed expansion would be required and usage of if !ERRORLEVEL! == X.
The integer comparison if %selected% GEQ %a% would not work if the two arguments would be enclosed in double quotes as the double quotes are also interpreted as part of the arguments to compare. For that reason using if "%selected%" GEQ "%a%" would result in running a string comparison instead of an integer comparison. For more information about comparing values with IF look on answer on Exit a for loop in batch.
It is safe here to omit the double quotes also on the other IF conditions with == operator running string comparisons because the environment variables selected and a must be both defined before running this IF condition and therefore both variables are defined at top of the batch file.
The answer on Why is no string output with 'echo %var%' after using 'set var = text' on command line? explains why set "variable=value" should be always used to assign a value to an environment variable or delete an environment variable on omitting the value. And this answer also explains why on set /A variable=expression the double quotes can be usually omitted as whitespace characters are interpreted completely different within an arithmetic expression. The exception is usage of set /A with 1 or more commands on same command line on which double quotes around variable=expression would be also needed.
The batch file should be exited when the batch file user enters e or E to take third choice. This could be done with just goto :EOF, or with exit /B which is an alias for goto :EOF, or with just exit which always exits entire command process independent on calling hierarchy which is not recommended. Windows command interpreter would implicitly restore the initial stack before finishing batch file execution. But it is nevertheless good coding practice to pop from stack with code which was pushed on stack before with code. For that reason there is used popd & endlocal & goto :EOF. See answer on Single line with multiple commands using Windows batch file for more information about usage of multiple commands on one command line.
The list of predefined environment variables of used user account is output on running in a command prompt window the command set. One predefined Windows environment variable is APPDATA with path to application data of current user account. This environment variable should be used instead of a fixed path to application data directory of user account.
And the directory separator on Windows is the backslash character \ and not slash character / as on Unix and Mac.
The usage of f as loop variable is not recommended as this is also a loop variable modifier. %%~f can be interpreted by Windows command interpreter as value of loop variable f without surrounding double quotes or as incomplete loop variable reference because of missing loop variable after %%~f which could be also interpreted as full file name of ?. So it is better to use # or $ as loop variable or upper case letters to avoid such a confusion on interpreting the loop variable reference. Loop variables are case-sensitive.
I prefer for IF conditions with an ELSE branch the coding style
if condition (
command
) else (
command
)
But here in this batch file with command being just a short ECHO command the code is better readable on being more compact with using:
if condition (echo short message) else echo other short message
Delayed expansion for an environment variable referenced within a command block started with ( and ending with matching ) is only needed if the environment variable is also modified in same command block. Therefore environment variable a must be referenced in body of FOR with usage of delayed expansion while environment variable selected can be referenced as usual because of not modified within this command block at all.
It is better to use echo/ to output an empty line instead of echo.. For the reason read the DosTips forum topic: ECHO. FAILS to give text or blank line - Instead use ECHO/
For a basic understanding of the used commands, open a command prompt window, execute there the following commands, and read entirely all help pages displayed for each command very carefully.
call /?
choice /?
cls /?
echo /?
endlocal /?
for /?
goto /?
if /?
popd /?
pushd /?
rem /?
set /?
setlocal /?
I'm trying to use another batch file called uppercase.bat to convert an existing string to uppercase.
#echo off
set /p TitleID=Enter the ID of the title you want to download.
set /p GameName=What is the name of the game you are trying to download?
:Execute
java -jar JNUSTool.jar %TitleID% -dlEncrypted
pause
:Change_to_uppercase
call %~dp0\uppercase.bat %TitleID%
:Rename
echo Renaming to %GameName%...
rename "%~dp0temp_%UpperTitleID%" "%~dp0%GameName%"
pause
uppercase.bat does this:
#ECHO OFF
SET STRING=%1
IF [%STRING%]==[] GOTO:EOF
SET STRING=%STRING:a=A%
SET STRING=%STRING:b=B%
SET STRING=%STRING:c=C%
SET STRING=%STRING:d=D%
SET STRING=%STRING:e=E%
SET STRING=%STRING:f=F%
SET STRING=%STRING:g=G%
SET STRING=%STRING:h=H%
SET STRING=%STRING:i=I%
SET STRING=%STRING:j=J%
SET STRING=%STRING:k=K%
SET STRING=%STRING:l=L%
SET STRING=%STRING:m=M%
SET STRING=%STRING:n=N%
SET STRING=%STRING:o=O%
SET STRING=%STRING:p=P%
SET STRING=%STRING:q=Q%
SET STRING=%STRING:r=R%
SET STRING=%STRING:s=S%
SET STRING=%STRING:t=T%
SET STRING=%STRING:u=U%
SET STRING=%STRING:v=V%
SET STRING=%STRING:w=W%
SET STRING=%STRING:x=X%
SET STRING=%STRING:y=Y%
SET STRING=%STRING:z=Z%
ECHO %STRING%
That's about it. The editor wants me to add more details, but that's all I can give.
I wouldn't pass the content of the var to the called batch, but indirectly the name of the var. Since the called batch shares the same environment it can modify the variable. So use this sample upperCase.bat
#Echo off&SetLocal EnableExtensions EnableDelayedExpansion
Set "ToUpper=!%~1!"
For %%U In (A B C D E F G H I J K L M N O P Q R S T U V W X Y Z) Do (
Set "ToUpper=!ToUpper:%%U=%%U!"
)
Endlocal&Set "%~1=%ToUpper%"
Sample output:
> Set "TitleID=this is all lower case"
> upperCase.bat TitleID
> Set Tit
TitleID=THIS IS ALL LOWER CASE
Your external batch file will return the result in the variable string, so all yo need to do is to assign that value to UpperTitleID - or change UpperTitleID to string when you want to use it in the rename command.
set "UpperTitleID=%string%"
The syntax SET "var=value" (where value may be empty) is used to ensure that any stray trailing spaces are NOT included in the value assigned. set /a can safely be used "quoteless".
Note that the %~dp0\ in call %~dp0\uppercase.bat is probably redundant. Windows will find uppercase.bat if it is in the current directory or in any directory specified on the path (for instance, in your batch-file directory, if you've included you batch-file directory in your path)
Rename is a poor name for a label because it is a keyword.
%~dp0 expands to path of batch file always ending with a backslash. Therefore don't specify an additional backslash after this string although it works because Windows removes the second backslash later.
It is also recommended to double quote the entire string in case of current batch file path contains for example a space character, i.e. use
call "%~dp0uppercase.bat" %TitleID%
The string assigned to environment variable TitleID is not quoted and therefore can't contain a space character or another character with special meaning on command line on parsing it to batch file uppercase.bat.
I suggest to embed code of uppercase.bat into your batch file.
#echo off
setlocal EnableExtensions EnableDelayedExpansion
echo/
echo Enter the ID of the title you want to download.
echo/
set "TitleID="
:TitlePrompt
set /P "TitleID=Title: "
if not defined TitleId goto TitlePrompt
set "TitleId=!TitleId:"=!"
if not defined TitleId goto TitlePrompt
echo/
echo What is the name of the game you are trying to download?
echo/
set "GameName="
:GamePrompt
set /P "GameName=Game: "
if not defined GameName goto GamePrompt
set "GameName=!GameName:"=!"
if not defined GameName goto GamePrompt
echo/
java.exe -jar "%~dp0JNUSTool.jar" "!TitleID!" -dlEncrypted
for %%U in (A B C D E F G H I J K L M N O P Q R S T U V W X Y Z) do set "TitleID=!TitleID:%%U=%%U!"
echo Renaming to !GameName! ...
ren "%~dp0temp_!TitleID!" "!GameName!"
endlocal
Note: The new name of a file being renamed must be specified without path or rename fails.
The batch code above checks if user has really entered anything at all and removes double quotes from entered string and checking once again if the remaining entered string has a length greater 0.
The batch code should be further improved to remove from entered title and game name all characters which are not acceptable in a file name like :\/<>| and others.
echo/ outputs just a blank line as it can be seen on running this batch file from within a command prompt window which is preferred for testing a batch file in development to see errors output by Windows command interpreter in case of having made a syntax error.
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.
echo /?
endlocal /?
goto /?
if /?
ren /? or rename /?
set /?
setlocal /?
I am writing a batch file whereby I can rename a xml file name inside a folder on my Desktop.
prompt the user to key in the file name
if the file name is found, it will then prompt the user to key in an existing xml file name
if an existing xml file name, it will then prompt the user to key in a new xml file name
an overview of my contents inside a file name(bb).
this is my batch-script
#echo off
set /p fn=Enter Folder name:
if exist C:\Users\roberts\Desktop\%fn% (
set /p oldxmlname=Enter a old xml file name:
if exist C:\Users\roberts\Desktop\%fn%\%oldxmlname%.xml (
set /p newxmlname=Enter a new xml file name:
ren C:\Users\roberts\Desktop\%oldxmlname%.xml %newxmlname%.xml
echo file name changed successfully.
)
)else (
echo folder not found in path.
echo C:\Users\roberts\Desktop\%fn%
)
this is my output. The file name didn't change at all.
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.
Hence, IF (something) else (somethingelse) will be executed using the values of %variables% at the time the IF is encountered. The same comment goes for the REN.
Two common ways to overcome this are 1) to use setlocal enabledelayedexpansion 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.
And if an ELSE clause is used, the IF-true command must be (parenthesised), and the ) and ELSE must be on the same physical line. If ELSE-true command is (parenthesised), the ELSE and ( must be on the same physical line. There must be a Space either side of the else keyword.
A demonstration:
#echo off
SETLOCAL
cls
set var=ORIGINAL
echo Start value of var=%var%
for %%i in (1) do (SET var=AFTER
ECHO var is %var% in the for loop
)
echo Final value of var=%var%
ENDLOCAL
ECHO.
echo ---- try again with ENABLEDELAYEDEXPANSION
ECHO.
setlocal enabledelayedexpansion
set var=ORIGINAL
echo Start value of var=%var%
for %%i in (1) do (SET var=AFTER
ECHO var is %var% not !var! in the for loop
ECHO Note: in the loop VAR has old value %var% and new value !var!
)
echo Final value of var=%var%
endlocal
Note how the value of var is interpreted differently depending on the use of setlocal or setlocal enabledelayedexpansion. The !var! syntax is only available in delayedexpansion mode and accesses the value of var as it is modified in the block,
You left \%fn% out of the ren command, so the file you're asking to rename really doesn't exist.
You want ren C:\Users\roberts\Desktop\%fn%\%oldxmlname%.xml %newxmlname%.xml
Here is a method that doesn't need delayed expansion, which your code does.
When changing a variable and using it within a loop, then delayed expansion is required.
There are some quotes to protect long file/path elements and an added backslash to detect a path and not a file.
#echo off
set /p fn=Enter Folder name:
if not exist "C:\Users\roberts\Desktop\%fn%\" (
echo The engines canna take the strain captain, try again!
goto :EOF
)
set /p oldxmlname=Enter a old xml file name:
if not exist "C:\Users\roberts\Desktop\%fn%\%oldxmlname%.xml" (
echo folder not found in path.
echo "C:\Users\roberts\Desktop\%fn%"
goto :EOF
)
set /p newxmlname=Enter a new xml file name:
ren "C:\Users\roberts\Desktop\%oldxmlname%.xml" "%newxmlname%.xml"
if not errorlevel 1 (
echo file name changed successfully.
) else (
echo oops! Something is fubar
)
I'm trying to check a variable that contains a path to see if there is a trailing slash and if there is then remove it. I have it working if the variable value is not surrounded by quotes but I also need to check for the trailing slash even if quotes exist.
The issue that I'm running into is trying to get an If statement to work to check for the double quote so I can basically check if it has a double quote and then check for the trailing slash. The If statement fails with "( was unexpected at this time". I'm sure it's an escaping issue but I've tried every way I can think of and haven't been able to get it to work. I've been searching on the web for hours with no luck.
Here's what I have for it so far (I left out the code checking for it without the quotes, basically the same format). Also, if there's a better way to achieve this I'm all ears.
set appRoot="C:\test\"
REM grab the last two characters
set lastChar=%appRoot:~-2%
if %lastChar% == \" (
echo It works!
)
This is a robust method
#echo off
set appRoot="C:\test\"
for %%a in (%approot%) do for %%b in ("%%~a\.") do echo "%%~fb"
pause
If you can change the layout of quotes in the set statement then this is simpler:
#echo off
set "appRoot=C:\test\"
for %%a in ("%approot%\.") do echo "%%~fa"
pause
Once the line if %lastChar% == \" ( is expanded (variables replaced with values), what you get is if \" == \" ( which is not a valid condition, so the parenthesis is not expected.
With the value assigned to appRoot, your best option is directly check not the last but the previous character with
set "lastChar=%appRoot:~-2,1%"
if %lastChar% == \
Or, if you can change the value of appRoot
set "appRoot=C:\test\"
REM grab the last character
set lastChar=%appRoot:~-1%
if %lastChar% == \ (
echo It works!
)
EDITED to adjust to comments
Since the OP don't have control on how the paths are asigned to the variables, the possible cases are: variables in the form set var=, set var="path", set var=path or set "var=path" (we can assume the two last are equivalent if no special characters present). With or without trailing backslash. With or without spaces in path. And the need is to get a correct path (good looking, exists or not, this to be checked later), without trailing backslashes and (not in OP question, but should be) with or without quotes in a consistent manner.
So, here we go
#echo off
setlocal enableextensions
set "appRoot=c:\some where\"
call :cleanToFullPath appRoot
echo %appRoot%
set "appRoot=c:\some where"
call :cleanToFullPath appRoot
echo %appRoot%
set appRoot="c:\some where\"
call :cleanToFullPath appRoot
echo %appRoot%
set appRoot="c:\some where\a\"
call :cleanToFullPath appRoot
echo %appRoot%
set appRoot=c:\some where\in a rare place
call :cleanToFullPath appRoot
echo %appRoot%
set appRoot=""
call :cleanToFullPath appRoot
echo %appRoot%
goto :EOF
:cleanToFullPath variableName
rem Prepare environment
setlocal enableextensions enabledelayedexpansion
rem get variable name
set "_varName=%~1"
rem get value of variable
set "_tmp=!%~1!"
rem remove quotes from variable value
set "_tmp=%_tmp:"=%"
rem handle empty variables. Default current folder
if not defined _tmp set "_tmp=."
rem prepare to process trailing bar if any
if "%_tmp:~-1%"=="\" set "_tmp=%_tmp%."
rem resolve to full path
for %%# in ("%_tmp%") do set "_tmp=%%~f#"
rem cleanup and update variable
endlocal & set "%~1=%_tmp%"
goto :eof