Nested Variables in Substring selection - batch-file

I'm struggling to get this "Substring"-Selection done dynamically:
set input=%input:~4%
I would like to have something like
set input=%%input:~%length% %%
But all my attempts with double %% and ! and many more have failed. Hope you can tell me, how nested variables like this work in windows batch files.
Many thanks in advance,
best regards,
marcus

Many possible ways
This uses the fact that CALL starts the batch parser a second time
set length=4
call set input=%%input:~%length%%%
With delayed expansion it's the most stable and secure solution
setlocal EnableDelayedExpansion
set length=4
set input=!input:~%length%!
Sometimes it's even useful to use a FOR parameter
setlocal EnableDelayedExpansion
set length=4
for /F %%n in ("!length!") do (
set input=!input:~%%~n!
)

Related

Use a variable on SET in Windows batch file

I´m trying to use a variable instead of a fixed number here:
set PACK_VERSION=Testing12345
set PACK_VERSION=%PACK_VERSION:~7,100%
echo %PACK_VERSION%
Instead of this number 7, I would like to use a variable, something like this:
set VARNUM=7
set PACK_VERSION=Testing12345
set PACK_VERSION=%PACK_VERSION:~%VARNUM%,100%
echo %PACK_VERSION%
I don´t know how to insert that properly, anyone can help? Thanks!
The "usual" way is using delayed expansion:
setlocal enabledelayedexpansion
set VARNUM=7
set PACK_VERSION=Testing12345
set PACK_VERSION=!PACK_VERSION:~%VARNUM%!
echo %PACK_VERSION%
but there is also a little trick to do it without delayed expansion (you have to parse the line twice, call is a good method to do so):
set VARNUM=7
set PACK_VERSION=Testing12345
call set PACK_VERSION=%%PACK_VERSION:~%VARNUM%%%
echo %PACK_VERSION%

How to refer to a variable in Batch Scripting?

Imagine a script called batch.bat, invoked like this:
batch.bat Two
The script contains:
set One=1
set Two=2
set Three=3
set Choice=%1
echo %Choice%
But I want to echo 2, not Two.
What elegant way can I employ to do that? I thought about if %Choice%=One, etc. but my actual script is a bit more complex than the example provided.
Edit: I also tried:
set percent=%%
echo %percent%%Choice%%percent%
But it won't treat the resulting expression as a variable reference.
#echo off
setlocal EnableDelayedExpansion
set one=1
set c=%1
echo delayed expansion and variable: !%c%!
echo delayed expansion and paramr: !%1!
call echo using call and variable: %%%c%%%
call echo using call and param: %%%1%%
I personally prefer the delayed expansion method, but sometimes there are reasons to look for an alternative.
OK, I have figured it out:
The key is to use the "set delayed expansion" trick.
There's also a trick using the "call set" instead of the above but I reckon if I use that, the next guy after me won't know what I was trying to do and might get in trouble.
The script can be fixed by adding !! around the reference that we want to force into the variable name, like so:
#echo off
setlocal EnableDelayedExpansion
set One=1
set Two=2
set Three=3
set Choice=!%1!
echo %Choice%

not able to read characters of a string inside a for loop

Am trying to read characters of a string inside a for loop.
The command !string:~1,3! works fine. But can I do this with variables instead of 1 and 3. I tried the following code, but I don't know what is wrong. Its not working.
#echo off
setlocal enableextensions enabledelayedexpansion
set string=abcdefghij
set /a count=1
for /l %%x in (1,1,3) do (
set string2=!string:~%count%,1!
set /a count+=1
echo !string2!
pause
)
but It always gives the output as:
b
I want the output to be as:
b
c
d
Kindly help in solving this.. A big thanks in advance
In order to achieve what you want, you need to do a Delayed Expansion twice, that is, something like this:
set string2=!string:~!count!,1!
Of course, previous line is invalid. Although there are several ways to solve this problem, most of they use call command that is slow. To fix this problem so it run in the fastest way use a for command to change the first !count! expansion into a FOR replaceable parameter, and then use it in the original expression:
for %%i in (!count!) do set string2=!string:~%%i,1!
The problem is that the expansion of %count% isn't delayed, so it has the same value for every loop iteration. It's better written like this:
#echo off
setlocal enableextensions enabledelayedexpansion
set string=abcdefghij
set /a count=1
for /l %%x in (%count%,1,3) do (
set string2=!string:~%%x,1!
echo !string2!
)
Edit
If you want to keep %count% evaluated as the variable is set and not just at the beginning of the for loop, use Aacini's answer.

Nested variable name using EnableDelayedExpansion

