Apply expression on string - windows

I'm new to batch and I know that you can use
%~dp0
to get the directory from a path, but then how do I use it on a path and put it into a variable.
Say I have this Location:
C:\someFolderName\anotherFolderName\FinalFolderName\file.txt
I want to know what the path is(excluding the drive and the file) and store it into a variable

The tilde notation works for for loop variables and call function arguments. Check out this sample .bat script for an example of each method:
#echo off
setlocal
set "fqname=C:\someFolderName\anotherFolderName\FinalFolderName\file.txt"
rem // set var1 to the path-to-file
for %%I in ("%fqname%") do set "var1=%%~dpI"
rem // set var2 to the path-to-file
call :get_path var2 "%fqname%"
echo var1: %var1%
echo var2: %var2%
rem // end main runtime
goto :EOF
rem // get_path function
:get_path <var_to_set> <filename>
set "%~1=%~dp2"
goto :EOF
In a cmd window, enter help for and see the last couple of pages for full details on tilde notation.

Related

Windows Batch Command : How to dereference FOR loop variable to check if that variable is SET in Environment Variable

I'm writing a batch command script where in there is a check for Environment variables. I need to write a FOR loop by passing all the required variables and then validate if it is defined or not and if it is not defined then prompt the value for that key and set that variable permanently.
Problem is that I could not dereference the loop variable and check it in Environment variable.
Sample code is as below:
#ECHO OFF
SETLOCAL ENABLEDELAYEDEXPANSION
FOR %%G IN (JBOSS_HOME, JAVA_HOME, ANT_HOME, PERFORCE_PATH, P4CLIENT) DO (
ECHO.
ECHO. Loop Item : %%G
:: Call a function by sending each value to check if it is set in ENVIRONMENT Variables, if not then add it persistently.
CALL:validateAndUpdate %%G
)
GOTO:EOF
:validateAndUpdate
:: Now I have to check if passed value is available in ENVIRONMENT variable or not
:: echo %~1 will print value like JBOSS_HOME
:: Below IF condition always substitues to IF ("JBOSS_HOME" == []) and it always returns true
:: but could not find syntax to use it to DE-reference and check if that key is set.
:: Ex: IF %JBOSS_HOME% == []
IF ("%~1" == []) (
ECHO.
ECHO. %~1 is empty
SET /p value="Enter value for '%~1' : "
:: Set that key value pair persistently using SETX
SETX %~1 "%value%"
) ELSE (
ECHO.
ECHO. %~1 is available as ENVIRONMENT variable
)
GOTO:EOF
ENDLOCAL
To check whether a variable is defined, use the defined keyword in an if statement. help if for more information.
If I may make another suggestion, it might be better to display a folder chooser for the user rather than asking him to key pathnames manually. To that end, save this proof of concept with a .bat extension and try it out. See whether it works like you want:
#if (#a==#b) #end /* JScript multiline comment
:: based on https://stackoverflow.com/a/15906994/1683264
:: batch portion
#echo off
setlocal enabledelayedexpansion
for %%G in (windir, temp, foo, bar) do (
if not defined %%G (
call :chooser %%G "Locate directory for %%G."
) else echo %%G is already defined as !%%G!
)
goto :EOF
:chooser <var_to_set> <dialog_title>
for /f "delims=" %%I in ('cscript /nologo /e:jscript "%~f0" "%~2"') do (
rem :: !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
rem :: Remove the "echo" from this next line when you are satisfied
rem :: that it will do what you intend.
rem :: !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
echo setx %~1 "%%~I"
)
goto :EOF
:: JScript portion */
var shl = new ActiveXObject("Shell.Application");
var folder = shl.BrowseForFolder(0, WSH.Arguments(0), 0, 0x00);
WSH.Echo(folder ? folder.self.path : '');
After you're satisfied the simulation does what you intend, remove echo from the :chooser subroutine.
See this page for more methods of launching a file or folder chooser from a .bat script, and see this GitHub Gist for more details and more examples of JScript / batch hybrids.
#echo off
setlocal enableextensions disabledelayedexpansion
for %%g in (JBOSS_HOME, JAVA_HOME, ANT_HOME, PERFORCE_PATH, P4CLIENT) do (
echo(
echo Testing %%g
if defined %%g (
echo %%g is available as ENVIRONMENT variable
) else (
echo %%g is empty
set /p "value=Enter value for '%%g' : " && (
setlocal enabledelayedexpansion
for /f "delims=" %%v in ("!value!") do (
endlocal
SETX %%g "%%v"
)
)
)
)
As already indicated, if defined varname is the "correct" way to check if a variable is defined.

goto was not expected at this time batch

#echo off
:start
set string=
set lo=1
set a=0
set b=0
set cl=1
set cloop=
set google=0
set k=0
set r=0
set id=
set t=0
set f=0
set /p string=?
if defined string (
echo %string%
goto loop
) else (
echo please enter a string
goto start
)
:loop
set a=
for /f "tokens=%lo%" %%G IN ("%string%") DO echo %%G
if defined a (
echo %a%
set google=0
set /p cloop=<greetings.txt
pause
:cloop
set b=
for /f "tokens=%cl%" %%g IN ("%cloop%") DO set b=%%g
if defined string (
if %a%==%b% goto greetings
set /a cl=%cl%+1
goto cloop
) else (
set cl=0
set /a lo=%lo%+1
goto loop
)
) else (
goto google
)
:greetings
set f=0
set k=0
set r=0
set /p id=<greetingtone.dat
for /f "tokens=%cl%" %%g IN ("%id%") DO set t=%%g
start greeting.bat
call greeting.bat
goto talk
:google
echo not done yet
pause
goto start
i have narrowed it down to this line
if %a%==%b% goto greetings
when i remove it it runs
i have looked but i have no idea why it does not work
please help the greetings.txt has "hi hello grunt"
i think it might be the variables
If %a% or %b% are empty values, it is likely the compare is incomplete, and it is saying that the goto is not expected yet. For instance, if you type the following at a C:\ prompt:
c:\>if a== echo ok
c:\>if ==a echo ok
echo was unexpected at this time.
c:\>if == echo ok
ok was unexpected at this time.
c:\>
If you enclose each value in quotes, then the comparison will still work even if one or both of the values are empty. For instance:
if "%a%"=="%b%" goto greetings
The normal reason for that an unexpected word in an IF statement is that IF has a very specific syntax, IF item1 operator item2 actionstatement(s).
What is likely to be happening is that item1 AND item2 appear to be missing, so IF resolves that as IF == goto greetings. Since goto is not one of its known operators (==, equ, neq, leq, lss, geq, gtr`) then it complains.
The question from here is - why do %a% and %b% appear to be empty?
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. In your case, that means the outermost IF - in if defined string.
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.
Next problem is using a label within a block. Not a good idea. On some versions, a label will terminate the block. Call a subroutine instead.
call :cloop
...
goto start
:cloop
(whatever needs to be done)
goto :eof
(note that :cloop and :EOF have a required colon. on cloop it means "this is an internal subroutine - it's in the cuurrent batchfile." :EOF is a predefined label understood by CMD to mean end of file.)

Updating a command line parameter in a batch file

Is it possible to update or replace a command line parameter (like %1) inside of a batch file?
Sample code:
rem test.cmd
#echo off
echo Before %1
IF "%1" == "123" (
set %%1 = "12345678"
)
echo After %1
Desired Result:
C:/>Test 123
Before 123
After 12345678
Actual Result:
C:/>Test 123
Before 123
After 123
No. What you are trying is not possible.
Can be simulated passing original batch parameters to subrutine, or call the same cmd recursively with modified parameters, which again get %1, %2, ... the parameters provided in the call. But this is not what you ask.
rem test.cmd
#echo off
echo Before %1
if "%~1"=="123" (
call :test %1234
) else (
call :test %1
)
goto :EOF
:test
echo After %1
Argument variables are reserved, protected variables, you can't modify the content of one of those variables by yourself.
I suggest you to store the argument in a local variable then you can do all operations you want:
#echo off
Set "FirstArg=%~1"
Echo: Before %FirstArg%
IF "%FirstArg%" EQU "123" (
Set "FirstArg=12345678"
)
Echo: After %FirstArg%
Pause&Exit

Expanding var in var in Windows CMD

I have smth like %SystemRoot%\blahblahblah in a variable (for example, variable a).
But echo !a! will return %SystemRoot%\blahblahblah (without expanding %SystemRoot%). How can I expand it?
You can use a trick of calling a subroutine that will cause the variable to be expanded twice:
#Echo Off
set a=%%SystemRoot%%\blahblahblah
call :reparse set b=%a%
echo value of a: %a%
echo value of b: %b%
goto :EOF
:reparse
%*
goto :EOF
The :reparse subroutine just executes all its parameters. The first expansion occurs when executing the call and the second occurs when %* is interpreted as set b=%SystemRoot%\blahblahblah.

The value returned from a function in a windows batch script is ignored in a FOR loop

I need a script that inserts a number at some point into a file path, like this:
from C:\WINDOWS\system32\ansi.sys
to C:\WINDOWS\system32\5.ansi.sys
I made a function using a label and it seems to work fine, until I invoke it from within a FOR loop.
This is the code I wrote:
#ECHO OFF
SET PATHTOPROCESS="C:\WINDOWS\system32\ansi.sys"
call :GetNewFilePath NEWPATH %PATHTOPROCESS% 7
echo New file name: %NEWPATH%
call :GetNewFilePath NEWPATH %PATHTOPROCESS% 5
echo New file name: %NEWPATH%
FOR /L %%i in (1,1,2) DO (
call :GetNewFilePath NEWPATH %PATHTOPROCESS% %%i
echo New file name in FOR loop: %NEWPATH%
)
goto :eof
:GetNewFilePath
SETLOCAL
SET PINDEX=%~3
SET PDIRECTORY=%~dp2
SET PFILE=%~nx2
SET LocalVar1=%PDIRECTORY%%PINDEX%.%PFILE%
ENDLOCAL & IF "%~1" NEQ "" SET %~1=%LocalVar1%
goto :eof
and this is the output I get:
New file name: C:\WINDOWS\system32\7.ansi.sys
New file name: C:\WINDOWS\system32\5.ansi.sys
New file name in FOR loop: C:\WINDOWS\system32\5.ansi.sys
New file name in FOR loop: C:\WINDOWS\system32\5.ansi.sys
and this is what I expect:
New file name: C:\WINDOWS\system32\7.ansi.sys
New file name: C:\WINDOWS\system32\5.ansi.sys
New file name in FOR loop: C:\WINDOWS\system32\1.ansi.sys
New file name in FOR loop: C:\WINDOWS\system32\2.ansi.sys
It seems that in the FOR loop, the variable is reverted back to the value it had before calling the function. Is there some special trick required for this when using FOR?
Thank you.
The variables inside the for loop are expanded immediately when that block is parsed, not when it's run. You'll need to use delayed expansion:
rem this should preferrably go at the very start of the batch file
setlocal enabladelayedexpansion
...
FOR /L %%i in (1,1,2) DO (
call :GetNewFilePath NEWPATH %PATHTOPROCESS% %%i
echo New file name in FOR loop: !NEWPATH!
)
Otherwise %NEWPATH% would be expanded to the value it had before the loop and inside the loop there wouldn't be any variable left.
You can easily verify that when removing the echo off at the start, by the way. The loop's block would then show the expanded value before it even ran. See help set for a more in-depth discussion of delayed expansion.

Resources