I am working on a script to get max lengths of each column, I'm trying to store lengths of max length in _c1...n vars. number of columns unknown.
I was able to get length for each column, create variables to store each with set _c!i! = !n!, n is the length
but in order to set the max length for a particular column I need to compare current with max and use something like !_c!!i!! which doesn't work, any ideas how to refer a variable which part of it's name coming from another variable?
Thanks...
I assume that you are using the delayed expansion character because you are working inside a set of brackets "()". Doing that makes your process harder. I know that method is easier to read, but it is harder to code for.
Inside brackets, I know of only one method to access a variable that was 'built' out of one or more variables. That is to use the call function to cause the assembled variable to 'activate'. This method works both inside and outside of brackets.
Here is a small example:
#echo off
setlocal enabledelayedexpansion
(
set i=10
set _c!i!=something
:: below is equivalent to echo !_c10!
call echo %%_c!i!%%
)
endlocal
Output:
something
You can do almost everything using a CALL in front of it that you can without it, though in XP or earlier you cannot call internal commands like if and can only call 'external' programs like FIND.EXE.
If you can work outside of a set of brackets by possibly using a call :label statement, you can simply access the variable like this:
#echo off
setlocal enabledelayedexpansion
set i=10
set _c!i!=something
:: The below 2 statements are equivalent to `echo %_c10%`
echo !_c%i%!
call echo %%_c!i!%%
endlocal
Output:
something
something
The CALL technique suggested by James K will work, but it is relatively slow and can be unsafe, depending on the content of the variable.
The following looks more complicated, but it is significantly faster and more reliable:
for %%A in (!i!) do echo !_c%%A!
In your case there could be a third solution be possible, if your variables contains only numbers.
#echo off
setlocal enabledelayedexpansion
(
set i=10
set _c!i!=4711
set /a tmp=_c!i!
echo !tmp!
)
This works, as SET /A can access the content of a variable without the nedd of explicitly expansion charaters.

How can I URL-encode spaces in an NT batch file?

I have the misfortune of working with a program which requires all filenames passed into it to be valid URLs. (No, I don't know why.) Rather than having to drop to the command line and hand-craft file: URLs each time, I'm throwing together a batch file onto which I can simply drop files dragged from the Windows GUI.
A full, proper URL encoder is beyond my needs or interest (most of the characters the app chokes on aren't valid in Windows filenames, anyway), but the two cases I do need to solve are backslashes and spaces. Backslashes are easily handled by variable replacement syntax (SET URL=%URL:\=/%), but spaces are tricky — % is special for both URLs and batch files.
Neither type of batch escaping I'm familiar with (^%, %%) allows the variable replacement to behave as desired and I haven't had any success Googling a solution. Can any batch gurus help me out?
Here's what I have so far:
#ECHO OFF
SETLOCAL
SET URLPATH=file:/%~dp1
SET URLPATH=%URLPATH:\=/%
REM none of these work
REM SET URLPATH=%URLPATH: =%20%
REM SET URLPATH=%URLPATH: =%%20%
REM SET URLPATH=%URLPATH: =^%20%
REM works; I just need to figure out how to generate it
SET URLPATH=file:/C:/Documents%%20and%%20Settings/bblank/example.dat
stupidapp.exe %URLPATH%
ENDLOCAL
Side note - I believe you want %~f1 instead of %~dp1
You need to switch over to delayed expansion.
#echo off
setlocal enableDelayedExpansion
set "URLPATH=file:/%~f1"
set "URLPATH=!URLPATH:\=/!"
set "URLPATH=!URLPATH: =%%20!"
stupidapp.exe !URLPATH!
endlocal
A bit more work is required if any of your file names happen to contain the ! character because it will be corrupted when %1 is expanded if delayed expansion is enabled.
#echo off
setlocal disableDelayedExpansion
set "URLPATH=file:/%~f1"
setlocal enableDelayedExpansion
set "URLPATH=!URLPATH:\=/!"
set "URLPATH=!URLPATH: =%%20!"
stupidapp.exe !URLPATH!
endlocal
endlocal
dbenham's solution is almost certainly preferable (being rather easier to read), but for the sake of completeness, here is an alternative solution:
SET URLPATH=file:/%~dp1
SET URLPATH=%URLPATH:\=/%
REM for each space in the path, split the path into the portions before and after
REM that space, then join them with an escaped space
:ESCAPE_SPACE
SET TRAILING=%URLPATH:* =%
CALL SET URLPATH=%%URLPATH: %TRAILING%=%%
SET URLPATH=%URLPATH%%%20%TRAILING%
IF NOT "%URLPATH%"=="%URLPATH: =%" GOTO ESCAPE_SPACE
stupidapp.exe %URLPATH%

Resources